Blender V5.0
sculpt_automasking.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array.hh"
10#include "BLI_index_range.hh"
11#include "BLI_math_base.h"
12#include "BLI_math_base.hh"
13#include "BLI_math_vector.hh"
15#include "BLI_set.hh"
16#include "BLI_vector.hh"
17
18#include "DNA_brush_types.h"
19#include "DNA_mesh_types.h"
20
21#include "BKE_colortools.hh"
22#include "BKE_paint.hh"
23#include "BKE_paint_bvh.hh"
24#include "BKE_subdiv_ccg.hh"
25
26#include "mesh_brush_common.hh"
27#include "paint_intern.hh"
28#include "sculpt_automask.hh"
29#include "sculpt_boundary.hh"
30#include "sculpt_dyntopo.hh"
31#include "sculpt_face_set.hh"
32#include "sculpt_filter.hh"
33#include "sculpt_flood_fill.hh"
34#include "sculpt_intern.hh"
35#include "sculpt_islands.hh"
36#include "sculpt_undo.hh"
37
38#include "bmesh.hh"
39
40#include <cmath>
41
44{
45 if (ss.cache) {
46 return ss.cache->automasking.get();
47 }
48 if (ss.filter_cache) {
49 return ss.filter_cache->automasking.get();
50 }
51 return nullptr;
52}
53
54bool mode_enabled(const Sculpt &sd, const Brush *br, const eAutomasking_flag mode)
55{
56 int automasking = sd.automasking_flags;
57
58 if (br) {
59 automasking |= br->automasking_flags;
60 }
61
62 return (eAutomasking_flag)automasking & mode;
63}
64
65bool is_enabled(const Sculpt &sd, const Object &object, const Brush *br)
66{
67 if (object.sculpt && br && dyntopo::stroke_is_dyntopo(object, *br)) {
68 return false;
69 }
71 return true;
72 }
74 return true;
75 }
77 return true;
78 }
80 return true;
81 }
83 return true;
84 }
86 return true;
87 }
89 return true;
90 }
91
92 return false;
93}
94
95static int calc_effective_bits(const Sculpt &sd, const Brush *brush)
96{
97 if (brush) {
98 int flags = sd.automasking_flags | brush->automasking_flags;
99
100 /* Check if we are using brush cavity settings. */
104 flags |= brush->automasking_flags;
105 }
109 flags |= sd.automasking_flags;
110 }
111
112 return flags;
113 }
114 return sd.automasking_flags;
115}
116
117static float normal_calc(const float3 &compare_normal,
118 const float3 &normal,
119 float limit_lower,
120 float limit_upper)
121{
122 float angle = math::safe_acos(math::dot(compare_normal, normal));
123
124 /* note that limit is pre-divided by M_PI */
125
126 if (angle > limit_lower && angle < limit_upper) {
127 float t = 1.0f - (angle - limit_lower) / (limit_upper - limit_lower);
128
129 /* smoothstep */
130 t = t * t * (3.0 - 2.0 * t);
131
132 return t;
133 }
134 if (angle > limit_upper) {
135 return 0.0f;
136 }
137
138 return 1.0f;
139}
140
141static bool is_constrained_by_radius(const Brush *br)
142{
143 if (br == nullptr) {
144 return false;
145 }
146
147 /* 2D falloff is not constrained by radius. */
149 return false;
150 }
151
152 if (ELEM(br->sculpt_brush_type,
156 {
157 return true;
158 }
159 return false;
160}
161
162/* Fetch the propogation_steps value, preferring the brush level value over the global sculpt tool
163 * value. */
171
172/* Determine if the given automasking settings require values to be precomputed and cached. */
173static bool needs_factors_cache(const Sculpt &sd, const Brush *brush)
174{
175 const int automasking_flags = calc_effective_bits(sd, brush);
176
177 if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY && brush && is_constrained_by_radius(brush)) {
178 return true;
179 }
180
181 if (automasking_flags &
183 {
184 return boundary_propagation_steps(sd, brush) != 1;
185 }
186 return false;
187}
188
189static float calc_brush_normal_factor(const Cache &automasking,
190 const Object &object,
191 const float3 &normal)
192{
193 const SculptSession &ss = *object.sculpt;
194 float falloff = automasking.settings.start_normal_falloff * M_PI;
195 float3 initial_normal;
196
197 if (ss.cache) {
198 initial_normal = ss.cache->initial_normal_symm;
199 }
200 else {
201 initial_normal = ss.filter_cache->initial_normal;
202 }
203
204 return normal_calc(normal,
205 initial_normal,
206 automasking.settings.start_normal_limit - falloff * 0.5f,
207 automasking.settings.start_normal_limit + falloff * 0.5f);
208}
209
210static float calc_view_normal_factor(const Cache &automasking,
211 const Object &object,
212 const float3 &normal)
213{
214 const SculptSession &ss = *object.sculpt;
215 float falloff = automasking.settings.view_normal_falloff * M_PI;
216
217 float3 view_normal;
218
219 if (ss.cache) {
220 view_normal = ss.cache->view_normal_symm;
221 }
222 else {
223 view_normal = ss.filter_cache->view_normal;
224 }
225
226 return normal_calc(normal,
227 view_normal,
228 automasking.settings.view_normal_limit,
229 automasking.settings.view_normal_limit + falloff);
230}
231
232static bool calc_view_occlusion_factor(const Depsgraph &depsgraph,
233 Cache &automasking,
234 const Object &object,
235 const int vert,
236 const float3 &vert_position)
237{
238 if (automasking.occlusion[vert] == Cache::OcclusionValue::Unknown) {
239 const bool occluded = vertex_is_occluded(depsgraph, object, vert_position, true);
240 automasking.occlusion[vert] = occluded ? Cache::OcclusionValue::Occluded :
242 }
243 return automasking.occlusion[vert] == Cache::OcclusionValue::Occluded;
244}
245
246static float calc_cavity_factor(const Cache &automasking, float factor)
247{
248 float sign = signf(factor);
249
250 factor = fabsf(factor) * automasking.settings.cavity_factor * 50.0f;
251
252 factor = factor * sign * 0.5f + 0.5f;
253 CLAMP(factor, 0.0f, 1.0f);
254
255 return (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_INVERTED) ? 1.0f - factor : factor;
256}
257
261 float distance = 0.0f;
262 int count = 0;
263};
264
265static void calc_blurred_cavity_mesh(const Depsgraph &depsgraph,
266 const Object &object,
267 const Cache &automasking,
268 const int steps,
269 const int vert,
270 MutableSpan<float> cavity_factors)
271{
272 struct CavityBlurVert {
273 int vertex;
274 int depth;
275 };
276
277 const Mesh &mesh = *static_cast<Mesh *>(object.data);
278
279 const OffsetIndices faces = mesh.faces();
280 const Span<int> corner_verts = mesh.corner_verts();
281 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
282
283 const bke::AttributeAccessor attributes = mesh.attributes();
284 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
285
286 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
287 const Span<float3> normals_eval = bke::pbvh::vert_normals_eval(depsgraph, object);
288
289 AccumulatedVert all_verts;
290 AccumulatedVert verts_in_range;
291 /* Steps starts at 1, but API and user interface
292 * are zero-based.
293 */
294 const int num_steps = steps + 1;
295
296 std::queue<CavityBlurVert> queue;
297 Set<int, 64> visited_verts;
298
299 const CavityBlurVert initial{vert, 0};
300 visited_verts.add_new(vert);
301 queue.push(initial);
302
303 const float3 starting_position = positions_eval[vert];
304
305 Vector<int> neighbors;
306 while (!queue.empty()) {
307 const CavityBlurVert blurvert = queue.front();
308 queue.pop();
309
310 const int current_vert = blurvert.vertex;
311
312 const float3 &blur_vert_position = positions_eval[current_vert];
313 const float3 &blur_vert_normal = normals_eval[current_vert];
314
315 const float dist_to_start = math::distance(blur_vert_position, starting_position);
316
317 all_verts.position += blur_vert_position;
318 all_verts.distance += dist_to_start;
319 all_verts.count++;
320
321 if (blurvert.depth < num_steps) {
322 verts_in_range.position += blur_vert_position;
323 verts_in_range.normal += blur_vert_normal;
324 verts_in_range.count++;
325 }
326
327 /* Use the total number of steps used to get to this particular vert to determine if we should
328 * keep processing */
329 if (blurvert.depth >= num_steps) {
330 continue;
331 }
332
333 for (const int neighbor : vert_neighbors_get_mesh(
334 faces, corner_verts, vert_to_face_map, hide_poly, current_vert, neighbors))
335 {
336 if (visited_verts.contains(neighbor)) {
337 continue;
338 }
339
340 visited_verts.add_new(neighbor);
341 queue.push({neighbor, blurvert.depth + 1});
342 }
343 }
344
345 BLI_assert(all_verts.count != verts_in_range.count);
346
347 if (all_verts.count == 0) {
348 all_verts.position = positions_eval[vert];
349 }
350 else {
351 all_verts.position /= float(all_verts.count);
352 all_verts.distance /= all_verts.count;
353 }
354
355 if (verts_in_range.count == 0) {
356 verts_in_range.position = positions_eval[vert];
357 }
358 else {
359 verts_in_range.position /= float(verts_in_range.count);
360 }
361
362 verts_in_range.normal = math::normalize(verts_in_range.normal);
363 if (math::dot(verts_in_range.normal, verts_in_range.normal) == 0.0f) {
364 verts_in_range.normal = normals_eval[vert];
365 }
366
367 const float3 vec = all_verts.position - verts_in_range.position;
368 float factor_sum = math::safe_divide(math::dot(vec, verts_in_range.normal), all_verts.distance);
369 cavity_factors[vert] = calc_cavity_factor(automasking, factor_sum);
370}
371
372static void calc_blurred_cavity_grids(const Object &object,
373 const Cache &automasking,
374 const int steps,
375 const SubdivCCGCoord vert,
376 MutableSpan<float> cavity_factors)
377{
378 struct CavityBlurVert {
379 int vert;
380 int depth;
381 };
382
383 const SculptSession &ss = *object.sculpt;
384 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
385 const Span<float3> positions = subdiv_ccg.positions;
386 const Span<float3> normals = subdiv_ccg.normals;
387 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
388
389 AccumulatedVert all_verts;
390 AccumulatedVert verts_in_range;
391 /* Steps starts at 1, but API and user interface
392 * are zero-based.
393 */
394 const int num_steps = steps + 1;
395
396 std::queue<CavityBlurVert> queue;
397 Set<int, 64> visited_verts;
398
399 const CavityBlurVert initial{vert.to_index(key), 0};
400 visited_verts.add_new(initial.vert);
401 queue.push(initial);
402
403 const float3 starting_position = positions[vert.to_index(key)];
404
405 SubdivCCGNeighbors neighbors;
406 while (!queue.empty()) {
407 const CavityBlurVert blurvert = queue.front();
408 queue.pop();
409
410 const int current_vert = blurvert.vert;
411
412 const float3 &blur_vert_position = positions[current_vert];
413 const float3 &blur_vert_normal = normals[current_vert];
414
415 const float dist_to_start = math::distance(blur_vert_position, starting_position);
416
417 all_verts.position += blur_vert_position;
418 all_verts.distance += dist_to_start;
419 all_verts.count++;
420
421 if (blurvert.depth < num_steps) {
422 verts_in_range.position += blur_vert_position;
423 verts_in_range.normal += blur_vert_normal;
424 verts_in_range.count++;
425 }
426
427 /* Use the total number of steps used to get to this particular vert to determine if we should
428 * keep processing */
429 if (blurvert.depth >= num_steps) {
430 continue;
431 }
432
434 subdiv_ccg, SubdivCCGCoord::from_index(key, current_vert), false, neighbors);
435 for (const SubdivCCGCoord neighbor : neighbors.coords) {
436 const int neighbor_idx = neighbor.to_index(key);
437 if (visited_verts.contains(neighbor_idx)) {
438 continue;
439 }
440
441 visited_verts.add_new(neighbor_idx);
442 queue.push({neighbor_idx, blurvert.depth + 1});
443 }
444 }
445
446 BLI_assert(all_verts.count != verts_in_range.count);
447
448 if (all_verts.count == 0) {
449 all_verts.position = positions[vert.to_index(key)];
450 }
451 else {
452 all_verts.position /= float(all_verts.count);
453 all_verts.distance /= all_verts.count;
454 }
455
456 if (verts_in_range.count == 0) {
457 verts_in_range.position = positions[vert.to_index(key)];
458 }
459 else {
460 verts_in_range.position /= float(verts_in_range.count);
461 }
462
463 verts_in_range.normal = math::normalize(verts_in_range.normal);
464 if (math::dot(verts_in_range.normal, verts_in_range.normal) == 0.0f) {
465 verts_in_range.normal = normals[vert.to_index(key)];
466 }
467
468 const float3 vec = all_verts.position - verts_in_range.position;
469 float factor_sum = math::dot(vec, verts_in_range.normal) / all_verts.distance;
470 cavity_factors[vert.to_index(key)] = calc_cavity_factor(automasking, factor_sum);
471}
472
473static void calc_blurred_cavity_bmesh(const Cache &automasking,
474 const int steps,
475 BMVert *vert,
476 MutableSpan<float> cavity_factors)
477{
478 struct CavityBlurVert {
479 BMVert *vertex;
480 int index;
481 int depth;
482 };
483
484 AccumulatedVert all_verts;
485 AccumulatedVert verts_in_range;
486 /* Steps starts at 1, but API and user interface
487 * are zero-based.
488 */
489 const int num_steps = steps + 1;
490
491 std::queue<CavityBlurVert> queue;
492 Set<int, 64> visited_verts;
493
494 const CavityBlurVert initial{vert, BM_elem_index_get(vert), 0};
495 visited_verts.add_new(initial.index);
496 queue.push(initial);
497
498 const float3 starting_position = vert->co;
499
500 BMeshNeighborVerts neighbors;
501 while (!queue.empty()) {
502 const CavityBlurVert blurvert = queue.front();
503 queue.pop();
504
505 BMVert *current_vert = blurvert.vertex;
506
507 const float3 blur_vert_position = current_vert->co;
508 const float3 blur_vert_normal = current_vert->no;
509
510 const float dist_to_start = math::distance(blur_vert_position, starting_position);
511
512 all_verts.position += blur_vert_position;
513 all_verts.distance += dist_to_start;
514 all_verts.count++;
515
516 if (blurvert.depth < num_steps) {
517 verts_in_range.position += blur_vert_position;
518 verts_in_range.normal += blur_vert_normal;
519 verts_in_range.count++;
520 }
521
522 /* Use the total number of steps used to get to this particular vert to determine if we should
523 * keep processing */
524 if (blurvert.depth >= num_steps) {
525 continue;
526 }
527
528 for (BMVert *neighbor : vert_neighbors_get_bmesh(*current_vert, neighbors)) {
529 const int neighbor_idx = BM_elem_index_get(neighbor);
530 if (visited_verts.contains(neighbor_idx)) {
531 continue;
532 }
533
534 visited_verts.add_new(neighbor_idx);
535 queue.push({neighbor, neighbor_idx, blurvert.depth + 1});
536 }
537 }
538
539 BLI_assert(all_verts.count != verts_in_range.count);
540
541 if (all_verts.count == 0) {
542 all_verts.position = vert->co;
543 }
544 else {
545 all_verts.position /= float(all_verts.count);
546 all_verts.distance /= all_verts.count;
547 }
548
549 if (verts_in_range.count == 0) {
550 verts_in_range.position = vert->co;
551 }
552 else {
553 verts_in_range.position /= float(verts_in_range.count);
554 }
555
556 verts_in_range.normal = math::normalize(verts_in_range.normal);
557 if (math::dot(verts_in_range.normal, verts_in_range.normal) == 0.0f) {
558 verts_in_range.normal = vert->no;
559 }
560
561 const float3 vec = all_verts.position - verts_in_range.position;
562 float factor_sum = math::dot(vec, verts_in_range.normal) / all_verts.distance;
563 cavity_factors[BM_elem_index_get(vert)] = calc_cavity_factor(automasking, factor_sum);
564}
565
566static float process_cavity_factor(const Cache &automasking, float factor)
567{
568 bool inverted = automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_INVERTED;
569
570 if ((automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) &&
572 {
573 factor = inverted ? 1.0f - factor : factor;
574 factor = BKE_curvemapping_evaluateF(automasking.settings.cavity_curve, 0, factor);
575 factor = inverted ? 1.0f - factor : factor;
576 }
577
578 return factor;
579}
580
581static void calc_cavity_factor_mesh(const Depsgraph &depsgraph,
582 const Cache &automasking,
583 const Object &object,
584 const int vert)
585{
586 if (automasking.cavity_factor[vert] == -1.0f) {
588 object,
589 automasking,
590 automasking.settings.cavity_blur_steps,
591 vert,
592 const_cast<Cache &>(automasking).cavity_factor);
593 }
594}
595
596static void calc_cavity_factor_grids(const CCGKey &key,
597 const Cache &automasking,
598 const Object &object,
599 const int vert)
600{
601 if (automasking.cavity_factor[vert] == -1.0f) {
603 automasking,
604 automasking.settings.cavity_blur_steps,
606 const_cast<Cache &>(automasking).cavity_factor);
607 }
608}
609
610static void calc_cavity_factor_bmesh(const Cache &automasking, BMVert *vert, const int vert_i)
611{
612 if (automasking.cavity_factor[vert_i] == -1.0f) {
613 calc_blurred_cavity_bmesh(automasking,
614 automasking.settings.cavity_blur_steps,
615 vert,
616 const_cast<Cache &>(automasking).cavity_factor);
617 }
618}
619
620void calc_vert_factors(const Depsgraph &depsgraph,
621 const Object &object,
622 const Cache &automasking,
623 const bke::pbvh::MeshNode &node,
624 const Span<int> verts,
625 const MutableSpan<float> factors)
626{
627 const SculptSession &ss = *object.sculpt;
628 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
629 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, object);
631 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
633 const bke::AttributeAccessor attributes = mesh.attributes();
634 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
635 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
636 Span<float3> orig_normals;
637 if (automasking.settings.flags &
639 {
640 if (std::optional<OrigPositionData> orig_data = orig_position_data_lookup_mesh(object, node)) {
641 orig_normals = orig_data->normals;
642 }
643 }
644
645 for (const int i : verts.index_range()) {
646 const int vert = verts[i];
647 const float3 &normal = orig_normals.is_empty() ? vert_normals[vert] : orig_normals[i];
648
649 /* Since brush normal mode depends on the current mirror symmetry pass
650 * it is not folded into the factor cache (when it exists). */
651 if ((ss.cache || ss.filter_cache) &&
653 {
654 factors[i] *= calc_brush_normal_factor(automasking, object, normal);
655 }
656
657 /* If the cache is initialized with valid info, use the cache. This is used when the
658 * automasking information can't be computed in real time per vertex and needs to be
659 * initialized for the whole mesh when the stroke starts. */
660 if (!automasking.factor.is_empty()) {
661 float cached_factor = automasking.factor[vert];
662
663 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
664 BLI_assert(automasking.cavity_factor[vert] != -1.0f);
665 cached_factor *= process_cavity_factor(automasking, automasking.cavity_factor[vert]);
666 }
667
668 factors[i] *= cached_factor;
669 continue;
670 }
671
672 bool do_occlusion = (automasking.settings.flags &
675 if (do_occlusion) {
676 const bool occluded = calc_view_occlusion_factor(
677 depsgraph, const_cast<Cache &>(automasking), object, vert, vert_positions[vert]);
678 if (occluded) {
679 factors[i] = 0.0f;
680 continue;
681 }
682 }
683
684 if (!automasking.settings.topology_use_brush_limit &&
686 islands::vert_id_get(ss, vert) != automasking.settings.initial_island_nr)
687 {
688 factors[i] = 0.0f;
689 continue;
690 }
691
692 if (automasking.settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
694 vert_to_face_map, face_sets, vert, automasking.settings.initial_face_set))
695 {
696 factors[i] = 0.0f;
697 continue;
698 }
699 }
700
702 if (boundary::vert_is_boundary(vert_to_face_map, hide_poly, boundary, vert)) {
703 factors[i] = 0.0f;
704 continue;
705 }
706 }
707
709 bool ignore = ss.cache && ss.cache->brush &&
711 face_set::vert_face_set_get(vert_to_face_map, face_sets, vert) ==
713
714 if (!ignore && !face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, vert)) {
715 factors[i] = 0.0f;
716 continue;
717 }
718 }
719
720 if ((ss.cache || ss.filter_cache) &&
722 {
723 factors[i] *= calc_view_normal_factor(automasking, object, normal);
724 }
725
726 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
727 BLI_assert(automasking.cavity_factor[vert] != -1.0f);
728 factors[i] *= process_cavity_factor(automasking, automasking.cavity_factor[vert]);
729 }
730 }
731}
732
733void calc_face_factors(const Depsgraph &depsgraph,
734 const Object &object,
736 const Span<int> corner_verts,
737 const Cache &automasking,
738 const bke::pbvh::MeshNode & /*node*/,
739 const Span<int> face_indices,
740 const MutableSpan<float> factors)
741{
742 const SculptSession &ss = *object.sculpt;
743 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
744 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, object);
746 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
748 const bke::AttributeAccessor attributes = mesh.attributes();
749 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
750 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
751 for (const int i : face_indices.index_range()) {
752 const Span<int> face_verts = corner_verts.slice(faces[face_indices[i]]);
753 float sum = 0.0f;
754 for (const int vert : face_verts) {
755 float factor = 1.0f;
756 BLI_SCOPED_DEFER([&]() { sum += factor; });
757
758 /* Since brush normal mode depends on the current mirror symmetry pass
759 * it is not folded into the factor cache (when it exists). */
760 if ((ss.cache || ss.filter_cache) &&
762 {
763 factor *= calc_brush_normal_factor(automasking, object, vert_normals[vert]);
764 }
765
766 /* If the cache is initialized with valid info, use the cache. This is used when the
767 * automasking information can't be computed in real time per vertex and needs to be
768 * initialized for the whole mesh when the stroke starts. */
769 if (!automasking.factor.is_empty()) {
770 float cached_factor = automasking.factor[vert];
771
772 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
773 BLI_assert(automasking.cavity_factor[vert] != -1.0f);
774 cached_factor *= process_cavity_factor(automasking, automasking.cavity_factor[vert]);
775 }
776
777 factor *= cached_factor;
778 continue;
779 }
780
781 bool do_occlusion = (automasking.settings.flags &
784 if (do_occlusion) {
785 const bool occluded = calc_view_occlusion_factor(
786 depsgraph, const_cast<Cache &>(automasking), object, vert, vert_positions[vert]);
787 if (occluded) {
788 factor = 0.0f;
789 continue;
790 }
791 }
792
793 if (!automasking.settings.topology_use_brush_limit &&
795 islands::vert_id_get(ss, vert) != automasking.settings.initial_island_nr)
796 {
797 factor = 0.0f;
798 continue;
799 }
800
801 if (automasking.settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
803 vert_to_face_map, face_sets, vert, automasking.settings.initial_face_set))
804 {
805 factor = 0.0f;
806 continue;
807 }
808 }
809
811 if (boundary::vert_is_boundary(vert_to_face_map, hide_poly, boundary, vert)) {
812 factor = 0.0f;
813 continue;
814 }
815 }
816
818 bool ignore = ss.cache && ss.cache->brush &&
820 face_set::vert_face_set_get(vert_to_face_map, face_sets, vert) ==
822
823 if (!ignore && !face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, vert)) {
824 factor = 0.0f;
825 continue;
826 }
827 }
828
829 if ((ss.cache || ss.filter_cache) &&
831 {
832 factor *= calc_view_normal_factor(automasking, object, vert_normals[vert]);
833 }
834
835 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
836 BLI_assert(automasking.cavity_factor[vert] != -1.0f);
837 factor *= process_cavity_factor(automasking, automasking.cavity_factor[vert]);
838 }
839 }
840 factors[i] *= sum * math::rcp(float(face_verts.size()));
841 }
842}
843
844void calc_grids_factors(const Depsgraph &depsgraph,
845 const Object &object,
846 const Cache &automasking,
847 const bke::pbvh::GridsNode &node,
848 const Span<int> grids,
849 const MutableSpan<float> factors)
850{
851 const SculptSession &ss = *object.sculpt;
852 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
853 const OffsetIndices<int> faces = base_mesh.faces();
854 const Span<int> corner_verts = base_mesh.corner_verts();
855 const GroupedSpan<int> vert_to_face_map = base_mesh.vert_to_face_map();
857 const bke::AttributeAccessor attributes = base_mesh.attributes();
858 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
859 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
860 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
861
862 Span<float3> orig_normals;
863 if (automasking.settings.flags &
865 {
866 if (std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(object, node))
867 {
868 orig_normals = orig_data->normals;
869 }
870 }
871
872 for (const int i : grids.index_range()) {
873 const int grid_face_set = face_sets.is_empty() ?
875 face_sets[subdiv_ccg.grid_to_face_map[grids[i]]];
876 const int node_start = i * key.grid_area;
877 const int grids_start = grids[i] * key.grid_area;
878 for (const int offset : IndexRange(key.grid_area)) {
879 const int node_vert = node_start + offset;
880 const int vert = grids_start + offset;
881 const float3 &normal = orig_normals.is_empty() ? subdiv_ccg.normals[vert] :
882 orig_normals[node_vert];
883
884 /* Since brush normal mode depends on the current mirror symmetry pass
885 * it is not folded into the factor cache (when it exists). */
886 if ((ss.cache || ss.filter_cache) &&
888 {
889 factors[node_vert] *= calc_brush_normal_factor(automasking, object, normal);
890 }
891
892 /* If the cache is initialized with valid info, use the cache. This is used when the
893 * automasking information can't be computed in real time per vertex and needs to be
894 * initialized for the whole mesh when the stroke starts. */
895 if (!automasking.factor.is_empty()) {
896 float cached_factor = automasking.factor[vert];
897
898 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
899 BLI_assert(automasking.cavity_factor[vert] != -1.0f);
900 cached_factor *= process_cavity_factor(automasking, automasking.cavity_factor[vert]);
901 }
902
903 factors[node_vert] *= cached_factor;
904 continue;
905 }
906
907 bool do_occlusion = (automasking.settings.flags &
910 if (do_occlusion) {
911 const bool occluded = calc_view_occlusion_factor(
912 depsgraph, const_cast<Cache &>(automasking), object, vert, subdiv_ccg.positions[vert]);
913 if (occluded) {
914 factors[node_vert] = 0.0f;
915 continue;
916 }
917 }
918
919 if (!automasking.settings.topology_use_brush_limit &&
921 islands::vert_id_get(ss, vert) != automasking.settings.initial_island_nr)
922 {
923 factors[node_vert] = 0.0f;
924 continue;
925 }
926
927 if (automasking.settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
928 if (grid_face_set != automasking.settings.initial_face_set) {
929 factors[node_vert] = 0.0f;
930 continue;
931 }
932 }
933
936 faces, corner_verts, boundary, subdiv_ccg, SubdivCCGCoord::from_index(key, vert)))
937 {
938 factors[node_vert] = 0.0f;
939 continue;
940 }
941 }
942
944 bool ignore = ss.cache && ss.cache->brush &&
946 grid_face_set == ss.cache->paint_face_set;
947
949 corner_verts,
950 vert_to_face_map,
951 face_sets,
952 subdiv_ccg,
953 SubdivCCGCoord::from_index(key, vert)))
954 {
955 factors[node_vert] = 0.0f;
956 continue;
957 }
958 }
959
960 if ((ss.cache || ss.filter_cache) &&
962 {
963 factors[node_vert] *= calc_view_normal_factor(automasking, object, normal);
964 }
965
966 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
967 BLI_assert(automasking.cavity_factor[vert] != -1.0f);
968 factors[node_vert] *= process_cavity_factor(automasking, automasking.cavity_factor[vert]);
969 }
970 }
971 }
972}
973
974void calc_vert_factors(const Depsgraph &depsgraph,
975 const Object &object,
976 const Cache &automasking,
977 const bke::pbvh::BMeshNode & /*node*/,
978 const Set<BMVert *, 0> &verts,
979 const MutableSpan<float> factors)
980{
981 SculptSession &ss = *object.sculpt;
982 BMesh &bm = *ss.bm;
983 const int face_set_offset = CustomData_get_offset_named(
984 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
985
986 Array<float3> orig_normals;
987 if (automasking.settings.flags &
989 {
990 orig_position_data_gather_bmesh(*ss.bm_log, verts, {}, orig_normals);
991 }
992
993 int i = 0;
994 for (BMVert *vert : verts) {
995 BLI_SCOPED_DEFER([&]() { i++; });
996 const int vert_i = BM_elem_index_get(vert);
997 const float3 normal = orig_normals.is_empty() ? float3(vert->no) : orig_normals[i];
998
999 /* Since brush normal mode depends on the current mirror symmetry pass
1000 * it is not folded into the factor cache (when it exists). */
1001 if ((ss.cache || ss.filter_cache) &&
1003 {
1004 factors[i] *= calc_brush_normal_factor(automasking, object, normal);
1005 }
1006
1007 /* If the cache is initialized with valid info, use the cache. This is used when the
1008 * automasking information can't be computed in real time per vertex and needs to be
1009 * initialized for the whole mesh when the stroke starts. */
1010 if (!automasking.factor.is_empty()) {
1011 float cached_factor = automasking.factor[vert_i];
1012
1013 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
1014 BLI_assert(automasking.cavity_factor[vert_i] != -1.0f);
1015 cached_factor *= process_cavity_factor(automasking, automasking.cavity_factor[vert_i]);
1016 }
1017
1018 factors[i] *= cached_factor;
1019 continue;
1020 }
1021
1022 bool do_occlusion = (automasking.settings.flags &
1025 if (do_occlusion) {
1026 const bool occluded = calc_view_occlusion_factor(
1027 depsgraph, const_cast<Cache &>(automasking), object, vert_i, vert->co);
1028 if (occluded) {
1029 factors[i] = 0.0f;
1030 continue;
1031 }
1032 }
1033
1034 if (!automasking.settings.topology_use_brush_limit &&
1036 islands::vert_id_get(ss, vert_i) != automasking.settings.initial_island_nr)
1037 {
1038 factors[i] = 0.0f;
1039 continue;
1040 }
1041
1042 if (automasking.settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
1044 face_set_offset, *vert, automasking.settings.initial_face_set))
1045 {
1046 factors[i] = 0.0f;
1047 continue;
1048 }
1049 }
1050
1052 if (boundary::vert_is_boundary(vert)) {
1053 factors[i] = 0.0f;
1054 continue;
1055 }
1056 }
1057
1059 bool ignore = ss.cache && ss.cache->brush &&
1061 face_set::vert_face_set_get(face_set_offset, *vert) ==
1063
1064 if (!ignore && !face_set::vert_has_unique_face_set(face_set_offset, *vert)) {
1065 factors[i] = 0.0f;
1066 continue;
1067 }
1068 }
1069
1070 if ((ss.cache || ss.filter_cache) &&
1072 {
1073 factors[i] *= calc_view_normal_factor(automasking, object, normal);
1074 }
1075
1076 if (automasking.settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
1077 BLI_assert(automasking.cavity_factor[vert_i] != -1.0f);
1078 factors[i] *= process_cavity_factor(automasking, automasking.cavity_factor[vert_i]);
1079 }
1080 }
1081}
1082
1084 const Sculpt &sd,
1085 Object &ob,
1086 const Span<float3> vert_positions,
1087 MutableSpan<float> factors)
1088{
1089 SculptSession &ss = *ob.sculpt;
1090 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1091 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1092 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1093
1094 const float radius = ss.cache ? ss.cache->radius : std::numeric_limits<float>::max();
1095 const int active_vert = std::get<int>(ss.active_vert());
1096 flood_fill::FillDataMesh flood = flood_fill::FillDataMesh(vert_positions.size());
1097
1098 flood.add_initial(find_symm_verts_mesh(depsgraph, ob, active_vert, radius));
1099
1100 const bool use_radius = ss.cache && is_constrained_by_radius(brush);
1102
1103 float3 location = vert_positions[active_vert];
1104
1105 if (use_radius) {
1106 flood.execute(ob, vert_to_face_map, [&](int from_v, int to_v) {
1107 factors[from_v] = 1.0f;
1108 factors[to_v] = 1.0f;
1110 vert_positions[to_v], location, radius, symm);
1111 });
1112 }
1113 else {
1114 flood.execute(ob, vert_to_face_map, [&](int from_v, int to_v) {
1115 factors[from_v] = 1.0f;
1116 factors[to_v] = 1.0f;
1117 return true;
1118 });
1119 }
1120}
1121
1123 Object &ob,
1124 const SubdivCCG &subdiv_ccg,
1125 MutableSpan<float> factors)
1126
1127{
1128 SculptSession &ss = *ob.sculpt;
1129 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1130
1131 const float radius = ss.cache ? ss.cache->radius : std::numeric_limits<float>::max();
1132 const int active_vert = ss.active_vert_index();
1133
1134 const Span<float3> positions = subdiv_ccg.positions;
1135 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1136
1138
1139 flood.add_initial(key, find_symm_verts_grids(ob, active_vert, radius));
1140
1141 const bool use_radius = ss.cache && is_constrained_by_radius(brush);
1143
1144 float3 location = positions[active_vert];
1145
1146 if (use_radius) {
1147 flood.execute(
1148 ob, subdiv_ccg, [&](SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool /*is_duplicate*/) {
1149 factors[from_v.to_index(key)] = 1.0f;
1150 factors[to_v.to_index(key)] = 1.0f;
1152 positions[to_v.to_index(key)], location, radius, symm);
1153 });
1154 }
1155 else {
1156 flood.execute(
1157 ob, subdiv_ccg, [&](SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool /*is_duplicate*/) {
1158 factors[from_v.to_index(key)] = 1.0f;
1159 factors[to_v.to_index(key)] = 1.0f;
1160 return true;
1161 });
1162 }
1163}
1164
1166 Object &ob,
1167 BMesh &bm,
1168 MutableSpan<float> factors)
1169{
1170 SculptSession &ss = *ob.sculpt;
1171 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1172
1173 const float radius = ss.cache ? ss.cache->radius : std::numeric_limits<float>::max();
1174 BMVert *active_vert = std::get<BMVert *>(ss.active_vert());
1175 const int num_verts = BM_mesh_elem_count(&bm, BM_VERT);
1177
1178 flood.add_initial(*ss.bm, find_symm_verts_bmesh(ob, BM_elem_index_get(active_vert), radius));
1179
1180 const bool use_radius = ss.cache && is_constrained_by_radius(brush);
1182
1183 float3 location = active_vert->co;
1184
1185 if (use_radius) {
1186 flood.execute(ob, [&](BMVert *from_v, BMVert *to_v) {
1187 factors[BM_elem_index_get(from_v)] = 1.0f;
1188 factors[BM_elem_index_get(to_v)] = 1.0f;
1189 return SCULPT_is_vertex_inside_brush_radius_symm(to_v->co, location, radius, symm);
1190 });
1191 }
1192 else {
1193 flood.execute(ob, [&](BMVert *from_v, BMVert *to_v) {
1194 factors[BM_elem_index_get(from_v)] = 1.0f;
1195 factors[BM_elem_index_get(to_v)] = 1.0f;
1196 return true;
1197 });
1198 }
1199}
1200
1202 const Sculpt &sd,
1203 Object &ob,
1204 MutableSpan<float> factors)
1205{
1206 /* TODO: This method is to be removed when more of the automasking code handles the different
1207 * pbvh types. */
1208 SculptSession &ss = *ob.sculpt;
1209 if (std::holds_alternative<std::monostate>(ss.active_vert())) {
1210 /* If we don't have an active vertex (i.e. the cursor is not over the mesh), we cannot
1211 * accurately calculate the topology automasking factor as it may be ambiguous which island the
1212 * user is intending to affect. */
1213 return;
1214 }
1215
1216 switch (bke::object::pbvh_get(ob)->type()) {
1219 depsgraph, sd, ob, bke::pbvh::vert_positions_eval(depsgraph, ob), factors);
1220 break;
1223 break;
1225 fill_topology_automasking_factors_bmesh(sd, ob, *ss.bm, factors);
1226 break;
1227 }
1228}
1229
1230static void init_face_sets_masking(const Sculpt &sd, Object &ob, MutableSpan<float> factors)
1231{
1232 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1233
1234 if (!is_enabled(sd, ob, brush)) {
1235 return;
1236 }
1237
1238 const int active_face_set = face_set::active_face_set_get(ob);
1239 switch (bke::object::pbvh_get(ob)->type()) {
1240 case bke::pbvh::Type::Mesh: {
1241 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1242 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1243 const bke::AttributeAccessor attributes = mesh.attributes();
1244 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set",
1246 if (face_sets.is_empty()) {
1247 return;
1248 }
1249 threading::parallel_for(IndexRange(mesh.verts_num), 1024, [&](const IndexRange range) {
1250 for (const int vert : range) {
1251 if (!face_set::vert_has_face_set(vert_to_face_map, face_sets, vert, active_face_set)) {
1252 factors[vert] = 0.0f;
1253 }
1254 }
1255 });
1256 break;
1257 }
1259 const Mesh &base_mesh = *static_cast<const Mesh *>(ob.data);
1260 const OffsetIndices<int> faces = base_mesh.faces();
1261 const bke::AttributeAccessor attributes = base_mesh.attributes();
1262 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set",
1264 if (face_sets.is_empty()) {
1265 return;
1266 }
1267 const SculptSession &ss = *ob.sculpt;
1268 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1269 const int grid_area = subdiv_ccg.grid_area;
1270 threading::parallel_for(faces.index_range(), 128, [&](const IndexRange range) {
1271 for (const int face : range) {
1272 if (face_sets[face] != active_face_set) {
1273 factors.slice(bke::ccg::face_range(faces, grid_area, face)).fill(0.0f);
1274 }
1275 }
1276 });
1277
1278 break;
1279 }
1281 const SculptSession &ss = *ob.sculpt;
1282 const BMesh &bm = *ss.bm;
1283 const int face_set_offset = CustomData_get_offset_named(
1284 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
1285 if (face_set_offset == -1) {
1286 return;
1287 }
1288 threading::parallel_for(IndexRange(bm.totvert), 1024, [&](const IndexRange range) {
1289 for (const int i : range) {
1290 const BMVert *vert = BM_vert_at_index(&const_cast<BMesh &>(bm), i);
1291 if (!face_set::vert_has_face_set(face_set_offset, *vert, active_face_set)) {
1292 factors[i] = 0.0f;
1293 }
1294 }
1295 });
1296 break;
1297 }
1298 }
1299}
1300
1301static constexpr int EDGE_DISTANCE_INF = -1;
1302
1306};
1307
1309 const Depsgraph &depsgraph,
1310 const BoundaryAutomaskMode mode,
1311 const int propagation_steps,
1312 MutableSpan<float> factors)
1313{
1314 SculptSession &ss = *object.sculpt;
1315 Mesh &mesh = *static_cast<Mesh *>(object.data);
1316
1317 const OffsetIndices faces = mesh.faces();
1318 const Span<int> corner_verts = mesh.corner_verts();
1319 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1320 const bke::AttributeAccessor attributes = mesh.attributes();
1321 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1322 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1323
1324 const int num_verts = bke::pbvh::vert_positions_eval(depsgraph, object).size();
1325 Array<int> edge_distance(num_verts, EDGE_DISTANCE_INF);
1326
1327 for (const int i : IndexRange(num_verts)) {
1328 switch (mode) {
1330 if (boundary::vert_is_boundary(vert_to_face_map, hide_poly, ss.vertex_info.boundary, i)) {
1331 edge_distance[i] = 0;
1332 }
1333 break;
1335 if (!face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, i)) {
1336 edge_distance[i] = 0;
1337 }
1338 break;
1339 }
1340 }
1341
1342 Vector<int> neighbors;
1343 for (const int propagation_it : IndexRange(propagation_steps)) {
1344 for (const int i : IndexRange(num_verts)) {
1345 if (edge_distance[i] != EDGE_DISTANCE_INF) {
1346 continue;
1347 }
1348
1349 for (const int neighbor :
1350 vert_neighbors_get_mesh(faces, corner_verts, vert_to_face_map, hide_poly, i, neighbors))
1351 {
1352 if (edge_distance[neighbor] == propagation_it) {
1353 edge_distance[i] = propagation_it + 1;
1354 }
1355 }
1356 }
1357 }
1358
1359 for (const int i : IndexRange(num_verts)) {
1360 if (edge_distance[i] == EDGE_DISTANCE_INF) {
1361 continue;
1362 }
1363
1364 const float p = 1.0f - (float(edge_distance[i]) / float(propagation_steps));
1365 const float edge_boundary_automask = pow2f(p);
1366
1367 factors[i] *= (1.0f - edge_boundary_automask);
1368 }
1369}
1370
1372 const BoundaryAutomaskMode mode,
1373 const int propagation_steps,
1374 MutableSpan<float> factors)
1375{
1376 SculptSession &ss = *object.sculpt;
1377 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1378 Mesh &mesh = *static_cast<Mesh *>(object.data);
1379
1380 const Span<float3> positions = subdiv_ccg.positions;
1381 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1382
1383 const OffsetIndices faces = mesh.faces();
1384 const Span<int> corner_verts = mesh.corner_verts();
1385 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1386 const bke::AttributeAccessor attributes = mesh.attributes();
1387 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1388
1389 Array<int> edge_distance(positions.size(), EDGE_DISTANCE_INF);
1390 for (const int i : positions.index_range()) {
1391 const SubdivCCGCoord coord = SubdivCCGCoord::from_index(key, i);
1392 switch (mode) {
1395 faces, corner_verts, ss.vertex_info.boundary, subdiv_ccg, coord))
1396 {
1397 edge_distance[i] = 0;
1398 }
1399 break;
1402 faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, coord))
1403 {
1404 edge_distance[i] = 0;
1405 }
1406 break;
1407 }
1408 }
1409
1410 SubdivCCGNeighbors neighbors;
1411 for (const int propagation_it : IndexRange(propagation_steps)) {
1412 for (const int i : positions.index_range()) {
1413 if (edge_distance[i] != EDGE_DISTANCE_INF) {
1414 continue;
1415 }
1416
1417 const SubdivCCGCoord coord = SubdivCCGCoord::from_index(key, i);
1418
1419 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
1420 for (const SubdivCCGCoord neighbor : neighbors.coords) {
1421 const int neighbor_idx = neighbor.to_index(key);
1422 if (edge_distance[neighbor_idx] == propagation_it) {
1423 edge_distance[i] = propagation_it + 1;
1424 }
1425 }
1426 }
1427 }
1428
1429 for (const int i : positions.index_range()) {
1430 if (edge_distance[i] == EDGE_DISTANCE_INF) {
1431 continue;
1432 }
1433
1434 const float p = 1.0f - (float(edge_distance[i]) / float(propagation_steps));
1435 const float edge_boundary_automask = pow2f(p);
1436
1437 factors[i] *= (1.0f - edge_boundary_automask);
1438 }
1439}
1440
1442 const BoundaryAutomaskMode mode,
1443 const int propagation_steps,
1444 MutableSpan<float> factors)
1445{
1446 SculptSession &ss = *object.sculpt;
1447 BMesh &bm = *ss.bm;
1448 const int face_set_offset = CustomData_get_offset_named(
1449 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
1450 const int num_verts = BM_mesh_elem_count(&bm, BM_VERT);
1451
1452 Array<int> edge_distance(num_verts, EDGE_DISTANCE_INF);
1453
1454 for (const int i : IndexRange(num_verts)) {
1455 BMVert *vert = BM_vert_at_index(&bm, i);
1456 switch (mode) {
1458 if (boundary::vert_is_boundary(vert)) {
1459 edge_distance[i] = 0;
1460 }
1461 break;
1463 if (!face_set::vert_has_unique_face_set(face_set_offset, *vert)) {
1464 edge_distance[i] = 0;
1465 }
1466 }
1467 }
1468
1469 BMeshNeighborVerts neighbors;
1470 for (const int propagation_it : IndexRange(propagation_steps)) {
1471 for (const int i : IndexRange(num_verts)) {
1472 if (edge_distance[i] != EDGE_DISTANCE_INF) {
1473 continue;
1474 }
1475
1476 BMVert *vert = BM_vert_at_index(&bm, i);
1477 for (BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
1478 const int neighbor_idx = BM_elem_index_get(neighbor);
1479
1480 if (edge_distance[neighbor_idx] == propagation_it) {
1481 edge_distance[i] = propagation_it + 1;
1482 }
1483 }
1484 }
1485 }
1486
1487 for (const int i : IndexRange(num_verts)) {
1488 if (edge_distance[i] == EDGE_DISTANCE_INF) {
1489 continue;
1490 }
1491
1492 const float p = 1.0f - (float(edge_distance[i]) / float(propagation_steps));
1493 const float edge_boundary_automask = pow2f(p);
1494
1495 factors[i] *= (1.0f - edge_boundary_automask);
1496 }
1497}
1498
1499static void init_boundary_masking(Object &object,
1500 const Depsgraph &depsgraph,
1501 const BoundaryAutomaskMode mode,
1502 const int propagation_steps,
1503 MutableSpan<float> factors)
1504{
1505 switch (bke::object::pbvh_get(object)->type()) {
1507 init_boundary_masking_mesh(object, depsgraph, mode, propagation_steps, factors);
1508 break;
1510 init_boundary_masking_grids(object, mode, propagation_steps, factors);
1511 break;
1513 init_boundary_masking_bmesh(object, mode, propagation_steps, factors);
1514 break;
1515 }
1516}
1517
1518/* Updates the cached values, preferring brush settings over tool-level settings. */
1519static void cache_settings_update(Cache &automasking,
1520 Object &object,
1521 const Sculpt &sd,
1522 const Brush *brush)
1523{
1524 automasking.settings.flags = calc_effective_bits(sd, brush);
1526
1527 if (brush && (brush->automasking_flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) {
1530 }
1531 else {
1534 }
1535
1536 if (brush && (brush->automasking_flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) {
1539 }
1540 else {
1543 }
1544
1545 if (brush && (brush->automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) {
1546 automasking.settings.cavity_curve = brush->automasking_cavity_curve;
1549 }
1550 else {
1554 }
1555}
1556
1558 Cache &automasking,
1559 Object &ob,
1560 eAutomasking_flag mode,
1561 MutableSpan<float> factors)
1562{
1563 const int totvert = SCULPT_vertex_count_get(ob);
1564 /* No need to build original data since this is only called at the beginning of strokes. */
1565 switch (bke::object::pbvh_get(ob)->type()) {
1566 case bke::pbvh::Type::Mesh: {
1567 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1569 threading::parallel_for(IndexRange(totvert), 1024, [&](const IndexRange range) {
1570 for (const int vert : range) {
1571 float f = factors[vert];
1572
1573 if (int(mode) & BRUSH_AUTOMASKING_VIEW_NORMAL) {
1574 if (int(mode) & BRUSH_AUTOMASKING_VIEW_OCCLUSION) {
1576 depsgraph, automasking, ob, vert, vert_positions[vert]);
1577 }
1578
1579 f *= calc_view_normal_factor(automasking, ob, vert_normals[vert]);
1580 }
1581
1582 factors[vert] = f;
1583 }
1584 });
1585 break;
1586 }
1588 const SculptSession &ss = *ob.sculpt;
1589 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1590 threading::parallel_for(IndexRange(totvert), 1024, [&](const IndexRange range) {
1591 for (const int vert : range) {
1592 float f = factors[vert];
1593
1594 if (int(mode) & BRUSH_AUTOMASKING_VIEW_NORMAL) {
1595 if (int(mode) & BRUSH_AUTOMASKING_VIEW_OCCLUSION) {
1597 depsgraph, automasking, ob, vert, subdiv_ccg.positions[vert]);
1598 }
1599
1600 f *= calc_view_normal_factor(automasking, ob, subdiv_ccg.normals[vert]);
1601 }
1602
1603 factors[vert] = f;
1604 }
1605 });
1606 break;
1607 }
1609 const SculptSession &ss = *ob.sculpt;
1610 BMesh &bm = *ss.bm;
1611 threading::parallel_for(IndexRange(bm.totvert), 1024, [&](const IndexRange range) {
1612 for (const int i : range) {
1613 const BMVert *vert = BM_vert_at_index(&bm, i);
1614 float f = factors[i];
1615
1616 if (int(mode) & BRUSH_AUTOMASKING_VIEW_NORMAL) {
1617 if (int(mode) & BRUSH_AUTOMASKING_VIEW_OCCLUSION) {
1618 f *= calc_view_occlusion_factor(depsgraph, automasking, ob, i, vert->co);
1619 }
1620
1621 f *= calc_view_normal_factor(automasking, ob, vert->no);
1622 }
1623
1624 factors[i] = f;
1625 }
1626 });
1627 break;
1628 }
1629 }
1630}
1631
1632std::unique_ptr<Cache> cache_init(const Depsgraph &depsgraph,
1633 const Sculpt &sd,
1634 const Brush *brush,
1635 Object &ob)
1636{
1637 SculptSession &ss = *ob.sculpt;
1638
1639 if (!is_enabled(sd, ob, brush)) {
1640 return nullptr;
1641 }
1642
1643 std::unique_ptr<Cache> automasking = std::make_unique<Cache>();
1644 cache_settings_update(*automasking, ob, sd, brush);
1646
1647 int mode = calc_effective_bits(sd, brush);
1648
1650 if (mode & BRUSH_AUTOMASKING_TOPOLOGY && ss.active_vert_index() != -1) {
1652 automasking->settings.initial_island_nr = islands::vert_id_get(ss, ss.active_vert_index());
1653 }
1654
1655 const int verts_num = SCULPT_vertex_count_get(ob);
1656
1658 automasking->occlusion = Array<Cache::OcclusionValue>(verts_num,
1660 }
1661
1662 if (mode & BRUSH_AUTOMASKING_CAVITY_ALL) {
1664 if (brush) {
1666 }
1667
1669 }
1670 automasking->cavity_factor = Array<float>(verts_num, -1.0f);
1671 }
1672
1673 /* Avoid precomputing data on the vertex level if the current auto-masking modes do not require
1674 * it to function. */
1675 if (!needs_factors_cache(sd, brush)) {
1676 return automasking;
1677 }
1678
1679 /* Topology builds up the mask from zero which other modes can subtract from.
1680 * If it isn't enabled, initialize to 1. */
1681 const float initial_value = !(mode & BRUSH_AUTOMASKING_TOPOLOGY) ? 1.0f : 0.0f;
1682 automasking->factor = Array<float>(verts_num, initial_value);
1683 MutableSpan<float> factors = automasking->factor;
1684
1685 /* Additive modes. */
1686 if (mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) {
1688
1689 automasking->settings.topology_use_brush_limit = is_constrained_by_radius(brush);
1691 }
1692
1693 if (mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) {
1695 init_face_sets_masking(sd, ob, factors);
1696 }
1697
1698 const int steps = boundary_propagation_steps(sd, brush);
1702 }
1706 }
1707
1708 /* Subtractive modes. */
1709 int normal_bits = calc_effective_bits(sd, brush) &
1711
1712 if (normal_bits) {
1714 depsgraph, *automasking, ob, (eAutomasking_flag)normal_bits, factors);
1715 }
1716
1717 return automasking;
1718}
1719
1720Cache &filter_cache_ensure(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
1721{
1722 BLI_assert(is_enabled(sd, ob, nullptr));
1723 if (ob.sculpt->filter_cache->automasking) {
1724 return *ob.sculpt->filter_cache->automasking;
1725 }
1726
1727 ob.sculpt->filter_cache->automasking = cache_init(depsgraph, sd, nullptr, ob);
1728 return *ob.sculpt->filter_cache->automasking;
1729}
1730
1732 const Sculpt &sd,
1733 const Brush *brush,
1734 Object &ob)
1735{
1736 BLI_assert(is_enabled(sd, ob, brush));
1737 if (ob.sculpt->cache->automasking) {
1738 return *ob.sculpt->cache->automasking;
1739 }
1740
1741 ob.sculpt->cache->automasking = cache_init(depsgraph, sd, brush, ob);
1742 return *ob.sculpt->cache->automasking;
1743}
1744
1746 const Object &object,
1747 const IndexMask &node_mask)
1748{
1749 if ((this->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) == 0) {
1750 return;
1751 }
1752
1753 BLI_assert(!this->cavity_factor.is_empty());
1754
1755 const SculptSession &ss = *object.sculpt;
1756 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1757 switch (pbvh.type()) {
1758 case bke::pbvh::Type::Mesh: {
1760 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1761 const Span<int> verts = nodes[i].verts();
1762 for (const int vert : verts) {
1763 calc_cavity_factor_mesh(depsgraph, *this, object, vert);
1764 }
1765 });
1766 break;
1767 }
1769 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1770 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1772 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1773 const Span<int> grids = nodes[i].grids();
1774 for (const int grid : grids) {
1775 for (const int vert : bke::ccg::grid_range(subdiv_ccg.grid_area, grid)) {
1776 calc_cavity_factor_grids(key, *this, object, vert);
1777 }
1778 }
1779 });
1780 break;
1781 }
1784 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1785 const Set<BMVert *, 0> verts = nodes[i].bm_unique_verts_;
1786 for (BMVert *vert : verts) {
1787 calc_cavity_factor_bmesh(*this, vert, BM_elem_index_get(vert));
1788 }
1789 });
1790 }
1791 }
1792}
1793
1794} // namespace blender::ed::sculpt_paint::auto_mask
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
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.
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float pow2f(float x)
MINLINE float signf(float f)
#define M_PI
#define BLI_SCOPED_DEFER(function_to_defer)
#define CLAMP(a, b, c)
#define ELEM(...)
eAutomasking_flag
@ BRUSH_AUTOMASKING_BRUSH_NORMAL
@ BRUSH_AUTOMASKING_CAVITY_NORMAL
@ BRUSH_AUTOMASKING_VIEW_OCCLUSION
@ BRUSH_AUTOMASKING_BOUNDARY_EDGES
@ BRUSH_AUTOMASKING_CAVITY_USE_CURVE
@ BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS
@ BRUSH_AUTOMASKING_FACE_SETS
@ BRUSH_AUTOMASKING_VIEW_NORMAL
@ BRUSH_AUTOMASKING_TOPOLOGY
@ BRUSH_AUTOMASKING_CAVITY_ALL
@ BRUSH_AUTOMASKING_CAVITY_INVERTED
@ SCULPT_BRUSH_TYPE_THUMB
@ SCULPT_BRUSH_TYPE_GRAB
@ SCULPT_BRUSH_TYPE_DRAW_FACE_SETS
@ SCULPT_BRUSH_TYPE_ROTATE
@ PAINT_FALLOFF_SHAPE_TUBE
@ CD_PROP_INT32
ePaintSymmetryFlags
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
#define BM_elem_index_get(ele)
BMesh * bm
int BM_mesh_elem_count(BMesh *bm, const char htype)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
#define BM_VERT
BPy_StructRNA * depsgraph
static T sum(const btAlignedObjectArray< T > &items)
bool is_empty() const
Definition BLI_array.hh:264
AttributeSet attributes
bool is_empty() const
Definition BLI_array.hh:264
bool contains(const Key &key) const
Definition BLI_set.hh:310
void add_new(const Key &key)
Definition BLI_set.hh:233
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
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
nullptr float
static float verts[][3]
static float normals[][3]
constexpr T sign(T) RET
static char faces[256]
IndexRange grid_range(const int grid_area, const int grid)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
static void calc_blurred_cavity_mesh(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const int steps, const int vert, MutableSpan< float > cavity_factors)
static int calc_effective_bits(const Sculpt &sd, const Brush *brush)
static float calc_brush_normal_factor(const Cache &automasking, const Object &object, const float3 &normal)
static float normal_calc(const float3 &compare_normal, const float3 &normal, float limit_lower, float limit_upper)
static void calc_cavity_factor_bmesh(const Cache &automasking, BMVert *vert, const int vert_i)
static bool calc_view_occlusion_factor(const Depsgraph &depsgraph, Cache &automasking, const Object &object, const int vert, const float3 &vert_position)
static void init_face_sets_masking(const Sculpt &sd, Object &ob, MutableSpan< float > factors)
static void calc_cavity_factor_mesh(const Depsgraph &depsgraph, const Cache &automasking, const Object &object, const int vert)
static void init_boundary_masking(Object &object, const Depsgraph &depsgraph, const BoundaryAutomaskMode mode, const int propagation_steps, MutableSpan< float > factors)
const Cache * active_cache_get(const SculptSession &ss)
static float calc_view_normal_factor(const Cache &automasking, const Object &object, const float3 &normal)
static void fill_topology_automasking_factors_grids(const Sculpt &sd, Object &ob, const SubdivCCG &subdiv_ccg, MutableSpan< float > factors)
Cache & stroke_cache_ensure(const Depsgraph &depsgraph, const Sculpt &sd, const Brush *brush, Object &ob)
static void init_boundary_masking_bmesh(Object &object, const BoundaryAutomaskMode mode, const int propagation_steps, MutableSpan< float > factors)
Cache & filter_cache_ensure(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
static bool needs_factors_cache(const Sculpt &sd, const Brush *brush)
static void normal_occlusion_automasking_fill(const Depsgraph &depsgraph, Cache &automasking, Object &ob, eAutomasking_flag mode, MutableSpan< float > factors)
static void calc_blurred_cavity_grids(const Object &object, const Cache &automasking, const int steps, const SubdivCCGCoord vert, MutableSpan< float > cavity_factors)
static void fill_topology_automasking_factors_mesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const Span< float3 > vert_positions, MutableSpan< float > factors)
static void init_boundary_masking_mesh(Object &object, const Depsgraph &depsgraph, const BoundaryAutomaskMode mode, const int propagation_steps, MutableSpan< float > factors)
static void fill_topology_automasking_factors_bmesh(const Sculpt &sd, Object &ob, BMesh &bm, MutableSpan< float > factors)
static void cache_settings_update(Cache &automasking, Object &object, const Sculpt &sd, const Brush *brush)
static void init_boundary_masking_grids(Object &object, const BoundaryAutomaskMode mode, const int propagation_steps, MutableSpan< float > factors)
static void calc_blurred_cavity_bmesh(const Cache &automasking, const int steps, BMVert *vert, MutableSpan< float > cavity_factors)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
bool is_enabled(const Sculpt &sd, const Object &object, const Brush *br)
static void fill_topology_automasking_factors(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, 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 int boundary_propagation_steps(const Sculpt &sd, const Brush *brush)
static float calc_cavity_factor(const Cache &automasking, float factor)
static bool is_constrained_by_radius(const Brush *br)
bool mode_enabled(const Sculpt &sd, const Brush *br, eAutomasking_flag mode)
std::unique_ptr< Cache > cache_init(const Depsgraph &depsgraph, const Sculpt &sd, const Brush *brush, Object &ob)
static float process_cavity_factor(const Cache &automasking, float factor)
static void calc_cavity_factor_grids(const CCGKey &key, const Cache &automasking, const Object &object, const int vert)
bool vert_is_boundary(const GroupedSpan< int > vert_to_face_map, const Span< bool > hide_poly, const BitSpan boundary, const int vert)
Definition sculpt.cc:483
void ensure_boundary_info(Object &object)
Definition sculpt.cc:6073
bool stroke_is_dyntopo(const Object &object, const Brush &brush)
Definition sculpt.cc:850
int vert_face_set_get(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert)
Definition sculpt.cc:230
bool vert_has_unique_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, int vert)
Definition sculpt.cc:292
bool vert_has_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert, const int face_set)
Definition sculpt.cc:252
int active_face_set_get(const Object &object)
Definition sculpt.cc:196
void ensure_cache(Object &object)
Definition sculpt.cc:6317
int vert_id_get(const SculptSession &ss, const int vert)
Definition sculpt.cc:6184
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:141
Vector< int > find_symm_verts_grids(const Object &object, const int original_vert, const float max_distance)
Vector< BMVert *, 64 > BMeshNeighborVerts
std::optional< OrigPositionData > orig_position_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
void orig_position_data_gather_bmesh(const BMLog &bm_log, const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions, MutableSpan< float3 > normals)
Vector< int > find_symm_verts_mesh(const Depsgraph &depsgraph, const Object &object, const int original_vert, const float max_distance)
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
bool vertex_is_occluded(const Depsgraph &depsgraph, const Object &object, const float3 &position, bool original)
Definition sculpt.cc:6128
std::optional< OrigPositionData > orig_position_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:429
Vector< int > find_symm_verts_bmesh(const Object &object, const int original_vert, const float max_distance)
T safe_divide(const T &a, const T &b)
T distance(const T &a, const T &b)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T rcp(const T &a)
T safe_acos(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< float, 3 > float3
#define fabsf
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:184
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:151
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], const float br_co[3], float radius, char symm)
Definition sculpt.cc:742
float co[3]
float no[3]
float automasking_cavity_factor
char sculpt_brush_type
float automasking_view_normal_limit
int automasking_flags
int automasking_cavity_blur_steps
int automasking_boundary_edges_propagation_steps
char falloff_shape
struct CurveMapping * automasking_cavity_curve
float automasking_start_normal_limit
float automasking_start_normal_falloff
float automasking_view_normal_falloff
int grid_area
Definition BKE_ccg.hh:35
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
BMLog * bm_log
Definition BKE_paint.hh:392
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:418
SculptVertexInfo vertex_info
Definition BKE_paint.hh:462
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
ActiveVert active_vert() const
Definition paint.cc:2367
int active_vert_index() const
Definition paint.cc:2377
blender::BitVector boundary
Definition BKE_paint.hh:334
float automasking_start_normal_falloff
int automasking_boundary_edges_propagation_steps
float automasking_view_normal_limit
float automasking_cavity_factor
int automasking_cavity_blur_steps
float automasking_start_normal_limit
struct CurveMapping * automasking_cavity_curve
int automasking_flags
float automasking_view_normal_falloff
int to_index(const CCGKey &key) const
static SubdivCCGCoord from_index(const CCGKey &key, int index)
SubdivCCGNeighborCoords coords
blender::Array< blender::float3 > normals
blender::Array< blender::float3 > positions
std::unique_ptr< auto_mask::Cache > automasking
void calc_cavity_factor(const Depsgraph &depsgraph, const Object &object, const IndexMask &node_mask)
std::unique_ptr< auto_mask::Cache > automasking
void execute(Object &object, FunctionRef< bool(BMVert *from_v, BMVert *to_v)> func)
void execute(Object &object, const SubdivCCG &subdiv_ccg, FunctionRef< bool(SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool is_duplicate)> func)
void execute(Object &object, GroupedSpan< int > vert_to_face_map, FunctionRef< bool(int from_v, int to_v)> func)
i
Definition text_draw.cc:230