Blender V4.3
draw_face_sets.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DNA_brush_types.h"
10
11#include "BKE_mesh.hh"
12#include "BKE_pbvh.hh"
13#include "BKE_subdiv_ccg.hh"
14
16#include "BLI_math_base.hh"
17#include "BLI_task.hh"
18
22
24inline namespace draw_face_sets_cc {
25
26constexpr float FACE_SET_BRUSH_MIN_FADE = 0.05f;
27
34
35static void calc_face_centers(const OffsetIndices<int> faces,
36 const Span<int> corner_verts,
37 const Span<float3> vert_positions,
38 const Span<int> face_indices,
39 const MutableSpan<float3> positions)
40{
41 BLI_assert(face_indices.size() == positions.size());
42
43 for (const int i : face_indices.index_range()) {
44 positions[i] = bke::mesh::face_center_calc(vert_positions,
45 corner_verts.slice(faces[face_indices[i]]));
46 }
47}
48
49static void calc_face_normals(const OffsetIndices<int> faces,
50 const Span<int> corner_verts,
51 const Span<float3> vert_positions,
52 const Span<int> face_indices,
53 const MutableSpan<float3> normals)
54{
55 BLI_assert(face_indices.size() == normals.size());
56
57 for (const int i : face_indices.index_range()) {
58 normals[i] = bke::mesh::face_normal_calc(vert_positions,
59 corner_verts.slice(faces[face_indices[i]]));
60 }
61}
62
64 const Span<int> face_indices,
65 const MutableSpan<float> r_factors)
66{
67 BLI_assert(face_indices.size() == r_factors.size());
68
69 const OffsetIndices<int> faces = mesh.faces();
70 const Span<int> corner_verts = mesh.corner_verts();
71
72 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
73 const bke::AttributeAccessor attributes = mesh.attributes();
74 if (const VArray mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point)) {
75 const VArraySpan span(mask);
76 for (const int i : face_indices.index_range()) {
77 const Span<int> face_verts = corner_verts.slice(faces[face_indices[i]]);
78 const float inv_size = math::rcp(float(face_verts.size()));
79 float sum = 0.0f;
80 for (const int vert : face_verts) {
81 sum += span[vert];
82 }
83 r_factors[i] = 1.0f - sum * inv_size;
84 }
85 }
86 else {
87 r_factors.fill(1.0f);
88 }
89
90 if (const VArray hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Point)) {
91 const VArraySpan span(hide_poly);
92 for (const int i : face_indices.index_range()) {
93 if (span[face_indices[i]]) {
94 r_factors[i] = 0.0f;
95 }
96 }
97 }
98}
99
100BLI_NOINLINE static void apply_face_set(const int face_set_id,
101 const Span<int> face_indices,
102 const Span<float> factors,
103 const MutableSpan<int> face_sets)
104{
105 BLI_assert(face_indices.size() == factors.size());
106
107 for (const int i : face_indices.index_range()) {
108 if (factors[i] > FACE_SET_BRUSH_MIN_FADE) {
109 face_sets[face_indices[i]] = face_set_id;
110 }
111 }
112}
113
114static void calc_faces(const Depsgraph &depsgraph,
115 Object &object,
116 const Brush &brush,
117 const float strength,
118 const int face_set_id,
119 Span<float3> positions_eval,
120 const bke::pbvh::MeshNode &node,
121 const Span<int> face_indices,
122 MeshLocalData &tls,
123 const MutableSpan<int> face_sets)
124{
125 SculptSession &ss = *object.sculpt;
126 const StrokeCache &cache = *ss.cache;
127 Mesh &mesh = *static_cast<Mesh *>(object.data);
128 const OffsetIndices<int> faces = mesh.faces();
129 const Span<int> corner_verts = mesh.corner_verts();
130
131 tls.positions.resize(face_indices.size());
132 const MutableSpan<float3> face_centers = tls.positions;
133 calc_face_centers(faces, corner_verts, positions_eval, face_indices, face_centers);
134
135 tls.normals.resize(face_indices.size());
136 const MutableSpan<float3> face_normals = tls.normals;
137 calc_face_normals(faces, corner_verts, positions_eval, face_indices, face_normals);
138
139 tls.factors.resize(face_indices.size());
140 const MutableSpan<float> factors = tls.factors;
141
142 fill_factor_from_hide_and_mask(mesh, face_indices, factors);
143
144 filter_region_clip_factors(ss, face_centers, factors);
145 if (brush.flag & BRUSH_FRONTFACE) {
146 calc_front_face(cache.view_normal_symm, face_normals, factors);
147 }
148
149 tls.distances.resize(face_indices.size());
150 const MutableSpan<float> distances = tls.distances;
151 calc_brush_distances(ss, face_centers, eBrushFalloffShape(brush.falloff_shape), distances);
152 filter_distances_with_radius(cache.radius, distances, factors);
153 apply_hardness_to_distances(cache, distances);
154 calc_brush_strength_factors(cache, brush, distances, factors);
155
156 if (cache.automasking) {
157 const OffsetIndices<int> faces = mesh.faces();
158 const Span<int> corner_verts = mesh.corner_verts();
160 depsgraph, object, faces, corner_verts, *cache.automasking, node, face_indices, factors);
161 }
162
163 calc_brush_texture_factors(ss, brush, face_centers, factors);
164 scale_factors(factors, strength);
165
166 apply_face_set(face_set_id, face_indices, factors, face_sets);
167}
168
169static void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph,
170 Object &object,
171 const Brush &brush,
172 const IndexMask &node_mask)
173{
174 const SculptSession &ss = *object.sculpt;
175 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
176 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
177
179
181 *static_cast<Mesh *>(object.data));
182
185 node_mask.foreach_index(GrainSize(1), [&](const int i) {
186 MeshLocalData &tls = all_tls.local();
187 const Span<int> face_indices = nodes[i].faces();
189 object,
190 brush,
191 ss.cache->bstrength,
193 positions_eval,
194 nodes[i],
195 face_indices,
196 tls,
197 face_sets.span);
198 });
199 pbvh.tag_face_sets_changed(node_mask);
200 face_sets.finish();
201}
202
209
210BLI_NOINLINE static void calc_face_indices_grids(const SubdivCCG &subdiv_ccg,
211 const Span<int> grids,
212 const MutableSpan<int> face_indices)
213{
214 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
215 BLI_assert(grids.size() * key.grid_area == face_indices.size());
216
217 for (const int i : grids.index_range()) {
218 const int start = i * key.grid_area;
219 for (const int offset : IndexRange(key.grid_area)) {
220 face_indices[start + offset] = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grids[i]);
221 }
222 }
223}
224
225static void calc_grids(const Depsgraph &depsgraph,
226 Object &object,
227 const Brush &brush,
228 const float strength,
229 const int face_set_id,
230 const bke::pbvh::GridsNode &node,
231 GridLocalData &tls,
232 const MutableSpan<int> face_sets)
233{
234 SculptSession &ss = *object.sculpt;
235 const StrokeCache &cache = *ss.cache;
236 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
237
238 const Span<int> grids = node.grids();
239 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
240
241 tls.factors.resize(positions.size());
242 const MutableSpan<float> factors = tls.factors;
244 filter_region_clip_factors(ss, positions, factors);
245 if (brush.flag & BRUSH_FRONTFACE) {
246 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
247 }
248
249 tls.distances.resize(positions.size());
250 const MutableSpan<float> distances = tls.distances;
251 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
252 filter_distances_with_radius(cache.radius, distances, factors);
253 apply_hardness_to_distances(cache, distances);
254 calc_brush_strength_factors(cache, brush, distances, factors);
255
256 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
257
258 calc_brush_texture_factors(ss, brush, positions, factors);
259 scale_factors(factors, strength);
260
261 tls.face_indices.resize(positions.size());
262 MutableSpan<int> face_indices = tls.face_indices;
263
264 calc_face_indices_grids(subdiv_ccg, grids, face_indices);
265 apply_face_set(face_set_id, face_indices, factors, face_sets);
266}
267
268static void do_draw_face_sets_brush_grids(const Depsgraph &depsgraph,
269 Object &object,
270 const Brush &brush,
271 const IndexMask &node_mask)
272{
273 SculptSession &ss = *object.sculpt;
274 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
275
277
279 *static_cast<Mesh *>(object.data));
280
283 node_mask.foreach_index(GrainSize(1), [&](const int i) {
284 GridLocalData &tls = all_tls.local();
286 object,
287 brush,
288 ss.cache->bstrength,
290 nodes[i],
291 tls,
292 face_sets.span);
293 });
294 pbvh.tag_face_sets_changed(node_mask);
295 face_sets.finish();
296}
302
304 const Set<BMFace *, 0L> &faces,
305 const MutableSpan<float> r_factors)
306{
307 BLI_assert(faces.size() == r_factors.size());
308
309 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
310 const int mask_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
311 int i = 0;
312 for (BMFace *f : faces) {
314 r_factors[i] = 0.0f;
315 continue;
316 }
317 if (mask_offset == -1) {
318 r_factors[i] = 1.0f;
319 continue;
320 }
321
322 const BMLoop *l_iter = f->l_first = BM_FACE_FIRST_LOOP(f);
323 int total_verts = 0;
324 float sum = 0.0f;
325 do {
326 BMVert *vert = l_iter->v;
327 sum += BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
328 total_verts++;
329 } while ((l_iter = l_iter->next) != f->l_first);
330 r_factors[i] = 1.0f - sum * math::rcp(float(total_verts));
331 i++;
332 }
333}
334
335static void calc_face_centers(const Set<BMFace *, 0L> &faces, const MutableSpan<float3> centers)
336{
337 BLI_assert(faces.size() == centers.size());
338
339 int i = 0;
340 for (const BMFace *f : faces) {
341 float3 face_center;
342 BM_face_calc_center_median(f, face_center);
343
344 centers[i] = face_center;
345 i++;
346 }
347}
348
349BLI_NOINLINE static void apply_face_set(const int face_set_id,
350 const Set<BMFace *, 0> &faces,
351 const MutableSpan<float> factors,
352 const int cd_offset)
353{
354 int i = 0;
355 for (BMFace *face : faces) {
356 if (factors[i] > FACE_SET_BRUSH_MIN_FADE) {
357 BM_ELEM_CD_SET_INT(face, cd_offset, face_set_id);
358 }
359 i++;
360 }
361}
362
363static void calc_bmesh(Object &object,
364 const Brush &brush,
365 const float strength,
366 const int face_set_id,
368 BMeshLocalData &tls,
369 const int cd_offset)
370{
371 SculptSession &ss = *object.sculpt;
372 const StrokeCache &cache = *ss.cache;
373
374 const Set<BMFace *, 0> &faces = BKE_pbvh_bmesh_node_faces(&node);
375 tls.positions.resize(faces.size());
376 const MutableSpan<float3> positions = tls.positions;
377 calc_face_centers(faces, positions);
378
379 tls.factors.resize(faces.size());
380 const MutableSpan<float> factors = tls.factors;
381 fill_factor_from_hide_and_mask(*ss.bm, faces, factors);
382 filter_region_clip_factors(ss, positions, factors);
383 if (brush.flag & BRUSH_FRONTFACE) {
384 calc_front_face(cache.view_normal_symm, faces, factors);
385 }
386
387 tls.distances.resize(faces.size());
388 const MutableSpan<float> distances = tls.distances;
389 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
390 filter_distances_with_radius(cache.radius, distances, factors);
391 apply_hardness_to_distances(cache, distances);
392 calc_brush_strength_factors(cache, brush, distances, factors);
393
394 calc_brush_texture_factors(ss, brush, positions, factors);
395 scale_factors(factors, strength);
396
397 apply_face_set(face_set_id, faces, factors, cd_offset);
398}
399
400static void do_draw_face_sets_brush_bmesh(const Depsgraph &depsgraph,
401 Object &object,
402 const Brush &brush,
403 const IndexMask &node_mask)
404{
405 SculptSession &ss = *object.sculpt;
406 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
407
409
410 const int cd_offset = face_set::ensure_face_sets_bmesh(object);
411
414 node_mask.foreach_index(GrainSize(1), [&](const int i) {
415 BMeshLocalData &tls = all_tls.local();
417 object, brush, ss.cache->bstrength, ss.cache->paint_face_set, nodes[i], tls, cd_offset);
418 });
419 pbvh.tag_face_sets_changed(node_mask);
420}
421
422} // namespace draw_face_sets_cc
423
424void do_draw_face_sets_brush(const Depsgraph &depsgraph,
425 const Sculpt &sd,
426 Object &object,
427 const IndexMask &node_mask)
428{
429 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
430
431 switch (bke::object::pbvh_get(object)->type()) {
433 do_draw_face_sets_brush_mesh(depsgraph, object, brush, node_mask);
434 break;
436 do_draw_face_sets_brush_grids(depsgraph, object, brush, node_mask);
437 break;
439 do_draw_face_sets_brush_bmesh(depsgraph, object, brush, node_mask);
440 break;
441 }
442}
443} // namespace blender::ed::sculpt_paint
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
const blender::Set< BMFace *, 0 > & BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG &subdiv_ccg, const int grid_index)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_NOINLINE
@ BRUSH_FRONTFACE
eBrushFalloffShape
@ CD_PROP_FLOAT
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
#define BM_ELEM_CD_SET_INT(ele, offset, f)
@ BM_ELEM_HIDDEN
#define BM_FACE_FIRST_LOOP(p)
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
static T sum(const btAlignedObjectArray< T > &items)
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void resize(const int64_t new_size)
Span< NodeT > nodes() const
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:579
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
static char faces[256]
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
void calc_face_factors(const Depsgraph &depsgraph, const Object &object, OffsetIndices< int > faces, Span< int > corner_verts, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > face_indices, MutableSpan< float > factors)
static void calc_face_centers(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< float3 > vert_positions, const Span< int > face_indices, const MutableSpan< float3 > positions)
static void calc_face_normals(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< float3 > vert_positions, const Span< int > face_indices, const MutableSpan< float3 > normals)
static void calc_bmesh(Object &object, const Brush &brush, const float strength, const int face_set_id, bke::pbvh::BMeshNode &node, BMeshLocalData &tls, const int cd_offset)
static void do_draw_face_sets_brush_bmesh(const Depsgraph &depsgraph, Object &object, const Brush &brush, const IndexMask &node_mask)
static BLI_NOINLINE void apply_face_set(const int face_set_id, const Span< int > face_indices, const Span< float > factors, const MutableSpan< int > face_sets)
static void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph, Object &object, const Brush &brush, const IndexMask &node_mask)
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
static BLI_NOINLINE void calc_face_indices_grids(const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< int > face_indices)
static void calc_grids(const Depsgraph &depsgraph, Object &object, const Brush &brush, const float strength, const int face_set_id, const bke::pbvh::GridsNode &node, GridLocalData &tls, const MutableSpan< int > face_sets)
static void calc_faces(const Depsgraph &depsgraph, Object &object, const Brush &brush, const float strength, const int face_set_id, Span< float3 > positions_eval, const bke::pbvh::MeshNode &node, const Span< int > face_indices, MeshLocalData &tls, const MutableSpan< int > face_sets)
static void do_draw_face_sets_brush_grids(const Depsgraph &depsgraph, Object &object, const Brush &brush, const IndexMask &node_mask)
bke::SpanAttributeWriter< int > ensure_face_sets_mesh(Mesh &mesh)
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:6862
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6772
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6639
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
void do_draw_face_sets_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6581
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert_indices, MutableSpan< float > factors)
Definition sculpt.cc:6898
T rcp(const T &a)
struct BMVert * v
struct BMLoop * next
CustomData vdata
char falloff_shape
int grid_area
Definition BKE_ccg.hh:35
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
std::unique_ptr< auto_mask::Cache > automasking