Blender V4.5
overlay_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
8
9#pragma once
10
11#include "BKE_attribute.hh"
12#include "BKE_curves.hh"
13#include "BKE_mesh.hh"
14#include "BKE_paint.hh"
15#include "BKE_paint_bvh.hh"
16#include "BKE_subdiv_ccg.hh"
18
19#include "DRW_render.hh"
20#include "bmesh.hh"
21
22#include "draw_cache_impl.hh"
23#include "draw_sculpt.hh"
24
25#include "overlay_base.hh"
26
27namespace blender::draw::overlay {
28
35
36 private:
37 PassSimple sculpt_mask_ = {"SculptMaskAndFaceSet"};
38 PassSimple::Sub *mesh_ps_ = nullptr;
39 PassSimple::Sub *curves_ps_ = nullptr;
40
41 PassSimple sculpt_curve_cage_ = {"SculptCage"};
42
43 bool show_curves_cage_ = false;
44 bool show_face_set_ = false;
45 bool show_mask_ = false;
46
47 public:
48 void begin_sync(Resources &res, const State &state) final
49 {
50 show_curves_cage_ = state.show_sculpt_curves_cage();
51 show_face_set_ = state.show_sculpt_face_sets();
52 show_mask_ = state.show_sculpt_mask();
53
54 enabled_ = state.is_space_v3d() && !state.is_wire() && !res.is_selection() &&
55 !state.is_depth_only_drawing &&
57 (show_curves_cage_ || show_face_set_ || show_mask_);
58
59 if (!enabled_) {
60 /* Not used. But release the data. */
61 sculpt_mask_.init();
62 sculpt_curve_cage_.init();
63 return;
64 }
65
66 float curve_cage_opacity = show_curves_cage_ ? state.overlay.sculpt_curves_cage_opacity : 0.0f;
67 float face_set_opacity = show_face_set_ ? state.overlay.sculpt_mode_face_sets_opacity : 0.0f;
68 float mask_opacity = show_mask_ ? state.overlay.sculpt_mode_mask_opacity : 0.0f;
69
70 {
71 sculpt_mask_.init();
72 sculpt_mask_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
73 sculpt_mask_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
74 {
75 auto &sub = sculpt_mask_.sub("Mesh");
77 state.clipping_plane_count);
78 sub.shader_set(res.shaders->sculpt_mesh.get());
79 sub.push_constant("mask_opacity", mask_opacity);
80 sub.push_constant("face_sets_opacity", face_set_opacity);
81 mesh_ps_ = ⊂
82 }
83 {
84 auto &sub = sculpt_mask_.sub("Curves");
86 state.clipping_plane_count);
87 sub.shader_set(res.shaders->sculpt_curves.get());
88 sub.push_constant("selection_opacity", mask_opacity);
89 curves_ps_ = ⊂
90 }
91 }
92 {
93 auto &pass = sculpt_curve_cage_;
94 pass.init();
96 state.clipping_plane_count);
97 pass.shader_set(res.shaders->sculpt_curves_cage.get());
98 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
99 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
100 pass.push_constant("opacity", curve_cage_opacity);
101 }
102 }
103
104 void object_sync(Manager &manager,
105 const ObjectRef &ob_ref,
106 Resources & /*res*/,
107 const State &state) final
108 {
109 if (!enabled_) {
110 return;
111 }
112
113 switch (ob_ref.object->type) {
114 case OB_MESH:
115 mesh_sync(manager, ob_ref, state);
116 break;
117 case OB_CURVES:
118 curves_sync(manager, ob_ref, state);
119 break;
120 }
121 }
122
123 void curves_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
124 {
126
127 /* As an optimization, draw nothing if everything is selected. */
128 if (show_mask_ && !everything_selected(curves)) {
129 /* Retrieve the location of the texture. */
130 bool is_point_domain;
132 &curves, ".selection", &is_point_domain);
133 if (select_attr_buf) {
134 /* Evaluate curves and their attributes if necessary. */
135 gpu::Batch *geometry = curves_sub_pass_setup(*curves_ps_, state.scene, ob_ref.object);
136 if (*select_attr_buf) {
137 ResourceHandle handle = manager.unique_handle(ob_ref);
138
139 curves_ps_->push_constant("is_point_domain", is_point_domain);
140 curves_ps_->bind_texture("selection_tx", *select_attr_buf);
141 curves_ps_->draw(geometry, handle);
142 }
143 }
144 }
145
146 if (show_curves_cage_) {
147 ResourceHandle handle = manager.unique_handle(ob_ref);
148
149 blender::gpu::Batch *geometry = DRW_curves_batch_cache_get_sculpt_curves_cage(&curves);
150 sculpt_curve_cage_.draw(geometry, handle);
151 }
152 }
153
154 void mesh_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
155 {
156 if (!show_face_set_ && !show_mask_) {
157 /* Nothing to display. */
158 return;
159 }
160
161 const SculptSession *sculpt_session = ob_ref.object->sculpt;
162 if (sculpt_session == nullptr) {
163 return;
164 }
165
167 if (!pbvh) {
168 /* It is possible to have SculptSession without pbvh::Tree. This happens, for example, when
169 * toggling object mode to sculpt then to edit mode. */
170 return;
171 }
172
173 /* Using the original object/geometry is necessary because we skip depsgraph updates in sculpt
174 * mode to improve performance. This means the evaluated mesh doesn't have the latest face set,
175 * visibility, and mask data. */
176 Object *object_orig = DEG_get_original(ob_ref.object);
177 if (!object_orig) {
179 return;
180 }
181
182 switch (pbvh->type()) {
184 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(*object_orig);
185 if (!mesh.attributes().contains(".sculpt_face_set") &&
186 !mesh.attributes().contains(".sculpt_mask"))
187 {
188 return;
189 }
190 break;
191 }
193 const SubdivCCG &subdiv_ccg = *sculpt_session->subdiv_ccg;
194 const Mesh &base_mesh = DRW_object_get_data_for_drawing<Mesh>(*object_orig);
195 if (subdiv_ccg.masks.is_empty() && !base_mesh.attributes().contains(".sculpt_face_set")) {
196 return;
197 }
198 break;
199 }
201 const BMesh &bm = *sculpt_session->bm;
202 if (!CustomData_has_layer_named(&bm.pdata, CD_PROP_FLOAT, ".sculpt_face_set") &&
203 !CustomData_has_layer_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask"))
204 {
205 return;
206 }
207 break;
208 }
209 }
210
211 const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d);
212 if (use_pbvh) {
213 ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
214
215 SculptBatchFeature sculpt_batch_features_ = (show_face_set_ ? SCULPT_BATCH_FACE_SET :
217 (show_mask_ ? SCULPT_BATCH_MASK :
219
220 for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, sculpt_batch_features_)) {
221 mesh_ps_->draw(batch.batch, handle);
222 }
223 }
224 else {
225 ResourceHandle handle = manager.unique_handle(ob_ref);
226
228 gpu::Batch *sculpt_overlays = DRW_mesh_batch_cache_get_sculpt_overlays(mesh);
229 mesh_ps_->draw(sculpt_overlays, handle);
230 }
231 }
232
233 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
234 {
235 if (!enabled_) {
236 return;
237 }
238 GPU_framebuffer_bind(framebuffer);
239 manager.submit(sculpt_curve_cage_, view);
240 }
241
242 void draw_on_render(GPUFrameBuffer *framebuffer, Manager &manager, View &view) final
243 {
244 if (!enabled_) {
245 return;
246 }
247 GPU_framebuffer_bind(framebuffer);
248 manager.submit(sculpt_mask_, view);
249 }
250
251 private:
252 bool everything_selected(const ::Curves &curves_id)
253 {
254 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
255 const VArray<bool> selection = *curves.attributes().lookup_or_default<bool>(
256 ".selection", bke::AttrDomain::Point, true);
257 return selection.is_single() && selection.get_internal_single();
258 }
259};
260
261} // namespace blender::draw::overlay
Low-level operations for curves.
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:2928
A BVH for high poly meshes.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define ELEM(...)
T * DEG_get_original(T *id)
@ CD_PROP_FLOAT
@ OB_MODE_SCULPT
@ OB_MODE_SCULPT_CURVES
@ OB_MESH
@ OB_CURVES
static AppView * view
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
BMesh * bm
bool is_empty() const
Definition BLI_array.hh:253
AttributeSet attributes
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
AttributeAccessor attributes() const
ResourceHandleRange unique_handle(const ObjectRef &ref)
ResourceHandleRange resource_handle_for_sculpt(const ObjectRef &ref)
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:490
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &, const State &state) final
void draw_on_render(GPUFrameBuffer *framebuffer, Manager &manager, View &view) final
void mesh_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
void begin_sync(Resources &res, const State &state) final
void curves_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
Mesh & DRW_object_get_data_for_drawing(const Object &object)
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
@ 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 @064345207361167251075330302113175271221317160336::@113254110077376341056327177062323111323010325277 batch
static ulong state[N]
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
detail::Pass< command::DrawCommandBuf > PassSimple
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, StringRef name, bool *r_is_point_domain)
blender::gpu::Batch * DRW_mesh_batch_cache_get_sculpt_overlays(Mesh &mesh)
struct SculptSession * sculpt
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
blender::Array< float > masks