Blender V5.0
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_paint_bvh.hh"
13#include "BKE_subdiv_ccg.hh"
14
16#include "BLI_math_base.hh"
17#include "BLI_task.hh"
18
22
23#include "ED_sculpt.hh"
24
25#include "bmesh.hh"
26
28inline namespace draw_face_sets_cc {
29
30constexpr float FACE_SET_BRUSH_MIN_FADE = 0.05f;
31
38
40 const Span<int> corner_verts,
41 const Span<float3> vert_positions,
42 const Span<int> face_indices,
43 const MutableSpan<float3> positions)
44{
45 BLI_assert(face_indices.size() == positions.size());
46
47 for (const int i : face_indices.index_range()) {
48 positions[i] = bke::mesh::face_center_calc(vert_positions,
49 corner_verts.slice(faces[face_indices[i]]));
50 }
51}
52
54 const Span<int> corner_verts,
55 const Span<float3> vert_positions,
56 const Span<int> face_indices,
58{
59 BLI_assert(face_indices.size() == normals.size());
60
61 for (const int i : face_indices.index_range()) {
62 normals[i] = bke::mesh::face_normal_calc(vert_positions,
63 corner_verts.slice(faces[face_indices[i]]));
64 }
65}
66
68 const Span<int> face_indices,
69 const MutableSpan<float> r_factors)
70{
71 BLI_assert(face_indices.size() == r_factors.size());
72
73 const OffsetIndices<int> faces = mesh.faces();
74 const Span<int> corner_verts = mesh.corner_verts();
75
76 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
77 const bke::AttributeAccessor attributes = mesh.attributes();
78 if (const VArray mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point)) {
79 const VArraySpan span(mask);
80 for (const int i : face_indices.index_range()) {
81 const Span<int> face_verts = corner_verts.slice(faces[face_indices[i]]);
82 const float inv_size = math::rcp(float(face_verts.size()));
83 float sum = 0.0f;
84 for (const int vert : face_verts) {
85 sum += span[vert];
86 }
87 r_factors[i] = 1.0f - sum * inv_size;
88 }
89 }
90 else {
91 r_factors.fill(1.0f);
92 }
93
94 if (const VArray hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face)) {
95 const VArraySpan span(hide_poly);
96 for (const int i : face_indices.index_range()) {
97 if (span[face_indices[i]]) {
98 r_factors[i] = 0.0f;
99 }
100 }
101 }
102}
103
104BLI_NOINLINE static void apply_face_set(const int face_set_id,
105 const Span<int> face_indices,
106 const Span<float> factors,
107 const MutableSpan<int> face_sets)
108{
109 BLI_assert(face_indices.size() == factors.size());
110
111 for (const int i : face_indices.index_range()) {
112 if (factors[i] > FACE_SET_BRUSH_MIN_FADE) {
113 face_sets[face_indices[i]] = face_set_id;
114 }
115 }
116}
117
118static void calc_faces(const Depsgraph &depsgraph,
119 Object &object,
120 const Brush &brush,
121 const float strength,
122 const int face_set_id,
123 Span<float3> positions_eval,
124 const bke::pbvh::MeshNode &node,
125 const Span<int> face_indices,
126 MeshLocalData &tls,
127 const MutableSpan<int> face_sets)
128{
129 SculptSession &ss = *object.sculpt;
130 const StrokeCache &cache = *ss.cache;
131 Mesh &mesh = *static_cast<Mesh *>(object.data);
132 const OffsetIndices<int> faces = mesh.faces();
133 const Span<int> corner_verts = mesh.corner_verts();
134
135 tls.positions.resize(face_indices.size());
136 const MutableSpan<float3> face_centers = tls.positions;
137 calc_face_centers(faces, corner_verts, positions_eval, face_indices, face_centers);
138
139 tls.normals.resize(face_indices.size());
140 const MutableSpan<float3> face_normals = tls.normals;
141 calc_face_normals(faces, corner_verts, positions_eval, face_indices, face_normals);
142
143 tls.factors.resize(face_indices.size());
144 const MutableSpan<float> factors = tls.factors;
145
146 fill_factor_from_hide_and_mask(mesh, face_indices, factors);
147
148 filter_region_clip_factors(ss, face_centers, factors);
149 if (brush.flag & BRUSH_FRONTFACE) {
150 calc_front_face(cache.view_normal_symm, face_normals, factors);
151 }
152
153 tls.distances.resize(face_indices.size());
154 const MutableSpan<float> distances = tls.distances;
155 calc_brush_distances(ss, face_centers, eBrushFalloffShape(brush.falloff_shape), distances);
156 filter_distances_with_radius(cache.radius, distances, factors);
157 apply_hardness_to_distances(cache, distances);
158 calc_brush_strength_factors(cache, brush, distances, factors);
159
160 if (cache.automasking) {
161 const OffsetIndices<int> faces = mesh.faces();
162 const Span<int> corner_verts = mesh.corner_verts();
164 depsgraph, object, faces, corner_verts, *cache.automasking, node, face_indices, factors);
165 }
166
167 calc_brush_texture_factors(ss, brush, face_centers, factors);
168 scale_factors(factors, strength);
169
170 apply_face_set(face_set_id, face_indices, factors, face_sets);
171}
172
173static void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph,
174 Object &object,
175 const Brush &brush,
176 const IndexMask &node_mask)
177{
178 const SculptSession &ss = *object.sculpt;
179 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
180 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
181
183
185 *static_cast<Mesh *>(object.data));
186
189 node_mask.foreach_index(GrainSize(1), [&](const int i) {
190 MeshLocalData &tls = all_tls.local();
191 const Span<int> face_indices = nodes[i].faces();
193 object,
194 brush,
195 ss.cache->bstrength,
197 positions_eval,
198 nodes[i],
199 face_indices,
200 tls,
201 face_sets.span);
202 });
203 pbvh.tag_face_sets_changed(node_mask);
204 face_sets.finish();
205}
206
213
214BLI_NOINLINE static void calc_face_indices_grids(const SubdivCCG &subdiv_ccg,
215 const Span<int> grids,
216 const MutableSpan<int> face_indices)
217{
218 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
219 BLI_assert(grids.size() * key.grid_area == face_indices.size());
220
221 for (const int i : grids.index_range()) {
222 const int start = i * key.grid_area;
223 for (const int offset : IndexRange(key.grid_area)) {
224 face_indices[start + offset] = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grids[i]);
225 }
226 }
227}
228
229static void calc_grids(const Depsgraph &depsgraph,
230 Object &object,
231 const Brush &brush,
232 const float strength,
233 const int face_set_id,
234 const bke::pbvh::GridsNode &node,
235 GridLocalData &tls,
236 const MutableSpan<int> face_sets)
237{
238 SculptSession &ss = *object.sculpt;
239 const StrokeCache &cache = *ss.cache;
240 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
241
242 const Span<int> grids = node.grids();
243 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
244
245 tls.factors.resize(positions.size());
246 const MutableSpan<float> factors = tls.factors;
248 filter_region_clip_factors(ss, positions, factors);
249 if (brush.flag & BRUSH_FRONTFACE) {
250 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
251 }
252
253 tls.distances.resize(positions.size());
254 const MutableSpan<float> distances = tls.distances;
255 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
256 filter_distances_with_radius(cache.radius, distances, factors);
257 apply_hardness_to_distances(cache, distances);
258 calc_brush_strength_factors(cache, brush, distances, factors);
259
260 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
261
262 calc_brush_texture_factors(ss, brush, positions, factors);
263 scale_factors(factors, strength);
264
265 tls.face_indices.resize(positions.size());
266 MutableSpan<int> face_indices = tls.face_indices;
267
268 calc_face_indices_grids(subdiv_ccg, grids, face_indices);
269 apply_face_set(face_set_id, face_indices, factors, face_sets);
270}
271
272static void do_draw_face_sets_brush_grids(const Depsgraph &depsgraph,
273 Object &object,
274 const Brush &brush,
275 const IndexMask &node_mask)
276{
277 SculptSession &ss = *object.sculpt;
278 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
279
281
283 *static_cast<Mesh *>(object.data));
284
287 node_mask.foreach_index(GrainSize(1), [&](const int i) {
288 GridLocalData &tls = all_tls.local();
290 object,
291 brush,
292 ss.cache->bstrength,
294 nodes[i],
295 tls,
296 face_sets.span);
297 });
298 pbvh.tag_face_sets_changed(node_mask);
299 face_sets.finish();
300}
306
309 const MutableSpan<float> r_factors)
310{
311 BLI_assert(faces.size() == r_factors.size());
312
313 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
314 const int mask_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
315 int i = 0;
316 for (BMFace *f : faces) {
318 r_factors[i] = 0.0f;
319 continue;
320 }
321 if (mask_offset == -1) {
322 r_factors[i] = 1.0f;
323 continue;
324 }
325
326 const BMLoop *l_iter = f->l_first = BM_FACE_FIRST_LOOP(f);
327 int total_verts = 0;
328 float sum = 0.0f;
329 do {
330 BMVert *vert = l_iter->v;
331 sum += BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
332 total_verts++;
333 } while ((l_iter = l_iter->next) != f->l_first);
334 r_factors[i] = 1.0f - sum * math::rcp(float(total_verts));
335 i++;
336 }
337}
338
340{
341 BLI_assert(faces.size() == centers.size());
342
343 int i = 0;
344 for (const BMFace *f : faces) {
345 float3 face_center;
346 BM_face_calc_center_median(f, face_center);
347
348 centers[i] = face_center;
349 i++;
350 }
351}
352
353BLI_NOINLINE static void apply_face_set(const int face_set_id,
354 const Set<BMFace *, 0> &faces,
355 const MutableSpan<float> factors,
356 const int cd_offset)
357{
358 int i = 0;
359 for (BMFace *face : faces) {
360 if (factors[i] > FACE_SET_BRUSH_MIN_FADE) {
361 BM_ELEM_CD_SET_INT(face, cd_offset, face_set_id);
362 }
363 i++;
364 }
365}
366
367static void calc_bmesh(Object &object,
368 const Brush &brush,
369 const float strength,
370 const int face_set_id,
372 BMeshLocalData &tls,
373 const int cd_offset)
374{
375 SculptSession &ss = *object.sculpt;
376 const StrokeCache &cache = *ss.cache;
377
379 tls.positions.resize(faces.size());
380 const MutableSpan<float3> positions = tls.positions;
381 calc_face_centers(faces, positions);
382
383 tls.factors.resize(faces.size());
384 const MutableSpan<float> factors = tls.factors;
386 filter_region_clip_factors(ss, positions, factors);
387 if (brush.flag & BRUSH_FRONTFACE) {
388 calc_front_face(cache.view_normal_symm, faces, factors);
389 }
390
391 tls.distances.resize(faces.size());
392 const MutableSpan<float> distances = tls.distances;
393 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
394 filter_distances_with_radius(cache.radius, distances, factors);
395 apply_hardness_to_distances(cache, distances);
396 calc_brush_strength_factors(cache, brush, distances, factors);
397
398 calc_brush_texture_factors(ss, brush, positions, factors);
399 scale_factors(factors, strength);
400
401 apply_face_set(face_set_id, faces, factors, cd_offset);
402}
403
404static void do_draw_face_sets_brush_bmesh(const Depsgraph &depsgraph,
405 Object &object,
406 const Brush &brush,
407 const IndexMask &node_mask)
408{
409 SculptSession &ss = *object.sculpt;
410 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
411
413
414 const int cd_offset = face_set::ensure_face_sets_bmesh(object);
415
418 node_mask.foreach_index(GrainSize(1), [&](const int i) {
419 BMeshLocalData &tls = all_tls.local();
421 object, brush, ss.cache->bstrength, ss.cache->paint_face_set, nodes[i], tls, cd_offset);
422 });
423 pbvh.tag_face_sets_changed(node_mask);
424}
425
426} // namespace draw_face_sets_cc
427
428void do_draw_face_sets_brush(const Depsgraph &depsgraph,
429 const Sculpt &sd,
430 Object &object,
431 const IndexMask &node_mask)
432{
433 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
434
435 if (object.sculpt->cache->paint_face_set == SCULPT_FACE_SET_NONE) {
436 if (object.sculpt->cache->invert) {
437 /* When inverting the brush, pick the paint face mask ID from the mesh. */
438 object.sculpt->cache->paint_face_set = face_set::active_face_set_get(object);
439 }
440 else {
441 /* By default, create a new Face Sets. */
442 object.sculpt->cache->paint_face_set = face_set::find_next_available_id(object);
443 }
444 }
445
446 switch (bke::object::pbvh_get(object)->type()) {
448 do_draw_face_sets_brush_mesh(depsgraph, object, brush, node_mask);
449 break;
451 do_draw_face_sets_brush_grids(depsgraph, object, brush, node_mask);
452 break;
454 do_draw_face_sets_brush_bmesh(depsgraph, object, brush, node_mask);
455 break;
456 }
457}
458} // namespace blender::ed::sculpt_paint::brushes
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
#define SCULPT_FACE_SET_NONE
Definition BKE_paint.hh:324
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
A BVH for high poly meshes.
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:46
#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)
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_HIDDEN
#define BM_elem_flag_test(ele, hflag)
BMesh const char void * data
BMesh * bm
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
BPy_StructRNA * depsgraph
static T sum(const btAlignedObjectArray< T > &items)
void resize(const int64_t new_size)
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void resize(const int64_t new_size)
GAttributeReader lookup(const StringRef attribute_id) const
Span< NodeT > nodes() const
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:662
void foreach_index(Fn &&fn) const
static float normals[][3]
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:3052
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, 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 &automasking, 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_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_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_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 BLI_NOINLINE void calc_face_indices_grids(const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< int > face_indices)
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 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_bmesh(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 void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph, Object &object, const Brush &brush, const IndexMask &node_mask)
static void do_draw_face_sets_brush_grids(const Depsgraph &depsgraph, Object &object, const Brush &brush, const IndexMask &node_mask)
void do_draw_face_sets_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
bke::SpanAttributeWriter< int > ensure_face_sets_mesh(Mesh &mesh)
int active_face_set_get(const Object &object)
Definition sculpt.cc:196
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6823
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:7183
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6972
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7055
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7195
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6914
T rcp(const T &a)
VecBase< float, 3 > float3
struct BMVert * v
struct BMLoop * next
char falloff_shape
int grid_area
Definition BKE_ccg.hh:35
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
std::unique_ptr< auto_mask::Cache > automasking
i
Definition text_draw.cc:230