Blender V4.3
overlay_next_sculpt.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#pragma once
10
11#include "BKE_attribute.hh"
12#include "BKE_mesh.hh"
13#include "BKE_paint.hh"
14#include "BKE_pbvh_api.hh"
15#include "BKE_subdiv_ccg.hh"
16
17#include "draw_cache_impl.hh"
18
20
21namespace blender::draw::overlay {
22
23class Sculpts {
24
25 private:
26 const SelectionType selection_type_;
27
28 PassSimple sculpt_mask_ = {"SculptMaskAndFaceSet"};
29 PassSimple::Sub *mesh_ps_ = nullptr;
30 PassSimple::Sub *curves_ps_ = nullptr;
31
32 PassSimple sculpt_curve_cage_ = {"SculptCage"};
33
34 bool show_curves_cage_ = false;
35 bool show_face_set_ = false;
36 bool show_mask_ = false;
37
38 bool enabled_ = false;
39
40 public:
41 Sculpts(const SelectionType selection_type_) : selection_type_(selection_type_) {}
42
43 void begin_sync(Resources &res, const State &state)
44 {
45 const int sculpt_overlay_flags = V3D_OVERLAY_SCULPT_SHOW_FACE_SETS |
47
48 enabled_ = (state.space_type == SPACE_VIEW3D) && !state.xray_enabled &&
49 (selection_type_ == SelectionType::DISABLED) &&
51 (state.overlay.flag & sculpt_overlay_flags);
52
53 if (!enabled_) {
54 /* Not used. But release the data. */
55 sculpt_mask_.init();
56 sculpt_curve_cage_.init();
57 return;
58 }
59
60 show_curves_cage_ = state.overlay.flag & V3D_OVERLAY_SCULPT_CURVES_CAGE;
61 show_face_set_ = state.overlay.flag & V3D_OVERLAY_SCULPT_SHOW_FACE_SETS;
62 show_mask_ = state.overlay.flag & V3D_OVERLAY_SCULPT_SHOW_MASK;
63
64 float curve_cage_opacity = show_curves_cage_ ? state.overlay.sculpt_curves_cage_opacity : 0.0f;
65 float face_set_opacity = show_face_set_ ? state.overlay.sculpt_mode_face_sets_opacity : 0.0f;
66 float mask_opacity = show_mask_ ? state.overlay.sculpt_mode_mask_opacity : 0.0f;
67
68 {
69 sculpt_mask_.init();
72 state.clipping_plane_count);
73 {
74 auto &sub = sculpt_mask_.sub("Mesh");
75 sub.shader_set(res.shaders.sculpt_mesh.get());
76 sub.bind_ubo("globalsBlock", &res.globals_buf);
77 sub.push_constant("maskOpacity", mask_opacity);
78 sub.push_constant("faceSetsOpacity", face_set_opacity);
79 mesh_ps_ = ⊂
80 }
81 {
82 auto &sub = sculpt_mask_.sub("Curves");
83 sub.shader_set(res.shaders.sculpt_curves.get());
84 sub.bind_ubo("globalsBlock", &res.globals_buf);
85 sub.push_constant("selection_opacity", mask_opacity);
86 curves_ps_ = ⊂
87 }
88 }
89 {
90 auto &pass = sculpt_curve_cage_;
91 pass.init();
93 state.clipping_plane_count);
94 pass.shader_set(res.shaders.sculpt_curves_cage.get());
95 pass.bind_ubo("globalsBlock", &res.globals_buf);
96 pass.push_constant("opacity", curve_cage_opacity);
97 }
98 }
99
100 void object_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
101 {
102 if (!enabled_) {
103 return;
104 }
105
106 switch (ob_ref.object->type) {
107 case OB_MESH:
108 mesh_sync(manager, ob_ref, state);
109 break;
110 case OB_CURVES:
111 curves_sync(manager, ob_ref, state);
112 break;
113 }
114 }
115
116 void curves_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
117 {
118 ::Curves *curves = static_cast<::Curves *>(ob_ref.object->data);
119
120 /* As an optimization, draw nothing if everything is selected. */
121 if (show_mask_ && !everything_selected(*curves)) {
122 /* Retrieve the location of the texture. */
123 bool is_point_domain;
125 curves, ".selection", &is_point_domain);
126 if (select_attr_buf) {
127 /* Evaluate curves and their attributes if necessary. */
128 gpu::Batch *geometry = curves_sub_pass_setup(*curves_ps_, state.scene, ob_ref.object);
129 if (*select_attr_buf) {
130 ResourceHandle handle = manager.unique_handle(ob_ref);
131
132 curves_ps_->push_constant("is_point_domain", is_point_domain);
133 curves_ps_->bind_texture("selection_tx", *select_attr_buf);
134 curves_ps_->draw(geometry, handle);
135 }
136 }
137 }
138
139 if (show_curves_cage_) {
140 ResourceHandle handle = manager.unique_handle(ob_ref);
141
142 blender::gpu::Batch *geometry = DRW_curves_batch_cache_get_sculpt_curves_cage(curves);
143 sculpt_curve_cage_.draw(geometry, handle);
144 }
145 }
146
147 void mesh_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
148 {
149 if (!show_face_set_ && !show_mask_) {
150 /* Nothing to display. */
151 return;
152 }
153
154 const SculptSession *sculpt_session = ob_ref.object->sculpt;
155 if (sculpt_session == nullptr) {
156 return;
157 }
158
160 if (!pbvh) {
161 /* It is possible to have SculptSession without pbvh::Tree. This happens, for example, when
162 * toggling object mode to sculpt then to edit mode. */
163 return;
164 }
165
166 /* Using the original object/geometry is necessary because we skip depsgraph updates in sculpt
167 * mode to improve performance. This means the evaluated mesh doesn't have the latest face set,
168 * visibility, and mask data. */
169 Object *object_orig = reinterpret_cast<Object *>(DEG_get_original_id(&ob_ref.object->id));
170 if (!object_orig) {
172 return;
173 }
174
175 switch (pbvh->type()) {
177 const Mesh &mesh = *static_cast<const Mesh *>(object_orig->data);
178 if (!mesh.attributes().contains(".sculpt_face_set") &&
179 !mesh.attributes().contains(".sculpt_mask"))
180 {
181 return;
182 }
183 break;
184 }
186 const SubdivCCG &subdiv_ccg = *sculpt_session->subdiv_ccg;
187 const Mesh &base_mesh = *static_cast<const Mesh *>(object_orig->data);
188 if (!BKE_subdiv_ccg_key_top_level(subdiv_ccg).has_mask &&
189 !base_mesh.attributes().contains(".sculpt_face_set"))
190 {
191 return;
192 }
193 break;
194 }
196 const BMesh &bm = *sculpt_session->bm;
197 if (!CustomData_has_layer_named(&bm.pdata, CD_PROP_FLOAT, ".sculpt_face_set") &&
199 {
200 return;
201 }
202 break;
203 }
204 }
205
206 const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d);
207 if (use_pbvh) {
208 ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
209
210 SculptBatchFeature sculpt_batch_features_ = (show_face_set_ ? SCULPT_BATCH_FACE_SET :
212 (show_mask_ ? SCULPT_BATCH_MASK :
214
215 for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, sculpt_batch_features_)) {
216 mesh_ps_->draw(batch.batch, handle);
217 }
218 }
219 else {
220 ResourceHandle handle = manager.unique_handle(ob_ref);
221
222 Mesh &mesh = *static_cast<Mesh *>(ob_ref.object->data);
223 gpu::Batch *sculpt_overlays = DRW_mesh_batch_cache_get_sculpt_overlays(mesh);
224 mesh_ps_->draw(sculpt_overlays, handle);
225 }
226 }
227
228 void draw(GPUFrameBuffer *framebuffer, Manager &manager, View &view)
229 {
230 if (!enabled_) {
231 return;
232 }
233 GPU_framebuffer_bind(framebuffer);
234 manager.submit(sculpt_curve_cage_, view);
235 }
236
237 void draw_on_render(GPUFrameBuffer *framebuffer, Manager &manager, View &view)
238 {
239 if (!enabled_) {
240 return;
241 }
242 GPU_framebuffer_bind(framebuffer);
243 manager.submit(sculpt_mask_, view);
244 }
245
246 private:
247 bool everything_selected(const ::Curves &curves_id)
248 {
249 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
250 const VArray<bool> selection = *curves.attributes().lookup_or_default<bool>(
251 ".selection", bke::AttrDomain::Point, true);
252 return selection.is_single() && selection.get_internal_single();
253 }
254};
255
256} // namespace blender::draw::overlay
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2862
A BVH for high poly meshes.
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define ELEM(...)
ID * DEG_get_original_id(ID *id)
@ CD_PROP_FLOAT
@ OB_MODE_SCULPT
@ OB_MODE_SCULPT_CURVES
@ OB_MESH
@ OB_CURVES
@ SPACE_VIEW3D
@ V3D_OVERLAY_SCULPT_SHOW_FACE_SETS
@ V3D_OVERLAY_SCULPT_SHOW_MASK
@ V3D_OVERLAY_SCULPT_CURVES_CAGE
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
ATTR_WARN_UNUSED_RESULT BMesh * bm
AttributeSet attributes
ResourceHandle unique_handle(const ObjectRef &ref)
ResourceHandle resource_handle_for_sculpt(const ObjectRef &ref)
void submit(PassSimple &pass, View &view)
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:760
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void push_constant(const char *name, const float &data)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
Sculpts(const SelectionType selection_type_)
void mesh_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
void draw_on_render(GPUFrameBuffer *framebuffer, Manager &manager, View &view)
void curves_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
void object_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
void begin_sync(Resources &res, const State &state)
void draw(GPUFrameBuffer *framebuffer, Manager &manager, View &view)
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_BLEND_MUL
Definition draw_state.hh:60
struct @620::@622 batch
static ulong state[N]
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, GPUMaterial *gpu_material=nullptr)
Vector< SculptBatch > sculpt_batches_get(const Object *ob, SculptBatchFeature features)
blender::gpu::Batch * DRW_curves_batch_cache_get_sculpt_curves_cage(Curves *curves)
gpu::VertBuf ** DRW_curves_texture_for_evaluated_attribute(Curves *curves, const char *name, bool *r_is_point_domain)
blender::gpu::Batch * DRW_mesh_batch_cache_get_sculpt_overlays(Mesh &mesh)
CustomData vdata
CustomData pdata
int has_mask
Definition BKE_ccg.hh:48
struct SculptSession * sculpt
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405