Blender V5.0
draw_sculpt.cc
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#include "draw_sculpt.hh"
10
11#include "DNA_mesh_types.h"
12#include "DNA_scene_types.h"
13#include "draw_attributes.hh"
15#include "draw_view.hh"
16
17#include "BKE_attribute.hh"
19#include "BKE_customdata.hh"
20#include "BKE_material.hh"
21#include "BKE_object.hh"
22#include "BKE_paint.hh"
23
24#include "BLI_math_matrix.hh"
25
26#include "bmesh_class.hh"
27
28#include "DRW_pbvh.hh"
29#include "DRW_render.hh"
30
31namespace blender::draw {
32
34{
35 static float3 colors[9] = {
36 {1.0f, 0.2f, 0.2f},
37 {0.2f, 1.0f, 0.2f},
38 {0.2f, 0.2f, 1.0f},
39 {1.0f, 1.0f, 0.2f},
40 {0.2f, 1.0f, 1.0f},
41 {1.0f, 0.2f, 1.0f},
42 {1.0f, 0.7f, 0.2f},
43 {0.2f, 1.0f, 0.7f},
44 {0.7f, 0.2f, 1.0f},
45 };
46
47 return colors[debug_index % 9];
48}
49
51 const bool use_wire,
53{
54 /* pbvh::Tree should always exist for non-empty meshes, created by depsgraph eval. */
56 nullptr;
57 if (!pbvh) {
58 return {};
59 }
60
61 /* TODO(Miguel Pozo): Don't use global context. */
62 const DRWContext *drwctx = DRW_context_get();
63 RegionView3D *rv3d = drwctx->rv3d;
64 const bool navigating = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
65
66 Paint *paint = nullptr;
67 if (drwctx->evil_C != nullptr) {
69 }
70
71 /* TODO: take into account partial redraw for clipping planes. */
72 /* Frustum planes to show only visible pbvh::Tree nodes. */
73 std::array<float4, 6> draw_frustum_planes = View::default_get().frustum_planes_get();
74 /* Transform clipping planes to object space. Transforming a plane with a
75 * 4x4 matrix is done by multiplying with the transpose inverse.
76 * The inverse cancels out here since we transform by inverse(obmat). */
77 float4x4 tmat = math::transpose(ob->object_to_world());
78 for (int i : IndexRange(draw_frustum_planes.size())) {
79 draw_frustum_planes[i] = tmat * draw_frustum_planes[i];
80 }
81
82 /* Fast mode to show low poly multires while navigating. */
83 bool fast_mode = false;
84 if (paint && (paint->flags & PAINT_FAST_NAVIGATE)) {
85 fast_mode = navigating;
86 }
87
88 /* Update draw buffers only for visible nodes while painting.
89 * But do update them otherwise so navigating stays smooth. */
90 bool update_only_visible = rv3d && !(rv3d->rflag & RV3D_PAINTING);
91 if (paint && (paint->flags & PAINT_SCULPT_DELAY_UPDATES)) {
92 update_only_visible = true;
93 }
94
96
97 pbvh::DrawCache &draw_data = pbvh::ensure_draw_data(pbvh->draw_data);
98
99 IndexMaskMemory memory;
100 const IndexMask visible_nodes = bke::pbvh::search_nodes(
101 *pbvh, memory, [&](const bke::pbvh::Node &node) {
102 return !BKE_pbvh_node_fully_hidden_get(node) &&
103 bke::pbvh::node_frustum_contain_aabb(node, draw_frustum_planes);
104 });
105
106 const IndexMask nodes_to_update = update_only_visible ? visible_nodes :
108
109 Span<gpu::Batch *> batches;
110 if (use_wire) {
111 batches = draw_data.ensure_lines_batches(*ob, {{}, fast_mode}, nodes_to_update);
112 }
113 else {
114 batches = draw_data.ensure_tris_batches(*ob, {attrs, fast_mode}, nodes_to_update);
115 }
116
117 const Span<int> material_indices = draw_data.ensure_material_indices(*ob);
118
119 const int max_material = std::max(0, BKE_object_material_count_eval(ob) - 1);
120 Vector<SculptBatch> result_batches(visible_nodes.size());
121 visible_nodes.foreach_index([&](const int i, const int pos) {
122 result_batches[pos] = {};
123 result_batches[pos].batch = batches[i];
124 result_batches[pos].material_slot = material_indices.is_empty() ?
125 0 :
126 std::clamp(material_indices[i], 0, max_material);
127 result_batches[pos].debug_index = pos;
128 });
129
130 return result_batches;
131}
132
133static const CustomData *get_cdata(const BMesh &bm, const bke::AttrDomain domain)
134{
135 switch (domain) {
137 return &bm.vdata;
139 return &bm.ldata;
141 return &bm.pdata;
142 default:
143 return nullptr;
144 }
145}
146
147static bool bmesh_attribute_exists(const BMesh &bm,
148 const bke::AttributeMetaData &meta_data,
149 const StringRef name)
150{
151 const CustomData *cdata = get_cdata(bm, meta_data.domain);
152 return cdata && CustomData_get_offset_named(
153 cdata, *bke::attr_type_to_custom_data_type(meta_data.data_type), name) != -1;
154}
155
157{
159
162 if (features & SCULPT_BATCH_MASK) {
164 }
165 if (features & SCULPT_BATCH_FACE_SET) {
167 }
168
169 const Mesh *mesh = BKE_object_get_original_mesh(ob);
170 const bke::AttributeAccessor attributes = mesh->attributes();
171 const SculptSession &ss = *ob->sculpt;
172
173 /* If Dyntopo is enabled, the source of truth for an attribute existing or not is the BMesh, not
174 * the Mesh. */
175 if (features & SCULPT_BATCH_VERTEX_COLOR) {
176 if (const char *name = mesh->active_color_attribute) {
177 if (const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
178 name))
179 {
180 if (ss.bm) {
181 if (bmesh_attribute_exists(*ss.bm, *meta_data, name)) {
183 }
184 }
185 else {
187 }
188 }
189 }
190 }
191
192 if (features & SCULPT_BATCH_UV) {
193 const CustomData *corner_data = ss.bm ? &ss.bm->ldata : &mesh->corner_data;
194 if (const char *name = CustomData_get_active_layer_name(corner_data, CD_PROP_FLOAT2)) {
196 }
197 }
198
199 return sculpt_batches_get_ex(ob, features & SCULPT_BATCH_WIREFRAME, attrs);
200}
201
204{
205 BLI_assert(ob->type == OB_MESH);
207
208 VectorSet<std::string> draw_attrs;
209 DRW_MeshCDMask cd_needed;
210 DRW_mesh_get_attributes(*ob, mesh, materials, &draw_attrs, &cd_needed);
211
213
216
217 for (const StringRef name : draw_attrs) {
219 }
220
221 /* UV maps are not in attribute requests. */
222 for (uint i = 0; i < 32; i++) {
223 if (cd_needed.uv & (1 << i)) {
225 CustomDataLayer *layer = layer_i != -1 ? mesh.corner_data.layers + layer_i : nullptr;
226 if (layer) {
227 attrs.append(pbvh::GenericRequest(layer->name));
228 }
229 }
230 }
231
232 return sculpt_batches_get_ex(ob, false, attrs);
233}
234
235} // namespace blender::draw
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_layer_index_n(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
General operations, lookup, etc. for materials.
int BKE_object_material_count_eval(const Object *ob)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_original_mesh(const Object *object)
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:476
bool BKE_pbvh_node_fully_hidden_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1723
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
@ CD_PROP_FLOAT2
@ OB_MESH
@ PAINT_SCULPT_DELAY_UPDATES
@ PAINT_FAST_NAVIGATE
@ RV3D_PAINTING
@ RV3D_NAVIGATING
T & DRW_object_get_data_for_drawing(const Object &object)
BMesh * bm
AttributeSet attributes
constexpr bool is_empty() const
Definition BLI_span.hh:260
void append(const T &value)
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
static View & default_get()
Definition draw_view.cc:317
std::array< float4, 6 > frustum_planes_get(int view_id=0)
Definition draw_view.cc:327
virtual Span< int > ensure_material_indices(const Object &object)=0
virtual Span< gpu::Batch * > ensure_lines_batches(const Object &object, const ViewportRequest &request, const IndexMask &nodes_to_update)=0
virtual Span< gpu::Batch * > ensure_tris_batches(const Object &object, const ViewportRequest &request, const IndexMask &nodes_to_update)=0
void foreach_index(Fn &&fn) const
Utilities for rendering attributes.
const DRWContext * DRW_context_get()
uint pos
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2663
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2628
void update_normals_from_eval(Object &object_eval, Tree &pbvh)
Definition pbvh.cc:1264
bool node_frustum_contain_aabb(const Node &node, Span< float4 > frustum_planes)
Definition pbvh.cc:2520
std::optional< eCustomDataType > attr_type_to_custom_data_type(AttrType attr_type)
DrawCache & ensure_draw_data(std::unique_ptr< bke::pbvh::DrawCache > &ptr)
Definition draw_pbvh.cc:250
std::string GenericRequest
Definition DRW_pbvh.hh:39
Vector< SculptBatch > sculpt_batches_get(const Object *ob, SculptBatchFeature features)
static Vector< SculptBatch > sculpt_batches_get_ex(const Object *ob, const bool use_wire, const Span< pbvh::AttributeRequest > attrs)
@ SCULPT_BATCH_VERTEX_COLOR
static bool bmesh_attribute_exists(const BMesh &bm, const bke::AttributeMetaData &meta_data, const StringRef name)
void DRW_mesh_get_attributes(const Object &object, const Mesh &mesh, const Span< const GPUMaterial * > materials, VectorSet< std::string > *r_attrs, DRW_MeshCDMask *r_cd_needed)
Vector< SculptBatch > sculpt_batches_per_material_get(const Object *ob, Span< const GPUMaterial * > materials)
static const CustomData * get_cdata(const BMesh &bm, const bke::AttrDomain domain)
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
const char * name
CustomData ldata
CustomDataLayer * layers
RegionView3D * rv3d
const bContext * evil_C
CustomData corner_data
char * active_color_attribute
struct SculptSession * sculpt
i
Definition text_draw.cc:230