Blender  V2.93
overlay_outline.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2019, Blender Foundation.
17  */
18 
23 #include "DRW_render.h"
24 
25 #include "BKE_global.h"
26 #include "BKE_gpencil.h"
27 
28 #include "BKE_object.h"
29 
30 #include "DNA_gpencil_types.h"
31 
32 #include "UI_resources.h"
33 
34 #include "overlay_private.h"
35 
36 /* Returns the normal plane in NDC space. */
37 static void gpencil_depth_plane(Object *ob, float r_plane[4])
38 {
39  /* TODO put that into private data. */
40  float viewinv[4][4];
41  DRW_view_viewmat_get(NULL, viewinv, true);
42  float *camera_z_axis = viewinv[2];
43  float *camera_pos = viewinv[3];
44 
45  /* Find the normal most likely to represent the grease pencil object. */
46  /* TODO: This does not work quite well if you use
47  * strokes not aligned with the object axes. Maybe we could try to
48  * compute the minimum axis of all strokes. But this would be more
49  * computationally heavy and should go into the GPData evaluation. */
51  /* Convert bbox to matrix */
52  float mat[4][4], size[3], center[3];
55  unit_m4(mat);
56  copy_v3_v3(mat[3], center);
57  /* Avoid division by 0.0 later. */
58  add_v3_fl(size, 1e-8f);
59  rescale_m4(mat, size);
60  /* BBox space to World. */
61  mul_m4_m4m4(mat, ob->obmat, mat);
62  /* BBox center in world space. */
63  copy_v3_v3(center, mat[3]);
64  /* View Vector. */
66  /* BBox center to camera vector. */
67  sub_v3_v3v3(r_plane, camera_pos, mat[3]);
68  }
69  else {
70  copy_v3_v3(r_plane, camera_z_axis);
71  }
72  /* World to BBox space. */
73  invert_m4(mat);
74  /* Normalize the vector in BBox space. */
75  mul_mat3_m4_v3(mat, r_plane);
76  normalize_v3(r_plane);
77 
78  transpose_m4(mat);
79  /* mat is now a "normal" matrix which will transform
80  * BBox space normal to world space. */
81  mul_mat3_m4_v3(mat, r_plane);
82  normalize_v3(r_plane);
83 
84  plane_from_point_normal_v3(r_plane, center, r_plane);
85 }
86 
88 {
89  OVERLAY_FramebufferList *fbl = vedata->fbl;
90  OVERLAY_TextureList *txl = vedata->txl;
91  OVERLAY_PrivateData *pd = vedata->stl->pd;
93 
94  if (DRW_state_is_fbo()) {
95  /* TODO only alloc if needed. */
98 
99  GPU_framebuffer_ensure_config(
100  &fbl->outlines_prepass_fb,
101  {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
102 
103  if (pd->antialiasing.enabled) {
104  GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
105  {
106  GPU_ATTACHMENT_NONE,
107  GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
108  GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx),
109  });
110  }
111  else {
112  GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
113  {
114  GPU_ATTACHMENT_NONE,
115  GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
116  });
117  }
118  }
119 }
120 
122 {
123  OVERLAY_PassList *psl = vedata->psl;
124  OVERLAY_TextureList *txl = vedata->txl;
125  OVERLAY_PrivateData *pd = vedata->stl->pd;
127  DRWShadingGroup *grp = NULL;
128 
129  const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
130  const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
131 
132  {
135 
137 
138  pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps);
139  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
140 
142 
143  pd->outlines_ptcloud_grp = grp = DRW_shgroup_create(sh_geom_ptcloud, psl->outlines_prepass_ps);
144  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
145 
147 
148  pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
149  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
150  }
151 
152  /* outlines_prepass_ps is still needed for selection of probes. */
153  if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
154  return;
155  }
156 
157  {
158  /* We can only do alpha blending with lineOutput just after clearing the buffer. */
161 
163 
164  grp = DRW_shgroup_create(sh, psl->outlines_detect_ps);
165  /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
166  DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
167  DRW_shgroup_uniform_bool_copy(grp, "doThickOutlines", do_expand);
168  DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", pd->antialiasing.enabled);
170  DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
171  DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
172  DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
173  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
175  }
176 }
177 
178 typedef struct iterData {
182  int cfra;
183  float plane[4];
185 
187  bGPDframe *UNUSED(gpf),
188  bGPDstroke *UNUSED(gps),
189  void *thunk)
190 {
191  iterData *iter = (iterData *)thunk;
192  bGPdata *gpd = (bGPdata *)iter->ob->data;
193 
194  const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
195  const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
196 
197  float object_scale = mat4_to_scale(iter->ob->obmat);
198  /* Negate thickness sign to tag that strokes are in screen space.
199  * Convert to world units (by default, 1 meter = 2000 px). */
200  float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
201 
203  DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", is_stroke_order_3d);
206  DRW_shgroup_uniform_float_copy(grp, "thicknessScale", object_scale);
207  DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
208  DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
209  DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
210 }
211 
213  bGPDframe *UNUSED(gpf),
214  bGPDstroke *gps,
215  void *thunk)
216 {
217  iterData *iter = (iterData *)thunk;
218 
219  MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
220 
221  bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
222  bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
223  // TODO: What about simplify Fill?
224  bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
225 
226  if (hide_material) {
227  return;
228  }
229 
230  if (show_fill) {
231  struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra);
232  int vfirst = gps->runtime.fill_start * 3;
233  int vcount = gps->tot_triangles * 3;
234  DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount);
235  }
236 
237  if (show_stroke) {
238  struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra);
239  /* Start one vert before to have gl_InstanceID > 0 (see shader). */
240  int vfirst = gps->runtime.stroke_start - 1;
241  /* Include "potential" cyclic vertex and start adj vertex (see shader). */
242  int vcount = gps->totpoints + 1 + 1;
243  DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
244  }
245 }
246 
248 {
249  /* No outlines in edit mode. */
250  bGPdata *gpd = (bGPdata *)ob->data;
251  if (gpd && GPENCIL_ANY_MODE(gpd)) {
252  return;
253  }
254 
255  iterData iter = {
256  .ob = ob,
257  .stroke_grp = pd->outlines_gpencil_grp,
259  .cfra = pd->cfra,
260  };
261 
262  if (gpd->draw_mode == GP_DRAWMODE_2D) {
263  gpencil_depth_plane(ob, iter.plane);
264  }
265 
267  ob,
270  &iter,
271  false,
272  pd->cfra);
273 }
274 
276 {
278  if (geom == NULL) {
279  return;
280  }
281 
282  DRWShadingGroup *shgroup = pd->outlines_grp;
283  DRW_shgroup_call(shgroup, geom, ob);
284 }
285 
287  Object *ob,
288  OVERLAY_DupliData *dupli,
289  bool init_dupli)
290 {
291  OVERLAY_PrivateData *pd = vedata->stl->pd;
292  const DRWContextState *draw_ctx = DRW_context_state_get();
293  struct GPUBatch *geom;
294  DRWShadingGroup *shgroup = NULL;
295  const bool draw_outline = ob->dt > OB_BOUNDBOX;
296 
297  /* Early exit: outlines of bounding boxes are not drawn. */
298  if (!draw_outline) {
299  return;
300  }
301 
302  if (ob->type == OB_GPENCIL) {
303  OVERLAY_outline_gpencil(pd, ob);
304  return;
305  }
306 
307  if (ob->type == OB_VOLUME) {
308  OVERLAY_outline_volume(pd, ob);
309  return;
310  }
311 
312  if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) {
313  /* Looks bad in this case. Could be relaxed if we draw a
314  * wireframe of some sort in the future. */
315  return;
316  }
317 
318  if (dupli && !init_dupli) {
319  geom = dupli->outline_geom;
320  shgroup = dupli->outline_shgrp;
321  }
322  else {
323  /* This fixes only the biggest case which is a plane in ortho view. */
324  int flat_axis = 0;
325  bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
326  DRW_object_is_flat(ob, &flat_axis) &&
327  DRW_object_axis_orthogonal_to_view(ob, flat_axis));
328 
329  if (pd->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
331  }
332  else {
333  geom = DRW_cache_object_surface_get(ob);
334  }
335 
336  if (geom) {
337  shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp;
338  }
339  }
340 
341  if (shgroup && geom) {
342  if (ob->type == OB_POINTCLOUD) {
343  /* Draw range to avoid drawcall batching messing up the instance attrib. */
344  DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0);
345  }
346  else {
347  DRW_shgroup_call(shgroup, geom, ob);
348  }
349  }
350 
351  if (init_dupli) {
352  dupli->outline_shgrp = shgroup;
353  dupli->outline_geom = geom;
354  }
355 }
356 
358 {
359  OVERLAY_FramebufferList *fbl = vedata->fbl;
360  OVERLAY_PassList *psl = vedata->psl;
361  const float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
362 
363  bool do_outlines = psl->outlines_prepass_ps != NULL &&
365 
366  if (DRW_state_is_fbo() && do_outlines) {
367  DRW_stats_group_start("Outlines");
368 
369  /* Render filled polygon on a separate framebuffer */
371  GPU_framebuffer_clear_color_depth_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00);
373 
374  /* Search outline pixels */
377 
379  }
380 }
@ G_TRANSFORM_OBJ
Definition: BKE_global.h:218
void BKE_gpencil_visible_stroke_iter(struct ViewLayer *view_layer, struct Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra)
Definition: gpencil.c:2637
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
Definition: material.c:713
General operations, lookup, etc. for blender objects.
void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3])
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3])
struct BoundBox * BKE_object_boundbox_get(struct Object *ob)
Definition: object.c:3817
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:243
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1187
void unit_m4(float m[4][4])
Definition: rct.c:1140
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
void rescale_m4(float mat[4][4], const float scale[3])
Definition: math_matrix.c:2396
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2196
void transpose_m4(float R[4][4])
Definition: math_matrix.c:1358
MINLINE void add_v3_fl(float r[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED(x)
@ GP_DRAWMODE_3D
@ GP_DRAWMODE_2D
@ GP_DATA_STROKE_KEEPTHICKNESS
#define GPENCIL_ANY_MODE(gpd)
@ GP_MATERIAL_HIDE
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
@ OB_BOUNDBOX
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_GPENCIL
#define V3D_SELECT_OUTLINE
#define RV3D_ORTHO
DRWState
Definition: DRW_render.h:312
@ DRW_STATE_WRITE_DEPTH
Definition: DRW_render.h:314
@ DRW_STATE_WRITE_COLOR
Definition: DRW_render.h:315
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition: DRW_render.h:323
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition: DRW_render.h:342
#define DRW_PASS_CREATE(pass, state)
Definition: DRW_render.h:593
#define DRW_shgroup_call(shgroup, geom, ob)
Definition: DRW_render.h:420
NSNotificationCenter * center
GPUBatch
Definition: GPU_batch.h:93
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
struct GPUShader GPUShader
Definition: GPU_shader.h:33
@ GPU_R16UI
Definition: GPU_texture.h:112
@ GPU_DEPTH24_STENCIL8
Definition: GPU_texture.h:121
@ TH_OUTLINE_WIDTH
Definition: UI_resources.h:98
float UI_GetThemeValuef(int colorid)
Definition: resources.c:1164
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
GPUBatch * DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold)
Definition: draw_cache.c:811
GPUBatch * DRW_cache_volume_selection_surface_get(Object *ob)
Definition: draw_cache.c:3320
GPUBatch * DRW_cache_object_surface_get(Object *ob)
Definition: draw_cache.c:886
struct GPUBatch * DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra)
struct GPUBatch * DRW_cache_gpencil_fills_get(struct Object *ob, int cfra)
struct DRW_Global G_draw
Definition: draw_common.c:45
bool DRW_object_is_flat(Object *ob, int *r_axis)
Definition: draw_common.c:441
bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis)
Definition: draw_common.c:474
bool DRW_state_is_fbo(void)
const DRWContextState * DRW_context_state_get(void)
const float * DRW_viewport_size_get(void)
Definition: draw_manager.c:439
const float * DRW_viewport_invert_size_get(void)
Definition: draw_manager.c:444
DefaultTextureList * DRW_viewport_texture_list_get(void)
Definition: draw_manager.c:702
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuf *ubo)
void DRW_shgroup_call_instance_range(DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
bool DRW_view_is_persp_get(const DRWView *view)
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob, uint tri_count)
bool DRW_pass_is_empty(DRWPass *pass)
DRWShadingGroup * DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_ct)
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
void DRW_draw_pass(DRWPass *pass)
void DRW_stats_group_start(const char *name)
void DRW_stats_group_end(void)
void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex, eGPUTextureFormat format, DRWTextureFlag flags)
static ulong state[N]
static void gpencil_stroke_cache_populate(bGPDlayer *UNUSED(gpl), bGPDframe *UNUSED(gpf), bGPDstroke *gps, void *thunk)
static void gpencil_depth_plane(Object *ob, float r_plane[4])
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, bool init_dupli)
void OVERLAY_outline_draw(OVERLAY_Data *vedata)
static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
void OVERLAY_outline_init(OVERLAY_Data *vedata)
struct iterData iterData
void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob)
static void gpencil_layer_cache_populate(bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *UNUSED(gps), void *thunk)
GPUShader * OVERLAY_shader_outline_prepass(bool use_wire)
GPUShader * OVERLAY_shader_outline_prepass_gpencil(void)
GPUShader * OVERLAY_shader_outline_prepass_pointcloud(void)
GPUShader * OVERLAY_shader_outline_detect(void)
struct RegionView3D * rv3d
Definition: DRW_render.h:741
struct GPUUniformBuf * block_ubo
Definition: draw_common.h:210
struct GPUTexture * depth
OVERLAY_PassList * psl
OVERLAY_StorageList * stl
OVERLAY_FramebufferList * fbl
OVERLAY_TextureList * txl
DRWShadingGroup * outline_shgrp
struct GPUBatch * outline_geom
struct GPUFrameBuffer * outlines_resolve_fb
struct GPUFrameBuffer * outlines_prepass_fb
DRWPass * outlines_detect_ps
DRWPass * outlines_prepass_ps
DRWShadingGroup * outlines_gpencil_grp
struct OVERLAY_PrivateData::@239 antialiasing
DRWShadingGroup * outlines_grp
DRWShadingGroup * outlines_ptcloud_grp
struct OVERLAY_PrivateData * pd
struct GPUTexture * outlines_id_tx
struct GPUTexture * temp_depth_tx
float obmat[4][4]
void * data
bGPDstroke_Runtime runtime
DRWShadingGroup * fill_grp
DRWShadingGroup * stroke_grp
float plane[4]
Object * ob
#define G(x, y, z)