Blender V4.3
overlay_wireframe.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
10#include "DNA_mesh_types.h"
11#include "DNA_particle_types.h"
12#include "DNA_view3d_types.h"
13#include "DNA_volume_types.h"
14
15#include "BKE_curve.hh"
16#include "BKE_displist.h"
17#include "BKE_duplilist.hh"
18#include "BKE_editmesh.hh"
19#include "BKE_global.hh"
20#include "BKE_mesh_types.hh"
21#include "BKE_object.hh"
22#include "BKE_paint.hh"
23#include "BKE_particle.h"
24
25#include "BLI_hash.h"
26#include "BLI_math_base.hh"
27
28#include "DRW_render.hh"
29#include "GPU_shader.hh"
30
31#include "ED_view3d.hh"
32
33#include "overlay_private.hh"
34
35using namespace blender::math;
36
38{
39 OVERLAY_PrivateData *pd = vedata->stl->pd;
40 const DRWContextState *draw_ctx = DRW_context_state_get();
41 DRWView *default_view = (DRWView *)DRW_view_default_get();
42 pd->view_wires = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f);
43}
44
46{
47 OVERLAY_PassList *psl = vedata->psl;
48 OVERLAY_TextureList *txl = vedata->txl;
49 OVERLAY_PrivateData *pd = vedata->stl->pd;
50 const DRWContextState *draw_ctx = DRW_context_state_get();
51 DRWShadingGroup *grp = nullptr;
52
53 View3DShading *shading = &draw_ctx->v3d->shading;
54
55 /* Use `sqrt` since the value stored in the edge is a variation of the cosine, so its square
56 * becomes more proportional with a variation of angle. */
58
59 /* The maximum value (255 in the VBO) is used to force hide the edge. */
60 pd->shdata.wire_step_param = interpolate(0.0f, 1.0f - (1.0f / 255), pd->shdata.wire_step_param);
61
63
64 bool is_material_shmode = (shading->type > OB_SOLID);
65
66 int color_type = shading->wire_color_type;
67
68 const bool use_select = (DRW_state_is_select() || DRW_state_is_depth());
69 GPUShader *wires_sh = use_select ? OVERLAY_shader_wireframe_select() :
71
72 for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) {
75 DRWPass *pass;
76 GPUTexture **depth_tx = ((!pd->xray_enabled || pd->xray_opacity > 0.0f) &&
78 &txl->temp_depth_tx :
79 &txl->dummy_depth_tx;
80
81 if (xray == 0) {
83 pass = psl->wireframe_ps;
84 }
85 else {
87 pass = psl->wireframe_xray_ps;
88 }
89
90 for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
91 pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
92 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
93 DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx);
94 DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param);
95 DRW_shgroup_uniform_float_copy(grp, "wireOpacity", pd->shdata.wire_opacity);
96 DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring);
97 DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
98 DRW_shgroup_uniform_int_copy(grp, "colorType", color_type);
99 DRW_shgroup_uniform_bool_copy(grp, "isHair", false);
100
101 pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
102 DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
103
104 pd->wires_hair_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
105 DRW_shgroup_uniform_bool_copy(grp, "isHair", true);
106 DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
107 }
108
109 pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
110 DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx);
111 DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
112 DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
113 DRW_shgroup_uniform_bool_copy(grp, "isHair", false);
114 }
115
116 if (is_material_shmode) {
117 /* Make all drawcalls go into the non-xray shading groups. */
118 for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
119 pd->wires_grp[1][use_coloring] = pd->wires_grp[0][use_coloring];
120 pd->wires_all_grp[1][use_coloring] = pd->wires_all_grp[0][use_coloring];
121 pd->wires_hair_grp[1][use_coloring] = pd->wires_hair_grp[0][use_coloring];
122 }
123 pd->wires_sculpt_grp[1] = pd->wires_sculpt_grp[0];
124 psl->wireframe_xray_ps = nullptr;
125 }
126}
127
129{
130 OVERLAY_PrivateData *pd = vedata->stl->pd;
131 const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
132
133 Object *dupli_parent = DRW_object_get_dupli_parent(ob);
134 DupliObject *dupli_object = DRW_object_get_dupli(ob);
135
136 float dupli_mat[4][4];
137 if ((dupli_parent != nullptr) && (dupli_object != nullptr)) {
138 if (dupli_object->type & OB_DUPLICOLLECTION) {
139 unit_m4(dupli_mat);
140 Collection *collection = dupli_parent->instance_collection;
141 if (collection != nullptr) {
142 sub_v3_v3(dupli_mat[3], collection->instance_offset);
143 }
144 mul_m4_m4m4(dupli_mat, dupli_parent->object_to_world().ptr(), dupli_mat);
145 }
146 else {
147 copy_m4_m4(dupli_mat, dupli_object->ob->object_to_world().ptr());
148 invert_m4(dupli_mat);
149 mul_m4_m4m4(dupli_mat, ob->object_to_world().ptr(), dupli_mat);
150 }
151 }
152 else {
153 unit_m4(dupli_mat);
154 }
155
156 blender::gpu::Batch *hairs = DRW_cache_particles_get_hair(ob, psys, nullptr);
157
158 const bool use_coloring = true;
159 DRWShadingGroup *shgrp = DRW_shgroup_create_sub(pd->wires_hair_grp[is_xray][use_coloring]);
160 DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", dupli_mat);
161 DRW_shgroup_call_no_cull(shgrp, hairs, ob);
162}
163
165 Object *ob,
166 OVERLAY_DupliData *dupli,
167 bool init_dupli)
168{
169 OVERLAY_PrivateData *pd = vedata->stl->pd;
170 const DRWContextState *draw_ctx = DRW_context_state_get();
171 const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0;
172 const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
173 const bool is_mesh = ob->type == OB_MESH;
174 const bool is_edit_mode = DRW_object_is_in_edit_mode(ob);
175 bool has_edit_mesh_cage = false;
176 bool is_mesh_verts_only = false;
177 if (is_mesh) {
178 /* TODO: Should be its own function. */
179 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
180 if (is_edit_mode) {
181 BLI_assert(mesh->runtime->edit_mesh.get());
182 const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
183 const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
184 has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
185 if (editmesh_eval_final) {
186 mesh = editmesh_eval_final;
187 }
188 }
189 is_mesh_verts_only = mesh->edges_num == 0 && mesh->verts_num > 0;
190 }
191
192 const bool use_wire = !is_mesh_verts_only && ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
193 (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE));
194
195 if (use_wire && pd->wireframe_mode && ob->particlesystem.first) {
196 for (ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
197 psys != nullptr;
198 psys = psys->next)
199 {
201 continue;
202 }
203 ParticleSettings *part = psys->part;
204 const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
205 if (draw_as == PART_DRAW_PATH) {
206 wireframe_hair_cache_populate(vedata, ob, psys);
207 }
208 }
209 }
210
213 float *color;
214 DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
215
216 blender::gpu::Batch *geom = nullptr;
217 switch (ob->type) {
218 case OB_CURVES_LEGACY:
220 break;
221 case OB_FONT:
223 break;
224 case OB_SURF:
226 break;
227 }
228
229 if (geom) {
230 OVERLAY_extra_wire(cb, geom, ob->object_to_world().ptr(), color);
231 }
232 }
233
234 /* Fast path for duplis. */
235 if (dupli && !init_dupli) {
236 if (dupli->wire_shgrp && dupli->wire_geom) {
237 if (dupli->base_flag == ob->base_flag) {
238 /* Check for the special cases used below, assign specific theme colors to the shaders. */
240 if (dupli->wire_shgrp == cb->extra_loose_points) {
241 float *color;
242 DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
243 OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->object_to_world().ptr(), color);
244 }
245 else if (dupli->wire_shgrp == cb->extra_wire) {
246 float *color;
247 DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
248 OVERLAY_extra_wire(cb, dupli->wire_geom, ob->object_to_world().ptr(), color);
249 }
250 else {
251 DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
252 }
253 return;
254 }
255 }
256 else {
257 /* Nothing to draw for this dupli. */
258 return;
259 }
260 }
261
262 if (use_wire && ELEM(ob->type, OB_VOLUME, OB_POINTCLOUD)) {
263 bool draw_as_points = true;
264 if (ob->type == OB_VOLUME) {
265 /* Volume object as points exception. */
266 Volume *volume = static_cast<Volume *>(ob->data);
267 draw_as_points = volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS;
268 }
269
270 if (draw_as_points) {
271 float *color;
273 DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
274
275 blender::gpu::Batch *geom = DRW_cache_object_face_wireframe_get(draw_ctx->scene, ob);
276 if (geom) {
277 OVERLAY_extra_loose_points(cb, geom, ob->object_to_world().ptr(), color);
278 }
279 return;
280 }
281 }
282
283 DRWShadingGroup *shgrp = nullptr;
284 blender::gpu::Batch *geom = nullptr;
285
286 /* Don't do that in edit Mesh mode, unless there is a modifier preview. */
287 if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
288 const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != nullptr);
289 const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) &&
291 const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI);
292 const bool instance_parent_in_edit_mode = is_instance ? DRW_object_is_in_edit_mode(
294 false;
295 const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode &&
296 !has_edit_mesh_cage && !instance_parent_in_edit_mode);
297 geom = DRW_cache_object_face_wireframe_get(draw_ctx->scene, ob);
298
299 if (geom || use_sculpt_pbvh) {
300 if (use_sculpt_pbvh) {
301 shgrp = pd->wires_sculpt_grp[is_xray];
302 }
303 else if (all_wires) {
304 shgrp = pd->wires_all_grp[is_xray][use_coloring];
305 }
306 else {
307 shgrp = pd->wires_grp[is_xray][use_coloring];
308 }
309
311 /* TODO(fclem): Make GPencil objects have correct bound-box. */
312 DRW_shgroup_call_no_cull(shgrp, geom, ob);
313 }
314 else if (use_sculpt_pbvh) {
315 DRW_shgroup_call_sculpt(shgrp, ob, true, false, false, false, false);
316 }
317 else {
318 DRW_shgroup_call(shgrp, geom, ob);
319 }
320 }
321 }
322 else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) {
324 float *color;
325 DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
326
327 /* Draw loose geometry. */
328 if (is_mesh_verts_only) {
330 if (geom) {
331 OVERLAY_extra_loose_points(cb, geom, ob->object_to_world().ptr(), color);
332 shgrp = cb->extra_loose_points;
333 }
334 }
335 else {
337 if (geom) {
338 OVERLAY_extra_wire(cb, geom, ob->object_to_world().ptr(), color);
339 shgrp = cb->extra_wire;
340 }
341 }
342 }
343
344 if (dupli) {
345 dupli->wire_shgrp = shgrp;
346 dupli->wire_geom = geom;
347 }
348}
349
351{
352 OVERLAY_PassList *psl = data->psl;
353 OVERLAY_PrivateData *pd = data->stl->pd;
354
357
358 DRW_view_set_active(nullptr);
359}
360
362{
363 OVERLAY_PassList *psl = data->psl;
364 OVERLAY_PrivateData *pd = data->stl->pd;
365
366 if (psl->wireframe_xray_ps) {
369
370 DRW_view_set_active(nullptr);
371 }
372}
display list (or rather multi purpose list) stuff.
@ G_TRANSFORM_OBJ
General operations, lookup, etc. for blender objects.
const Mesh * BKE_object_get_editmesh_eval_cage(const Object *object)
const Mesh * BKE_object_get_editmesh_eval_final(const Object *object)
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2862
#define BLI_assert(a)
Definition BLI_assert.h:50
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 copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4(float mat[4][4])
MINLINE void sub_v3_v3(float r[3], const float a[3])
#define ELEM(...)
Object groups, one object can be in many groups at once.
@ BASE_FROM_DUPLI
@ OB_WIRE
@ OB_SOLID
@ OB_MODE_SCULPT
@ OB_SURF
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_GPENCIL_LEGACY
@ OB_DRAW_ALL_EDGES
@ OB_DRAW_IN_FRONT
@ OB_DRAWWIRE
@ OB_DUPLICOLLECTION
@ PART_DRAW_PATH
@ PART_DRAW_REND
@ V3D_OVERLAY_WIREFRAMES
@ VOLUME_WIREFRAME_POINTS
#define DRW_shgroup_call_no_cull(shgroup, geom, ob)
#define DRW_PASS_CREATE(pass, state)
#define DRW_shgroup_uniform_block(shgroup, name, ubo)
#define DRW_shgroup_call(shgroup, geom, ob)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
struct GPUShader GPUShader
blender::gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_object_face_wireframe_get(const Scene *scene, Object *ob)
blender::gpu::Batch * DRW_cache_surf_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
blender::gpu::Batch * DRW_cache_mesh_all_verts_get(Object *ob)
blender::gpu::Batch * DRW_cache_text_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_mesh_loose_edges_get(Object *ob)
int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color)
DRWView * DRW_view_create_with_zoffset(const DRWView *parent_view, const RegionView3D *rv3d, float offset)
DRW_Global G_draw
Object * DRW_object_get_dupli_parent(const Object *)
bool DRW_object_is_in_edit_mode(const Object *ob)
bool DRW_state_is_image_render()
bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys)
const DRWContextState * DRW_context_state_get()
DupliObject * DRW_object_get_dupli(const Object *)
bool DRW_state_is_fbo()
bool DRW_state_is_select()
bool DRW_state_is_depth()
const DRWView * DRW_view_default_get()
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_call_sculpt(DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask, bool use_fset, bool use_color, bool use_uv)
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int 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_uniform_mat4_copy(DRWShadingGroup *shgroup, const char *name, const float(*value)[4])
void DRW_draw_pass(DRWPass *pass)
void DRW_view_set_active(const DRWView *view)
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_FIRST_VERTEX_CONVENTION
Definition draw_state.hh:70
static ulong state[N]
#define G(x, y, z)
T sqrt(const T &a)
T interpolate(const T &a, const T &b, const FactorT &t)
T abs(const T &a)
void OVERLAY_extra_wire(OVERLAY_ExtraCallBuffers *cb, blender::gpu::Batch *geom, const float mat[4][4], const float color[4])
OVERLAY_ExtraCallBuffers * OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob)
void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb, blender::gpu::Batch *geom, const float mat[4][4], const float color[4])
GPUShader * OVERLAY_shader_wireframe(bool custom_bias)
GPUShader * OVERLAY_shader_wireframe_select()
static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, ParticleSystem *psys)
void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *data)
void OVERLAY_wireframe_draw(OVERLAY_Data *data)
void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, bool init_dupli)
void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
void OVERLAY_wireframe_init(OVERLAY_Data *vedata)
ViewLayer * view_layer
RegionView3D * rv3d
GPUUniformBuf * block_ubo
void * first
int edges_num
OVERLAY_PassList * psl
OVERLAY_StorageList * stl
OVERLAY_TextureList * txl
DRWShadingGroup * wire_shgrp
blender::gpu::Batch * wire_geom
DRWShadingGroup * extra_wire
DRWShadingGroup * extra_loose_points
DRWPass * wireframe_xray_ps
OVERLAY_ShadingData shdata
DRWShadingGroup * wires_all_grp[2][2]
struct OVERLAY_PrivateData::@227 antialiasing
DRWShadingGroup * wires_hair_grp[2][2]
DRWShadingGroup * wires_grp[2][2]
DRWShadingGroup * wires_sculpt_grp[2]
OVERLAY_PrivateData * pd
GPUTexture * dummy_depth_tx
GPUTexture * temp_depth_tx
ListBase particlesystem
struct Collection * instance_collection
short base_flag
struct SculptSession * sculpt
View3DShading shading
VolumeDisplay display
ccl_device_inline bool is_mesh(const ccl_global KernelLightTreeEmitter *kemitter)
Definition tree.h:69