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