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