Blender V4.5
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"
18#include "BKE_customdata.hh"
19#include "BKE_material.hh"
20#include "BKE_object.hh"
21#include "BKE_paint.hh"
22
23#include "BLI_math_matrix.hh"
24
25#include "bmesh_class.hh"
26
27#include "DRW_pbvh.hh"
28#include "DRW_render.hh"
29
30namespace blender::draw {
31
33{
34 static float3 colors[9] = {
35 {1.0f, 0.2f, 0.2f},
36 {0.2f, 1.0f, 0.2f},
37 {0.2f, 0.2f, 1.0f},
38 {1.0f, 1.0f, 0.2f},
39 {0.2f, 1.0f, 1.0f},
40 {1.0f, 0.2f, 1.0f},
41 {1.0f, 0.7f, 0.2f},
42 {0.2f, 1.0f, 0.7f},
43 {0.7f, 0.2f, 1.0f},
44 };
45
46 return colors[debug_index % 9];
47}
48
50 const bool use_wire,
52{
53 /* pbvh::Tree should always exist for non-empty meshes, created by depsgraph eval. */
55 nullptr;
56 if (!pbvh) {
57 return {};
58 }
59
60 /* TODO(Miguel Pozo): Don't use global context. */
61 const DRWContext *drwctx = DRW_context_get();
62 RegionView3D *rv3d = drwctx->rv3d;
63 const bool navigating = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
64
65 Paint *paint = nullptr;
66 if (drwctx->evil_C != nullptr) {
68 }
69
70 /* TODO: take into account partial redraw for clipping planes. */
71 /* Frustum planes to show only visible pbvh::Tree nodes. */
72 std::array<float4, 6> draw_frustum_planes = View::default_get().frustum_planes_get();
73 /* Transform clipping planes to object space. Transforming a plane with a
74 * 4x4 matrix is done by multiplying with the transpose inverse.
75 * The inverse cancels out here since we transform by inverse(obmat). */
76 float4x4 tmat = math::transpose(ob->object_to_world());
77 for (int i : IndexRange(draw_frustum_planes.size())) {
78 draw_frustum_planes[i] = tmat * draw_frustum_planes[i];
79 }
80
81 /* Fast mode to show low poly multires while navigating. */
82 bool fast_mode = false;
83 if (paint && (paint->flags & PAINT_FAST_NAVIGATE)) {
84 fast_mode = navigating;
85 }
86
87 /* Update draw buffers only for visible nodes while painting.
88 * But do update them otherwise so navigating stays smooth. */
89 bool update_only_visible = rv3d && !(rv3d->rflag & RV3D_PAINTING);
90 if (paint && (paint->flags & PAINT_SCULPT_DELAY_UPDATES)) {
91 update_only_visible = true;
92 }
93
95
96 pbvh::DrawCache &draw_data = pbvh::ensure_draw_data(pbvh->draw_data);
97
98 IndexMaskMemory memory;
99 const IndexMask visible_nodes = bke::pbvh::search_nodes(
100 *pbvh, memory, [&](const bke::pbvh::Node &node) {
101 return !BKE_pbvh_node_fully_hidden_get(node) &&
102 bke::pbvh::node_frustum_contain_aabb(node, draw_frustum_planes);
103 });
104
105 const IndexMask nodes_to_update = update_only_visible ? visible_nodes :
107
108 Span<gpu::Batch *> batches;
109 if (use_wire) {
110 batches = draw_data.ensure_lines_batches(*ob, {{}, fast_mode}, nodes_to_update);
111 }
112 else {
113 batches = draw_data.ensure_tris_batches(*ob, {attrs, fast_mode}, nodes_to_update);
114 }
115
116 const Span<int> material_indices = draw_data.ensure_material_indices(*ob);
117
118 const int max_material = std::max(0, BKE_object_material_count_eval(ob) - 1);
119 Vector<SculptBatch> result_batches(visible_nodes.size());
120 visible_nodes.foreach_index([&](const int i, const int pos) {
121 result_batches[pos] = {};
122 result_batches[pos].batch = batches[i];
123 result_batches[pos].material_slot = material_indices.is_empty() ?
124 0 :
125 std::clamp(material_indices[i], 0, max_material);
126 result_batches[pos].debug_index = pos;
127 });
128
129 return result_batches;
130}
131
132static const CustomData *get_cdata(const BMesh &bm, const bke::AttrDomain domain)
133{
134 switch (domain) {
136 return &bm.vdata;
138 return &bm.ldata;
140 return &bm.pdata;
141 default:
142 return nullptr;
143 }
144}
145
146static bool bmesh_attribute_exists(const BMesh &bm,
147 const bke::AttributeMetaData &meta_data,
148 const StringRef name)
149{
150 const CustomData *cdata = get_cdata(bm, meta_data.domain);
151 return cdata && CustomData_get_offset_named(cdata, meta_data.data_type, name) != -1;
152}
153
155{
157
160 if (features & SCULPT_BATCH_MASK) {
162 }
163 if (features & SCULPT_BATCH_FACE_SET) {
165 }
166
167 const Mesh *mesh = BKE_object_get_original_mesh(ob);
168 const bke::AttributeAccessor attributes = mesh->attributes();
169 const SculptSession &ss = *ob->sculpt;
170
171 /* If Dyntopo is enabled, the source of truth for an attribute existing or not is the BMesh, not
172 * the Mesh. */
173 if (features & SCULPT_BATCH_VERTEX_COLOR) {
174 if (const char *name = mesh->active_color_attribute) {
175 if (const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
176 name))
177 {
178 if (ss.bm) {
179 if (bmesh_attribute_exists(*ss.bm, *meta_data, name)) {
180 attrs.append(pbvh::GenericRequest(name));
181 }
182 }
183 else {
184 attrs.append(pbvh::GenericRequest(name));
185 }
186 }
187 }
188 }
189
190 if (features & SCULPT_BATCH_UV) {
191 const CustomData *corner_data = ss.bm ? &ss.bm->ldata : &mesh->corner_data;
192 if (const char *name = CustomData_get_active_layer_name(corner_data, CD_PROP_FLOAT2)) {
193 attrs.append(pbvh::GenericRequest(name));
194 }
195 }
196
197 return sculpt_batches_get_ex(ob, features & SCULPT_BATCH_WIREFRAME, attrs);
198}
199
202{
203 BLI_assert(ob->type == OB_MESH);
205
206 VectorSet<std::string> draw_attrs;
207 DRW_MeshCDMask cd_needed;
208 DRW_mesh_get_attributes(*ob, mesh, materials, &draw_attrs, &cd_needed);
209
211
214
215 for (const StringRef name : draw_attrs) {
216 attrs.append(pbvh::GenericRequest(name));
217 }
218
219 /* UV maps are not in attribute requests. */
220 for (uint i = 0; i < 32; i++) {
221 if (cd_needed.uv & (1 << i)) {
223 CustomDataLayer *layer = layer_i != -1 ? mesh.corner_data.layers + layer_i : nullptr;
224 if (layer) {
225 attrs.append(pbvh::GenericRequest(layer->name));
226 }
227 }
228 }
229
230 return sculpt_batches_get_ex(ob, false, attrs);
231}
232
233} // 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:467
bool BKE_pbvh_node_fully_hidden_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1539
#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
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()
Mesh & DRW_object_get_data_for_drawing(const Object &object)
uint pos
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2579
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
void update_normals_from_eval(Object &object_eval, Tree &pbvh)
Definition pbvh.cc:1080
bool node_frustum_contain_aabb(const Node &node, Span< float4 > frustum_planes)
Definition pbvh.cc:2336
DrawCache & ensure_draw_data(std::unique_ptr< bke::pbvh::DrawCache > &ptr)
Definition draw_pbvh.cc:249
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
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