Blender  V3.3
overlay_outline.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. */
3 
8 #include "DRW_render.h"
9 
10 #include "BKE_global.h"
11 #include "BKE_gpencil.h"
12 
13 #include "BKE_object.h"
14 
15 #include "DNA_gpencil_types.h"
16 
17 #include "UI_resources.h"
18 
19 #include "overlay_private.h"
20 
21 /* Returns the normal plane in NDC space. */
22 static void gpencil_depth_plane(Object *ob, float r_plane[4])
23 {
24  /* TODO: put that into private data. */
25  float viewinv[4][4];
26  DRW_view_viewmat_get(NULL, viewinv, true);
27  float *camera_z_axis = viewinv[2];
28  float *camera_pos = viewinv[3];
29 
30  /* Find the normal most likely to represent the grease pencil object. */
31  /* TODO: This does not work quite well if you use
32  * strokes not aligned with the object axes. Maybe we could try to
33  * compute the minimum axis of all strokes. But this would be more
34  * computationally heavy and should go into the GPData evaluation. */
35  const BoundBox *bbox = BKE_object_boundbox_get(ob);
36  /* Convert bbox to matrix */
37  float mat[4][4], size[3], center[3];
40  unit_m4(mat);
41  copy_v3_v3(mat[3], center);
42  /* Avoid division by 0.0 later. */
43  add_v3_fl(size, 1e-8f);
44  rescale_m4(mat, size);
45  /* BBox space to World. */
46  mul_m4_m4m4(mat, ob->obmat, mat);
47  /* BBox center in world space. */
48  copy_v3_v3(center, mat[3]);
49  /* View Vector. */
51  /* BBox center to camera vector. */
52  sub_v3_v3v3(r_plane, camera_pos, mat[3]);
53  }
54  else {
55  copy_v3_v3(r_plane, camera_z_axis);
56  }
57  /* World to BBox space. */
58  invert_m4(mat);
59  /* Normalize the vector in BBox space. */
60  mul_mat3_m4_v3(mat, r_plane);
61  normalize_v3(r_plane);
62 
63  transpose_m4(mat);
64  /* mat is now a "normal" matrix which will transform
65  * BBox space normal to world space. */
66  mul_mat3_m4_v3(mat, r_plane);
67  normalize_v3(r_plane);
68 
69  plane_from_point_normal_v3(r_plane, center, r_plane);
70 }
71 
73 {
74  OVERLAY_FramebufferList *fbl = vedata->fbl;
75  OVERLAY_TextureList *txl = vedata->txl;
76  OVERLAY_PrivateData *pd = vedata->stl->pd;
78 
79  if (DRW_state_is_fbo()) {
80  /* TODO: only alloc if needed. */
83 
84  GPU_framebuffer_ensure_config(
85  &fbl->outlines_prepass_fb,
86  {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
87 
88  if (pd->antialiasing.enabled) {
89  GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
90  {
91  GPU_ATTACHMENT_NONE,
92  GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
93  GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx),
94  });
95  }
96  else {
97  GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
98  {
99  GPU_ATTACHMENT_NONE,
100  GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
101  });
102  }
103  }
104 }
105 
107 {
108  OVERLAY_PassList *psl = vedata->psl;
109  OVERLAY_TextureList *txl = vedata->txl;
110  OVERLAY_PrivateData *pd = vedata->stl->pd;
112  DRWShadingGroup *grp = NULL;
113 
114  const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
115  const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
116 
117  {
120 
122 
123  pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps);
124  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
125 
127 
128  pd->outlines_ptcloud_grp = grp = DRW_shgroup_create(sh_geom_ptcloud, psl->outlines_prepass_ps);
129  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
130 
132 
133  pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
134  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
135  DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", 0.0);
136 
138  pd->outlines_curves_grp = grp = DRW_shgroup_create(sh_curves, psl->outlines_prepass_ps);
139  DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
140  }
141 
142  /* outlines_prepass_ps is still needed for selection of probes. */
143  if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
144  return;
145  }
146 
147  {
148  /* We can only do alpha blending with lineOutput just after clearing the buffer. */
151 
153 
155  /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
156  DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
157  DRW_shgroup_uniform_bool_copy(grp, "doThickOutlines", do_expand);
158  DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", pd->antialiasing.enabled);
160  DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
161  DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
162  DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
163  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
165  }
166 }
167 
168 typedef struct iterData {
172  int cfra;
173  float plane[4];
175 
177  bGPDframe *UNUSED(gpf),
178  bGPDstroke *UNUSED(gps),
179  void *thunk)
180 {
181  iterData *iter = (iterData *)thunk;
182  bGPdata *gpd = (bGPdata *)iter->ob->data;
183 
184  const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
185  const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
186 
187  float object_scale = mat4_to_scale(iter->ob->obmat);
188  /* Negate thickness sign to tag that strokes are in screen space.
189  * Convert to world units (by default, 1 meter = 2000 pixels). */
190  float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
191 
193  DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d);
194  DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale);
195  DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", (float)gpl->line_change);
196  DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale);
197  DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
198 }
199 
201  bGPDframe *UNUSED(gpf),
202  bGPDstroke *gps,
203  void *thunk)
204 {
205  iterData *iter = (iterData *)thunk;
206 
207  MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
208 
209  bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
210  bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
211  // TODO: What about simplify Fill?
212  bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
213 
214  if (hide_material) {
215  return;
216  }
217 
218  if (show_fill) {
219  struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra);
220  int vfirst = gps->runtime.fill_start * 3;
221  int vcount = gps->tot_triangles * 3;
222  DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount);
223  }
224 
225  if (show_stroke) {
226  struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra);
227  /* Start one vert before to have gl_InstanceID > 0 (see shader). */
228  int vfirst = gps->runtime.stroke_start - 1;
229  /* Include "potential" cyclic vertex and start adj vertex (see shader). */
230  int vcount = gps->totpoints + 1 + 1;
231  DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
232  }
233 }
234 
236 {
237  /* No outlines in edit mode. */
238  bGPdata *gpd = (bGPdata *)ob->data;
239  if (gpd && GPENCIL_ANY_MODE(gpd)) {
240  return;
241  }
242 
243  iterData iter = {
244  .ob = ob,
245  .stroke_grp = pd->outlines_gpencil_grp,
247  .cfra = pd->cfra,
248  };
249 
250  if (gpd->draw_mode == GP_DRAWMODE_2D) {
251  gpencil_depth_plane(ob, iter.plane);
252  }
253 
255  ob,
258  &iter,
259  false,
260  pd->cfra);
261 }
262 
264 {
266  if (geom == NULL) {
267  return;
268  }
269 
270  DRWShadingGroup *shgroup = pd->outlines_grp;
271  DRW_shgroup_call(shgroup, geom, ob);
272 }
273 
275 {
276  DRWShadingGroup *shgroup = pd->outlines_curves_grp;
277  DRW_shgroup_curves_create_sub(ob, shgroup, NULL);
278 }
279 
281  Object *ob,
282  OVERLAY_DupliData *dupli,
283  bool init_dupli)
284 {
285  OVERLAY_PrivateData *pd = vedata->stl->pd;
286  const DRWContextState *draw_ctx = DRW_context_state_get();
287  struct GPUBatch *geom;
288  DRWShadingGroup *shgroup = NULL;
289  const bool draw_outline = ob->dt > OB_BOUNDBOX;
290 
291  /* Early exit: outlines of bounding boxes are not drawn. */
292  if (!draw_outline) {
293  return;
294  }
295 
296  if (ob->type == OB_GPENCIL) {
297  OVERLAY_outline_gpencil(pd, ob);
298  return;
299  }
300 
301  if (ob->type == OB_VOLUME) {
302  OVERLAY_outline_volume(pd, ob);
303  return;
304  }
305 
306  if (ob->type == OB_CURVES) {
307  OVERLAY_outline_curves(pd, ob);
308  return;
309  }
310 
311  if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) {
312  /* Looks bad in this case. Could be relaxed if we draw a
313  * wireframe of some sort in the future. */
314  return;
315  }
316 
317  if (dupli && !init_dupli) {
318  geom = dupli->outline_geom;
319  shgroup = dupli->outline_shgrp;
320  }
321  else {
322  /* This fixes only the biggest case which is a plane in ortho view. */
323  int flat_axis = 0;
324  bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
325  DRW_object_is_flat(ob, &flat_axis) &&
326  DRW_object_axis_orthogonal_to_view(ob, flat_axis));
327 
328  if (pd->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
330  }
331  else {
332  geom = DRW_cache_object_surface_get(ob);
333  }
334 
335  if (geom) {
336  shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp;
337  }
338  }
339 
340  if (shgroup && geom) {
341  if (ob->type == OB_POINTCLOUD) {
342  /* Draw range to avoid drawcall batching messing up the instance attribute. */
343  DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0);
344  }
345  else {
346  DRW_shgroup_call(shgroup, geom, ob);
347  }
348  }
349 
350  if (init_dupli) {
351  dupli->outline_shgrp = shgroup;
352  dupli->outline_geom = geom;
353  }
354 }
355 
357 {
358  OVERLAY_FramebufferList *fbl = vedata->fbl;
359  OVERLAY_PassList *psl = vedata->psl;
360  const float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
361 
362  bool do_outlines = psl->outlines_prepass_ps != NULL &&
364 
365  if (DRW_state_is_fbo() && do_outlines) {
366  DRW_stats_group_start("Outlines");
367 
368  /* Render filled polygon on a separate framebuffer */
370  GPU_framebuffer_clear_color_depth_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00);
372 
373  /* Search outline pixels */
376 
378  }
379 }
@ G_TRANSFORM_OBJ
Definition: BKE_global.h:247
void BKE_gpencil_visible_stroke_advanced_iter(struct ViewLayer *view_layer, struct Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra)
Definition: gpencil.c:2430
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
Definition: material.c:805
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])
const struct BoundBox * BKE_object_boundbox_get(struct Object *ob)
Definition: object.cc:3684
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:209
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1206
void unit_m4(float m[4][4])
Definition: rct.c:1090
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:790
void rescale_m4(float mat[4][4], const float scale[3])
Definition: math_matrix.c:2362
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2185
void transpose_m4(float R[4][4])
Definition: math_matrix.c:1377
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_CURVES
@ OB_GPENCIL
#define V3D_SELECT_OUTLINE
#define RV3D_ORTHO
DRWState
Definition: DRW_render.h:298
@ DRW_STATE_WRITE_DEPTH
Definition: DRW_render.h:302
@ DRW_STATE_WRITE_COLOR
Definition: DRW_render.h:303
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition: DRW_render.h:311
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition: DRW_render.h:330
#define DRW_PASS_CREATE(pass, state)
Definition: DRW_render.h:690
#define DRW_shgroup_uniform_block(shgroup, name, ubo)
Definition: DRW_render.h:651
#define DRW_shgroup_call(shgroup, geom, ob)
Definition: DRW_render.h:414
NSNotificationCenter * center
GPUBatch
Definition: GPU_batch.h:78
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
struct GPUShader GPUShader
Definition: GPU_shader.h:20
@ GPU_R16UI
Definition: GPU_texture.h:111
@ GPU_DEPTH24_STENCIL8
Definition: GPU_texture.h:120
@ TH_OUTLINE_WIDTH
Definition: UI_resources.h:82
float UI_GetThemeValuef(int colorid)
Definition: resources.c:1141
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:812
GPUBatch * DRW_cache_volume_selection_surface_get(Object *ob)
Definition: draw_cache.c:3081
GPUBatch * DRW_cache_object_surface_get(Object *ob)
Definition: draw_cache.c:887
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:32
bool DRW_object_is_flat(Object *ob, int *r_axis)
Definition: draw_common.c:411
bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis)
Definition: draw_common.c:444
struct DRWShadingGroup * DRW_shgroup_curves_create_sub(struct Object *object, struct DRWShadingGroup *shgrp, struct GPUMaterial *gpu_material)
Definition: draw_curves.cc:303
bool DRW_state_is_fbo(void)
const DRWContextState * DRW_context_state_get(void)
DefaultTextureList * DRW_viewport_texture_list_get(void)
Definition: draw_manager.c:638
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
void DRW_shgroup_call_instance_range(DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_num)
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_num)
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)
const int state
ccl_gpu_kernel_postfix ccl_global float int int int int sh
#define G(x, y, z)
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])
static void OVERLAY_outline_curves(OVERLAY_PrivateData *pd, Object *ob)
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)
GPUShader * OVERLAY_shader_outline_prepass_curves(void)
struct RegionView3D * rv3d
Definition: DRW_render.h:975
struct GPUUniformBuf * block_ubo
Definition: draw_common.h:129
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
struct OVERLAY_PrivateData::@249 antialiasing
DRWShadingGroup * outlines_gpencil_grp
DRWShadingGroup * outlines_grp
DRWShadingGroup * outlines_curves_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