Blender V4.3
overlay_outline.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_vector.hh"
10
11#include "DRW_render.hh"
12
13#include "BKE_curves.hh"
14#include "BKE_global.hh"
15#include "BKE_gpencil_legacy.h"
16#include "BKE_grease_pencil.hh"
17
18#include "BKE_object.hh"
19
21
22#include "ED_grease_pencil.hh"
23
24#include "UI_resources.hh"
25
26#include "overlay_private.hh"
27
28/* Returns the normal plane in NDC space. */
29static void gpencil_depth_plane(Object *ob, float r_plane[4])
30{
31 using namespace blender;
32 /* TODO: put that into private data. */
33 float viewinv[4][4];
34 DRW_view_viewmat_get(nullptr, viewinv, true);
35 float *camera_z_axis = viewinv[2];
36 float *camera_pos = viewinv[3];
37
38 /* Find the normal most likely to represent the grease pencil object. */
39 /* TODO: This does not work quite well if you use
40 * strokes not aligned with the object axes. Maybe we could try to
41 * compute the minimum axis of all strokes. But this would be more
42 * computationally heavy and should go into the GPData evaluation. */
43 const std::optional<Bounds<float3>> bounds = BKE_object_boundbox_get(ob).value_or(
44 Bounds(float3(0)));
45 float3 size = (bounds->max - bounds->min) * 0.5f;
46 float3 center = math::midpoint(bounds->min, bounds->max);
47 /* Convert bbox to matrix */
48 float mat[4][4];
49 unit_m4(mat);
50 copy_v3_v3(mat[3], center);
51 /* Avoid division by 0.0 later. */
52 add_v3_fl(size, 1e-8f);
53 rescale_m4(mat, size);
54 /* BBox space to World. */
55 mul_m4_m4m4(mat, ob->object_to_world().ptr(), mat);
56 /* BBox center in world space. */
57 copy_v3_v3(center, mat[3]);
58 /* View Vector. */
59 if (DRW_view_is_persp_get(nullptr)) {
60 /* BBox center to camera vector. */
61 sub_v3_v3v3(r_plane, camera_pos, mat[3]);
62 }
63 else {
64 copy_v3_v3(r_plane, camera_z_axis);
65 }
66 /* World to BBox space. */
67 invert_m4(mat);
68 /* Normalize the vector in BBox space. */
69 mul_mat3_m4_v3(mat, r_plane);
70 normalize_v3(r_plane);
71
72 transpose_m4(mat);
73 /* mat is now a "normal" matrix which will transform
74 * BBox space normal to world space. */
75 mul_mat3_m4_v3(mat, r_plane);
76 normalize_v3(r_plane);
77
78 plane_from_point_normal_v3(r_plane, center, r_plane);
79}
80
82{
83 OVERLAY_FramebufferList *fbl = vedata->fbl;
84 OVERLAY_TextureList *txl = vedata->txl;
85 OVERLAY_PrivateData *pd = vedata->stl->pd;
87
88 if (DRW_state_is_fbo()) {
89 /* TODO: only alloc if needed. */
92
95 {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
96
97 if (pd->antialiasing.enabled) {
99 {
100 GPU_ATTACHMENT_NONE,
101 GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
102 GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx),
103 });
104 }
105 else {
107 {
108 GPU_ATTACHMENT_NONE,
109 GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
110 });
111 }
112 }
113}
114
116{
117 OVERLAY_PassList *psl = vedata->psl;
118 OVERLAY_TextureList *txl = vedata->txl;
119 OVERLAY_PrivateData *pd = vedata->stl->pd;
121 DRWShadingGroup *grp = nullptr;
122
123 const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
124 const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
125
126 {
129
131
132 pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps);
133 DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
134 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
135
137
138 pd->outlines_ptcloud_grp = grp = DRW_shgroup_create(sh_geom_ptcloud, psl->outlines_prepass_ps);
139 DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
140 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
141
143
144 pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
145 DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
146 DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", 0.0);
147 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
148
150
152 DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
153 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
154 }
155
156 /* outlines_prepass_ps is still needed for selection of probes. */
157 if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
158 return;
159 }
160
161 {
162 /* We can only do alpha blending with lineOutput just after clearing the buffer. */
165
167
169 /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
170 DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
171 DRW_shgroup_uniform_bool_copy(grp, "doThickOutlines", do_expand);
172 DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", pd->antialiasing.enabled);
174 DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
175 DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
176 DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
177 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
179 }
180}
181
182struct iterData {
185 int cfra;
186 float plane[4];
187};
188
190{
191 using namespace blender;
192 using namespace blender::ed::greasepencil;
193 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
194 /* Outlines only in object mode. */
195 if (ob->mode != OB_MODE_OBJECT) {
196 return;
197 }
198
199 float plane[4] = {0.0f, 0.0f, 0.0f, 0.0f};
200 if ((grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) == 0) {
201 gpencil_depth_plane(ob, plane);
202 }
203
204 int t_offset = 0;
205 const Vector<DrawingInfo> drawings = retrieve_visible_drawings(*scene, grease_pencil, true);
206 for (const DrawingInfo info : drawings) {
207 const bool is_stroke_order_3d = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0;
208
209 const float object_scale = mat4_to_scale(ob->object_to_world().ptr());
210 const float thickness_scale = bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
211
212 gpu::VertBuf *position_tx = draw::DRW_cache_grease_pencil_position_buffer_get(scene, ob);
213 gpu::VertBuf *color_tx = draw::DRW_cache_grease_pencil_color_buffer_get(scene, ob);
214
216 DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d);
217 DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale);
218 DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", 0.0f);
219 DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale);
220 DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", plane);
221 DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx);
222 DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx);
223
224 const bke::CurvesGeometry &curves = info.drawing.strokes();
225 const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve();
226 const bke::AttributeAccessor attributes = curves.attributes();
227 const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
228 "material_index", bke::AttrDomain::Curve, 0);
229 const VArray<bool> cyclic = *attributes.lookup_or_default<bool>(
230 "cyclic", bke::AttrDomain::Curve, false);
231
232 IndexMaskMemory memory;
233 const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
234 *ob, info.drawing, memory);
235
236 visible_strokes.foreach_index([&](const int stroke_i) {
237 const IndexRange points = points_by_curve[stroke_i];
238 const int material_index = stroke_materials[stroke_i];
239 MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1);
240
241 const bool hide_onion = info.onion_id != 0;
242 const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
243
244 const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0;
245 const int num_stroke_vertices = (points.size() +
246 int(cyclic[stroke_i] && (points.size() >= 3)));
247
248 if (hide_material || hide_onion) {
249 t_offset += num_stroke_triangles;
250 t_offset += num_stroke_vertices * 2;
251 return;
252 }
253
254 blender::gpu::Batch *geom = draw::DRW_cache_grease_pencil_get(scene, ob);
255
256 const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
257 const bool show_fill = (points.size() >= 3) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
258
259 if (show_fill) {
260 int v_first = t_offset * 3;
261 int v_count = num_stroke_triangles * 3;
262 DRW_shgroup_call_range(grp, ob, geom, v_first, v_count);
263 }
264
265 t_offset += num_stroke_triangles;
266
267 if (show_stroke) {
268 int v_first = t_offset * 3;
269 int v_count = num_stroke_vertices * 2 * 3;
270 DRW_shgroup_call_range(grp, ob, geom, v_first, v_count);
271 }
272 t_offset += num_stroke_vertices * 2;
273 });
274 }
275}
276
278{
279 using namespace blender::draw;
280 blender::gpu::Batch *geom = DRW_cache_volume_selection_surface_get(ob);
281 if (geom == nullptr) {
282 return;
283 }
284
285 DRWShadingGroup *shgroup = pd->outlines_grp;
286 DRW_shgroup_call(shgroup, geom, ob);
287}
288
290{
291 using namespace blender::draw;
293 DRW_shgroup_curves_create_sub(ob, shgroup, nullptr);
294}
295
297{
298 using namespace blender::draw;
299 if (pd->wireframe_mode) {
300 /* Looks bad in this case. Could be relaxed if we draw a
301 * wireframe of some sort in the future. */
302 return;
303 }
304
306 DRW_shgroup_pointcloud_create_sub(ob, shgroup, nullptr);
307}
308
310 Object *ob,
311 OVERLAY_DupliData *dupli,
312 bool init_dupli)
313{
314 OVERLAY_PrivateData *pd = vedata->stl->pd;
315 const DRWContextState *draw_ctx = DRW_context_state_get();
316 blender::gpu::Batch *geom;
317 DRWShadingGroup *shgroup = nullptr;
318 const bool draw_outline = ob->dt > OB_BOUNDBOX;
319
320 /* Early exit: outlines of bounding boxes are not drawn. */
321 if (!draw_outline) {
322 return;
323 }
324
325 if (ob->type == OB_GREASE_PENCIL) {
326 OVERLAY_outline_grease_pencil(pd, draw_ctx->scene, ob);
327 return;
328 }
329
330 if (ob->type == OB_VOLUME) {
332 return;
333 }
334
335 if (ob->type == OB_CURVES) {
337 return;
338 }
339
340 if (ob->type == OB_POINTCLOUD) {
342 return;
343 }
344
345 if (dupli && !init_dupli) {
346 geom = dupli->outline_geom;
347 shgroup = dupli->outline_shgrp;
348 }
349 else {
350 /* This fixes only the biggest case which is a plane in ortho view. */
351 int flat_axis = 0;
352 bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
353 DRW_object_is_flat(ob, &flat_axis) &&
355
356 if (pd->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
357 geom = DRW_cache_object_edge_detection_get(ob, nullptr);
358 }
359 else {
361 }
362
363 if (geom) {
364 shgroup = pd->outlines_grp;
365 }
366 }
367
368 if (shgroup && geom) {
369 DRW_shgroup_call(shgroup, geom, ob);
370 }
371
372 if (init_dupli) {
373 dupli->outline_shgrp = shgroup;
374 dupli->outline_geom = geom;
375 }
376}
377
379{
380 OVERLAY_FramebufferList *fbl = vedata->fbl;
381 OVERLAY_PassList *psl = vedata->psl;
382 const float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
383
384 bool do_outlines = psl->outlines_prepass_ps != nullptr &&
386
387 if (DRW_state_is_fbo() && do_outlines) {
388 DRW_stats_group_start("Outlines");
389
390 /* Render filled polygon on a separate framebuffer */
394
395 /* Search outline pixels */
398
400 }
401}
Low-level operations for curves.
@ G_TRANSFORM_OBJ
Low-level operations for grease pencil.
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
General operations, lookup, etc. for blender objects.
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:215
float mat4_to_scale(const float mat[4][4])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void unit_m4(float m[4][4])
Definition rct.c:1127
void rescale_m4(float mat[4][4], const float scale[3])
bool invert_m4(float mat[4][4])
void transpose_m4(float R[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
MINLINE void add_v3_fl(float r[3], float f)
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])
MINLINE float normalize_v3(float n[3])
@ GREASE_PENCIL_STROKE_ORDER_3D
@ GP_MATERIAL_HIDE
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
@ OB_BOUNDBOX
@ OB_MODE_OBJECT
@ OB_GREASE_PENCIL
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES
@ RV3D_ORTHO
@ V3D_SELECT_OUTLINE
DRWTextureFlag
#define DRW_PASS_CREATE(pass, state)
#define DRW_shgroup_uniform_block(shgroup, name, ubo)
#define DRW_shgroup_call(shgroup, geom, ob)
void GPU_framebuffer_clear_color_depth_stencil(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth, uint clear_stencil)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
#define GPU_framebuffer_ensure_config(_fb,...)
@ GPU_R16UI
@ GPU_DEPTH24_STENCIL8
@ TH_OUTLINE_WIDTH
float UI_GetThemeValuef(int colorid)
struct GPUShader GPUShader
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
unsigned int U
Definition btGjkEpa3.h:78
OffsetIndices< int > evaluated_points_by_curve() const
blender::gpu::Batch * DRW_cache_object_surface_get(Object *ob)
blender::gpu::Batch * DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold)
bool DRW_object_is_flat(Object *ob, int *r_axis)
bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis)
DRW_Global G_draw
DefaultTextureList * DRW_viewport_texture_list_get()
const DRWContextState * DRW_context_state_get()
bool DRW_state_is_fbo()
DRWShadingGroup * DRW_shgroup_create(GPUShader *shader, DRWPass *pass)
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup, const char *name, blender::gpu::VertBuf *vertex_buffer)
bool DRW_view_is_persp_get(const DRWView *view)
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
bool DRW_pass_is_empty(DRWPass *pass)
void DRW_shgroup_call_range(DRWShadingGroup *shgroup, const Object *ob, blender::gpu::Batch *geom, uint v_sta, uint v_num)
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, const Object *ob, uint tri_count)
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_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 DRW_texture_ensure_fullscreen_2d(GPUTexture **tex, eGPUTextureFormat format, DRWTextureFlag flags)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition draw_state.hh:57
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static ulong state[N]
#define G(x, y, z)
T midpoint(const T &a, const T &b)
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)
void OVERLAY_outline_init(OVERLAY_Data *vedata)
void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
static void OVERLAY_outline_pointcloud(OVERLAY_PrivateData *pd, Object *ob)
static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, Object *ob)
static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob)
GPUShader * OVERLAY_shader_outline_prepass(bool use_wire)
GPUShader * OVERLAY_shader_outline_prepass_pointcloud()
GPUShader * OVERLAY_shader_outline_detect()
GPUShader * OVERLAY_shader_outline_prepass_gpencil()
GPUShader * OVERLAY_shader_outline_prepass_curves()
RegionView3D * rv3d
GPUUniformBuf * block_ubo
OVERLAY_PassList * psl
OVERLAY_StorageList * stl
OVERLAY_FramebufferList * fbl
OVERLAY_TextureList * txl
DRWShadingGroup * outline_shgrp
blender::gpu::Batch * outline_geom
GPUFrameBuffer * outlines_prepass_fb
GPUFrameBuffer * outlines_resolve_fb
DRWPass * outlines_detect_ps
DRWPass * outlines_prepass_ps
DRWShadingGroup * outlines_gpencil_grp
DRWShadingGroup * outlines_grp
DRWShadingGroup * outlines_curves_grp
DRWShadingGroup * outlines_ptcloud_grp
struct OVERLAY_PrivateData::@227 antialiasing
OVERLAY_PrivateData * pd
GPUTexture * outlines_id_tx
GPUTexture * temp_depth_tx
DRWShadingGroup * stroke_grp