Blender V5.0
sculpt_boundary.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#include "sculpt_boundary.hh"
9
10#include "BLI_array_utils.hh"
12#include "BLI_math_geom.h"
14#include "BLI_math_vector.hh"
15
16#include "DNA_brush_types.h"
17#include "DNA_mesh_types.h"
18#include "DNA_object_types.h"
19
20#include "BKE_attribute.hh"
21#include "BKE_brush.hh"
22#include "BKE_ccg.hh"
23#include "BKE_colortools.hh"
24#include "BKE_paint.hh"
25#include "BKE_paint_bvh.hh"
26
27#include "mesh_brush_common.hh"
28#include "paint_intern.hh"
29#include "sculpt_automask.hh"
30#include "sculpt_cloth.hh"
31#include "sculpt_flood_fill.hh"
32#include "sculpt_intern.hh"
33
34#include "GPU_immediate.hh"
35#include "GPU_state.hh"
36
37#include "bmesh.hh"
38
39#include <cstdlib>
40
42
43static bool check_counts(const int neighbor_count, const int boundary_vertex_count)
44{
45 /* Corners are ambiguous as it can't be decide which boundary should be active. The flood fill
46 * should also stop at corners. */
47 if (neighbor_count <= 2) {
48 return false;
49 }
50
51 /* Non manifold geometry in the mesh boundary.
52 * The deformation result will be unpredictable and not very useful. */
53 if (boundary_vertex_count > 2) {
54 return false;
55 }
56
57 return true;
58}
59
65 const Span<int> corner_verts,
66 const GroupedSpan<int> vert_to_face,
67 const Span<bool> hide_vert,
68 const Span<bool> hide_poly,
69 const BitSpan boundary,
70 const int initial_vert)
71{
72 if (!hide_vert.is_empty() && hide_vert[initial_vert]) {
73 return false;
74 }
75
76 int neighbor_count = 0;
77 int boundary_vertex_count = 0;
78
79 Vector<int> neighbors;
80 for (const int neighbor : vert_neighbors_get_mesh(
81 faces, corner_verts, vert_to_face, hide_poly, initial_vert, neighbors))
82 {
83 if (hide_vert.is_empty() || !hide_vert[neighbor]) {
84 neighbor_count++;
85 if (boundary::vert_is_boundary(vert_to_face, hide_poly, boundary, neighbor)) {
86 boundary_vertex_count++;
87 }
88 }
89 }
90
91 return check_counts(neighbor_count, boundary_vertex_count);
92}
93
95 const Span<int> corner_verts,
96 const SubdivCCG &subdiv_ccg,
97 const BitSpan boundary,
98 const SubdivCCGCoord initial_vert)
99{
100 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
101 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
102 if (!grid_hidden.is_empty() && grid_hidden[initial_vert.grid_index][initial_vert.to_index(key)])
103 {
104 return false;
105 }
106
107 SubdivCCGNeighbors neighbors;
108 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, initial_vert, false, neighbors);
109
110 int neighbor_count = 0;
111 int boundary_vertex_count = 0;
112 for (const SubdivCCGCoord neighbor : neighbors.coords) {
113 if (grid_hidden.is_empty() || !grid_hidden[neighbor.grid_index][neighbor.to_index(key)]) {
114 neighbor_count++;
115 if (boundary::vert_is_boundary(faces, corner_verts, boundary, subdiv_ccg, neighbor)) {
116 boundary_vertex_count++;
117 }
118 }
119 }
120
121 return check_counts(neighbor_count, boundary_vertex_count);
122}
123
125{
126 if (BM_elem_flag_test(&initial_vert, BM_ELEM_HIDDEN)) {
127 return false;
128 }
129
130 int neighbor_count = 0;
131 int boundary_vertex_count = 0;
132
133 BMeshNeighborVerts neighbors;
134 for (BMVert *neighbor : vert_neighbors_get_bmesh(initial_vert, neighbors)) {
135 if (!BM_elem_flag_test(neighbor, BM_ELEM_HIDDEN)) {
136 neighbor_count++;
137 if (boundary::vert_is_boundary(neighbor)) {
138 boundary_vertex_count++;
139 }
140 }
141 }
142
143 return check_counts(neighbor_count, boundary_vertex_count);
144}
145
146/* -------------------------------------------------------------------- */
153static std::optional<int> get_closest_boundary_vert_mesh(Object &object,
154 const GroupedSpan<int> vert_to_face,
155 const Span<float3> vert_positions,
156 const Span<bool> hide_vert,
157 const Span<bool> hide_poly,
158 const BitSpan boundary,
159 const int initial_vert,
160 const float radius)
161{
162 if (boundary::vert_is_boundary(vert_to_face, hide_poly, boundary, initial_vert)) {
163 return initial_vert;
164 }
165
166 flood_fill::FillDataMesh flood_fill(vert_positions.size());
167 flood_fill.add_initial(initial_vert);
168
169 const float3 initial_vert_position = vert_positions[initial_vert];
170 const float radius_sq = radius * radius;
171
172 std::optional<int> boundary_initial_vert;
173 int boundary_initial_vert_steps = std::numeric_limits<int>::max();
174 Array<int> floodfill_steps(vert_positions.size(), 0);
175
176 flood_fill.execute(object, vert_to_face, [&](int from_v, int to_v) {
177 if (!hide_vert.is_empty() && hide_vert[from_v]) {
178 return false;
179 }
180
181 floodfill_steps[to_v] = floodfill_steps[from_v] + 1;
182
183 if (boundary::vert_is_boundary(vert_to_face, hide_poly, boundary, to_v)) {
184 if (floodfill_steps[to_v] < boundary_initial_vert_steps) {
185 boundary_initial_vert_steps = floodfill_steps[to_v];
186 boundary_initial_vert = to_v;
187 }
188 }
189
190 const float len_sq = math::distance_squared(initial_vert_position, vert_positions[to_v]);
191 return len_sq < radius_sq;
192 });
193
194 return boundary_initial_vert;
195}
196
197static std::optional<SubdivCCGCoord> get_closest_boundary_vert_grids(
198 Object &object,
200 const Span<int> corner_verts,
201 const SubdivCCG &subdiv_ccg,
202 const BitSpan boundary,
203 const SubdivCCGCoord initial_vert,
204 const float radius)
205{
206 if (boundary::vert_is_boundary(faces, corner_verts, boundary, subdiv_ccg, initial_vert)) {
207 return initial_vert;
208 }
209
210 const Span<float3> positions = subdiv_ccg.positions;
211 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
212
214 flood_fill.add_initial(initial_vert);
215
216 const float3 initial_vert_position = positions[initial_vert.to_index(key)];
217 const float radius_sq = radius * radius;
218
219 int boundary_initial_vert_steps = std::numeric_limits<int>::max();
220 Array<int> floodfill_steps(positions.size(), 0);
221 std::optional<SubdivCCGCoord> boundary_initial_vert;
222
223 flood_fill.execute(
224 object, subdiv_ccg, [&](SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool is_duplicate) {
225 const int to_v_index = to_v.to_index(key);
226 const int from_v_index = from_v.to_index(key);
227
228 if (!subdiv_ccg.grid_hidden.is_empty()) {
229 return false;
230 }
231
232 if (is_duplicate) {
233 floodfill_steps[to_v_index] = floodfill_steps[from_v_index];
234 }
235 else {
236 floodfill_steps[to_v_index] = floodfill_steps[from_v_index] + 1;
237 }
238
239 if (boundary::vert_is_boundary(faces, corner_verts, boundary, subdiv_ccg, to_v)) {
240 if (floodfill_steps[to_v_index] < boundary_initial_vert_steps) {
241 boundary_initial_vert_steps = floodfill_steps[to_v_index];
242 boundary_initial_vert = to_v;
243 }
244 }
245
246 const float len_sq = math::distance_squared(initial_vert_position,
247 positions[to_v.to_index(key)]);
248 return len_sq < radius_sq;
249 });
250
251 return boundary_initial_vert;
252}
253
254static std::optional<BMVert *> get_closest_boundary_vert_bmesh(Object &object,
255 BMesh *bm,
256 BMVert &initial_vert,
257 const float radius)
258{
259 if (boundary::vert_is_boundary(&initial_vert)) {
260 return &initial_vert;
261 }
262
263 const int num_verts = BM_mesh_elem_count(bm, BM_VERT);
265 flood_fill.add_initial(&initial_vert);
266
267 const float3 initial_vert_position = initial_vert.co;
268 const float radius_sq = radius * radius;
269
270 int boundary_initial_vert_steps = std::numeric_limits<int>::max();
271 Array<int> floodfill_steps(num_verts, 0);
272 std::optional<BMVert *> boundary_initial_vert;
273
274 flood_fill.execute(object, [&](BMVert *from_v, BMVert *to_v) {
275 const int from_v_i = BM_elem_index_get(from_v);
276 const int to_v_i = BM_elem_index_get(to_v);
277
279 return false;
280 }
281
282 floodfill_steps[to_v_i] = floodfill_steps[from_v_i] + 1;
283
284 if (boundary::vert_is_boundary(to_v)) {
285 if (floodfill_steps[to_v_i] < boundary_initial_vert_steps) {
286 boundary_initial_vert_steps = floodfill_steps[to_v_i];
287 boundary_initial_vert = to_v;
288 }
289 }
290
291 const float len_sq = math::distance_squared(initial_vert_position, float3(to_v->co));
292 return len_sq < radius_sq;
293 });
294
295 return boundary_initial_vert;
296}
297
299
300/* -------------------------------------------------------------------- */
303
304/* Used to allocate the memory of the boundary index arrays. This was decided considered the most
305 * common use cases for the brush deformers, taking into account how many vertices those
306 * deformations usually need in the boundary. */
307constexpr int BOUNDARY_INDICES_BLOCK_SIZE = 300;
308
310 const int new_index,
311 const float distance,
313{
314 boundary.verts.append(new_index);
315
316 boundary.distance.add(new_index, distance);
317 included_verts.add(new_index);
318};
319
323static void indices_init_mesh(Object &object,
325 const Span<int> corner_verts,
326 const GroupedSpan<int> vert_to_face,
327 const Span<bool> hide_vert,
328 const Span<bool> hide_poly,
329 const BitSpan boundary_verts,
330 const Span<float3> vert_positions,
331 const int initial_boundary_vert,
333{
334 flood_fill::FillDataMesh flood_fill(vert_positions.size());
335
337 add_index(boundary, initial_boundary_vert, 0.0f, included_verts);
338 flood_fill.add_initial(initial_boundary_vert);
339
340 flood_fill.execute(object, vert_to_face, [&](const int from_v, const int to_v) {
341 const float3 from_v_co = vert_positions[from_v];
342 const float3 to_v_co = vert_positions[to_v];
343
344 if (!boundary::vert_is_boundary(vert_to_face, hide_poly, boundary_verts, to_v)) {
345 return false;
346 }
347 const float edge_len = len_v3v3(from_v_co, to_v_co);
348 const float distance_boundary_to_dst = boundary.distance.lookup_default(from_v, 0.0f) +
349 edge_len;
350 add_index(boundary, to_v, distance_boundary_to_dst, included_verts);
351 boundary.edges.append({from_v_co, to_v_co});
353 faces, corner_verts, vert_to_face, hide_vert, hide_poly, boundary_verts, to_v);
354 });
355}
356
357static void indices_init_grids(Object &object,
359 const Span<int> corner_verts,
360 const SubdivCCG &subdiv_ccg,
361 const BitSpan boundary_verts,
362 const SubdivCCGCoord initial_vert,
364{
365 const Span<float3> positions = subdiv_ccg.positions;
366 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
368
369 const int initial_boundary_index = initial_vert.to_index(key);
371 add_index(boundary, initial_boundary_index, 0.0f, included_verts);
372 flood_fill.add_initial(initial_vert);
373
374 flood_fill.execute(
375 object,
376 subdiv_ccg,
377 [&](const SubdivCCGCoord from_v, const SubdivCCGCoord to_v, const bool is_duplicate) {
378 const int from_v_i = from_v.to_index(key);
379 const int to_v_i = to_v.to_index(key);
380
381 const float3 &from_v_co = positions[from_v_i];
382 const float3 &to_v_co = positions[to_v_i];
383
384 if (!boundary::vert_is_boundary(faces, corner_verts, boundary_verts, subdiv_ccg, to_v)) {
385 return false;
386 }
387 const float edge_len = len_v3v3(from_v_co, to_v_co);
388 const float distance_boundary_to_dst = boundary.distance.lookup_default(from_v_i, 0.0f) +
389 edge_len;
390 add_index(boundary, to_v_i, distance_boundary_to_dst, included_verts);
391 if (!is_duplicate) {
392 boundary.edges.append({from_v_co, to_v_co});
393 }
395 faces, corner_verts, subdiv_ccg, boundary_verts, to_v);
396 });
397}
398
399static void indices_init_bmesh(Object &object,
400 BMesh *bm,
401 BMVert &initial_boundary_vert,
403{
404 const int num_verts = BM_mesh_elem_count(bm, BM_VERT);
406
407 const int initial_boundary_index = BM_elem_index_get(&initial_boundary_vert);
409 add_index(boundary, initial_boundary_index, 0.0f, included_verts);
410 flood_fill.add_initial(&initial_boundary_vert);
411
412 flood_fill.execute(object, [&](BMVert *from_v, BMVert *to_v) {
413 const int from_v_i = BM_elem_index_get(from_v);
414 const int to_v_i = BM_elem_index_get(to_v);
415
416 const float3 from_v_co = from_v->co;
417 const float3 to_v_co = to_v->co;
418
419 if (!boundary::vert_is_boundary(to_v)) {
420 return false;
421 }
422 const float edge_len = len_v3v3(from_v_co, to_v_co);
423 const float distance_boundary_to_dst = boundary.distance.lookup_default(from_v_i, 0.0f) +
424 edge_len;
425 add_index(boundary, to_v_i, distance_boundary_to_dst, included_verts);
426 boundary.edges.append({from_v_co, to_v_co});
428 });
429}
430
432
433/* -------------------------------------------------------------------- */
436
437#define BOUNDARY_VERTEX_NONE -1
438#define BOUNDARY_STEPS_NONE -1
439
447 Span<int> corner_verts,
448 GroupedSpan<int> vert_to_face,
449 Span<float3> vert_positions,
450 Span<bool> hide_vert,
451 Span<bool> hide_poly,
452 const int initial_vert_i,
453 const float radius,
455{
456 boundary.edit_info.original_vertex_i = Array<int>(vert_positions.size(), BOUNDARY_VERTEX_NONE);
457 boundary.edit_info.propagation_steps_num = Array<int>(vert_positions.size(),
459 boundary.edit_info.strength_factor = Array<float>(vert_positions.size(), 0.0f);
460
461 std::queue<int> current_iteration;
462
463 for (const int i : boundary.verts.index_range()) {
464 const int vert = boundary.verts[i];
465 const int index = boundary.verts[i];
466
467 boundary.edit_info.original_vertex_i[index] = index;
468 boundary.edit_info.propagation_steps_num[index] = 0;
469
470 current_iteration.push(vert);
471 }
472
473 int propagation_steps_num = 0;
474 float accum_distance = 0.0f;
475
476 std::queue<int> next_iteration;
477
478 while (true) {
479 /* Stop adding steps to edit info. This happens when a steps is further away from the boundary
480 * than the brush radius or when the entire mesh was already processed. */
481 if (accum_distance > radius || current_iteration.empty()) {
482 boundary.max_propagation_steps = propagation_steps_num;
483 break;
484 }
485
486 while (!current_iteration.empty()) {
487 const int from_v = current_iteration.front();
488 current_iteration.pop();
489
490 Vector<int> neighbors;
491 for (const int neighbor : vert_neighbors_get_mesh(
492 faces, corner_verts, vert_to_face, hide_poly, from_v, neighbors))
493 {
494 if ((!hide_vert.is_empty() && hide_vert[from_v]) ||
495 boundary.edit_info.propagation_steps_num[neighbor] != BOUNDARY_STEPS_NONE)
496 {
497 continue;
498 }
499
500 boundary.edit_info.original_vertex_i[neighbor] =
501 boundary.edit_info.original_vertex_i[from_v];
502
503 boundary.edit_info.propagation_steps_num[neighbor] =
504 boundary.edit_info.propagation_steps_num[from_v] + 1;
505
506 next_iteration.push(neighbor);
507
508 /* Check the distance using the vertex that was propagated from the initial vertex that
509 * was used to initialize the boundary. */
510 if (boundary.edit_info.original_vertex_i[from_v] == initial_vert_i) {
511 boundary.pivot_position = vert_positions[neighbor];
512 accum_distance += math::distance(vert_positions[from_v], boundary.pivot_position);
513 }
514 }
515 }
516
517 /* Copy the new vertices to the queue to be processed in the next iteration. */
518 while (!next_iteration.empty()) {
519 const int next_v = next_iteration.front();
520 next_iteration.pop();
521 current_iteration.push(next_v);
522 }
523
524 propagation_steps_num++;
525 }
526}
527
528static void edit_data_init_grids(const SubdivCCG &subdiv_ccg,
529 const int initial_vert_i,
530 const float radius,
532{
533 const Span<float3> positions = subdiv_ccg.positions;
534 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
535
536 boundary.edit_info.original_vertex_i = Array<int>(positions.size(), BOUNDARY_VERTEX_NONE);
537 boundary.edit_info.propagation_steps_num = Array<int>(positions.size(), BOUNDARY_STEPS_NONE);
538 boundary.edit_info.strength_factor = Array<float>(positions.size(), 0.0f);
539
540 std::queue<SubdivCCGCoord> current_iteration;
541
542 for (const int i : boundary.verts.index_range()) {
543 const SubdivCCGCoord vert = SubdivCCGCoord::from_index(key, boundary.verts[i]);
544
545 const int index = boundary.verts[i];
546
547 boundary.edit_info.original_vertex_i[index] = index;
548 boundary.edit_info.propagation_steps_num[index] = 0;
549
550 SubdivCCGNeighbors neighbors;
551 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, vert, true, neighbors);
552 for (SubdivCCGCoord neighbor : neighbors.duplicates()) {
553 boundary.edit_info.original_vertex_i[neighbor.to_index(key)] = index;
554 }
555
556 current_iteration.push(vert);
557 }
558
559 int propagation_steps_num = 0;
560 float accum_distance = 0.0f;
561
562 std::queue<SubdivCCGCoord> next_iteration;
563
564 while (true) {
565 /* Stop adding steps to edit info. This happens when a steps is further away from the boundary
566 * than the brush radius or when the entire mesh was already processed. */
567 if (accum_distance > radius || current_iteration.empty()) {
568 boundary.max_propagation_steps = propagation_steps_num;
569 break;
570 }
571
572 while (!current_iteration.empty()) {
573 const SubdivCCGCoord from_v = current_iteration.front();
574 current_iteration.pop();
575
576 const int from_v_i = from_v.to_index(key);
577
578 SubdivCCGNeighbors neighbors;
579 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, from_v, true, neighbors);
580
581 for (const SubdivCCGCoord neighbor : neighbors.duplicates()) {
582 const int neighbor_idx = neighbor.to_index(key);
583 const int index_in_grid = CCG_grid_xy_to_index(key.grid_size, neighbor.x, neighbor.y);
584
585 const bool is_hidden = !subdiv_ccg.grid_hidden.is_empty() &&
586 subdiv_ccg.grid_hidden[neighbor.grid_index][index_in_grid];
587 if (is_hidden ||
588 boundary.edit_info.propagation_steps_num[neighbor_idx] != BOUNDARY_STEPS_NONE)
589 {
590 continue;
591 }
592 boundary.edit_info.original_vertex_i[neighbor_idx] =
593 boundary.edit_info.original_vertex_i[from_v_i];
594
595 boundary.edit_info.propagation_steps_num[neighbor_idx] =
596 boundary.edit_info.propagation_steps_num[from_v_i];
597 }
598
599 for (const SubdivCCGCoord neighbor : neighbors.unique()) {
600 const int neighbor_idx = neighbor.to_index(key);
601 const int index_in_grid = CCG_grid_xy_to_index(key.grid_size, neighbor.x, neighbor.y);
602
603 const bool is_hidden = !subdiv_ccg.grid_hidden.is_empty() &&
604 subdiv_ccg.grid_hidden[neighbor.grid_index][index_in_grid];
605 if (is_hidden ||
606 boundary.edit_info.propagation_steps_num[neighbor_idx] != BOUNDARY_STEPS_NONE)
607 {
608 continue;
609 }
610 boundary.edit_info.original_vertex_i[neighbor_idx] =
611 boundary.edit_info.original_vertex_i[from_v_i];
612
613 boundary.edit_info.propagation_steps_num[neighbor_idx] =
614 boundary.edit_info.propagation_steps_num[from_v_i] + 1;
615
616 next_iteration.push(neighbor);
617
618 /* When copying the data to the neighbor for the next iteration, it has to be copied to
619 * all its duplicates too. This is because it is not possible to know if the updated
620 * neighbor or one if its uninitialized duplicates is going to come first in order to
621 * copy the data in the from_v neighbor iterator. */
622
623 SubdivCCGNeighbors neighbor_duplicates;
624 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, neighbor, true, neighbor_duplicates);
625
626 for (const SubdivCCGCoord coord : neighbor_duplicates.duplicates()) {
627 const int neighbor_duplicate_index = coord.to_index(key);
628 boundary.edit_info.original_vertex_i[neighbor_duplicate_index] =
629 boundary.edit_info.original_vertex_i[from_v_i];
630 boundary.edit_info.propagation_steps_num[neighbor_duplicate_index] =
631 boundary.edit_info.propagation_steps_num[from_v_i] + 1;
632 }
633
634 /* Check the distance using the vertex that was propagated from the initial vertex that
635 * was used to initialize the boundary. */
636 if (boundary.edit_info.original_vertex_i[from_v_i] == initial_vert_i) {
637 boundary.pivot_position = positions[neighbor_idx];
638 accum_distance += math::distance(positions[from_v_i], boundary.pivot_position);
639 }
640 }
641 }
642
643 /* Copy the new vertices to the queue to be processed in the next iteration. */
644 while (!next_iteration.empty()) {
645 const SubdivCCGCoord next_v = next_iteration.front();
646 next_iteration.pop();
647 current_iteration.push(next_v);
648 }
649
650 propagation_steps_num++;
651 }
652}
653
655 const int initial_vert_i,
656 const float radius,
658{
659 const int num_verts = BM_mesh_elem_count(bm, BM_VERT);
660
661 boundary.edit_info.original_vertex_i = Array<int>(num_verts, BOUNDARY_VERTEX_NONE);
662 boundary.edit_info.propagation_steps_num = Array<int>(num_verts, BOUNDARY_STEPS_NONE);
663 boundary.edit_info.strength_factor = Array<float>(num_verts, 0.0f);
664
665 std::queue<BMVert *> current_iteration;
666
667 for (const int i : boundary.verts.index_range()) {
668 const int index = boundary.verts[i];
669 BMVert *vert = BM_vert_at_index(bm, index);
670
671 boundary.edit_info.original_vertex_i[index] = index;
672 boundary.edit_info.propagation_steps_num[index] = 0;
673
674 /* This ensures that all duplicate vertices in the boundary have the same original_vertex
675 * index, so the deformation for them will be the same. */
676 current_iteration.push(vert);
677 }
678
679 int propagation_steps_num = 0;
680 float accum_distance = 0.0f;
681
682 std::queue<BMVert *> next_iteration;
683
684 while (true) {
685 /* Stop adding steps to edit info. This happens when a steps is further away from the boundary
686 * than the brush radius or when the entire mesh was already processed. */
687 if (accum_distance > radius || current_iteration.empty()) {
688 boundary.max_propagation_steps = propagation_steps_num;
689 break;
690 }
691
692 while (!current_iteration.empty()) {
693 BMVert *from_v = current_iteration.front();
694 current_iteration.pop();
695
696 const int from_v_i = BM_elem_index_get(from_v);
697
698 BMeshNeighborVerts neighbors;
699 for (BMVert *neighbor : vert_neighbors_get_bmesh(*from_v, neighbors)) {
700 const int neighbor_idx = BM_elem_index_get(neighbor);
701 if (BM_elem_flag_test(neighbor, BM_ELEM_HIDDEN) ||
702 boundary.edit_info.propagation_steps_num[neighbor_idx] != BOUNDARY_STEPS_NONE)
703 {
704 continue;
705 }
706 boundary.edit_info.original_vertex_i[neighbor_idx] =
707 boundary.edit_info.original_vertex_i[from_v_i];
708
709 boundary.edit_info.propagation_steps_num[neighbor_idx] =
710 boundary.edit_info.propagation_steps_num[from_v_i] + 1;
711
712 next_iteration.push(neighbor);
713
714 /* Check the distance using the vertex that was propagated from the initial vertex that
715 * was used to initialize the boundary. */
716 if (boundary.edit_info.original_vertex_i[from_v_i] == initial_vert_i) {
717 boundary.pivot_position = neighbor->co;
718 accum_distance += math::distance(float3(from_v->co), boundary.pivot_position);
719 }
720 }
721 }
722
723 /* Copy the new vertices to the queue to be processed in the next iteration. */
724 while (!next_iteration.empty()) {
725 BMVert *next_v = next_iteration.front();
726 next_iteration.pop();
727 current_iteration.push(next_v);
728 }
729
730 propagation_steps_num++;
731 }
732}
733
735
736/* -------------------------------------------------------------------- */
741
742/* These functions initialize the required vectors for the desired deformation using the
743 * SculptBoundaryEditInfo. They calculate the data using the vertices that have the
744 * max_propagation_steps value and them this data is copied to the rest of the vertices using the
745 * original vertex index. */
746static void bend_data_init_mesh(const Span<float3> vert_positions,
747 const Span<float3> vert_normals,
749{
750 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
751 boundary.edit_info.propagation_steps_num.size());
752 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
753 boundary.edit_info.strength_factor.size());
754
755 const int num_elements = boundary.edit_info.strength_factor.size();
756
757 boundary.bend.pivot_rotation_axis = Array<float3>(num_elements, float3(0));
758 boundary.bend.pivot_positions = Array<float3>(num_elements, float3(0));
759
760 for (const int i : IndexRange(num_elements)) {
761 if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
762 continue;
763 }
764
765 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
766
767 const float3 normal = vert_normals[i];
768 const float3 dir = vert_positions[orig_vert_i] - vert_positions[i];
769 boundary.bend.pivot_rotation_axis[orig_vert_i] = math::normalize(math::cross(dir, normal));
770 boundary.bend.pivot_positions[orig_vert_i] = vert_positions[i];
771 }
772
773 for (const int i : IndexRange(num_elements)) {
774 if (boundary.edit_info.propagation_steps_num[i] == BOUNDARY_STEPS_NONE) {
775 continue;
776 }
777 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
778
779 boundary.bend.pivot_positions[i] = boundary.bend.pivot_positions[orig_vert_i];
780 boundary.bend.pivot_rotation_axis[i] = boundary.bend.pivot_rotation_axis[orig_vert_i];
781 }
782}
783
785{
786 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
787 boundary.edit_info.propagation_steps_num.size());
788 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
789 boundary.edit_info.strength_factor.size());
790
791 const int num_elements = boundary.edit_info.strength_factor.size();
792
793 const Span<float3> positions = subdiv_ccg.positions;
794 const Span<float3> normals = subdiv_ccg.normals;
795
796 boundary.bend.pivot_rotation_axis = Array<float3>(num_elements, float3(0));
797 boundary.bend.pivot_positions = Array<float3>(num_elements, float3(0));
798
799 for (const int i : IndexRange(num_elements)) {
800 if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
801 continue;
802 }
803
804 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
805
806 const float3 normal = normals[i];
807 const float3 dir = positions[orig_vert_i] - positions[i];
808 boundary.bend.pivot_rotation_axis[orig_vert_i] = math::normalize(math::cross(dir, normal));
809 boundary.bend.pivot_positions[orig_vert_i] = positions[i];
810 }
811
812 for (const int i : IndexRange(num_elements)) {
813 if (boundary.edit_info.propagation_steps_num[i] == BOUNDARY_STEPS_NONE) {
814 continue;
815 }
816 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
817
818 boundary.bend.pivot_positions[i] = boundary.bend.pivot_positions[orig_vert_i];
819 boundary.bend.pivot_rotation_axis[i] = boundary.bend.pivot_rotation_axis[orig_vert_i];
820 }
821}
822
824{
825 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
826 boundary.edit_info.propagation_steps_num.size());
827 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
828 boundary.edit_info.strength_factor.size());
829
830 const int num_elements = boundary.edit_info.strength_factor.size();
831
832 boundary.bend.pivot_rotation_axis = Array<float3>(num_elements, float3(0));
833 boundary.bend.pivot_positions = Array<float3>(num_elements, float3(0));
834
835 for (const int i : IndexRange(num_elements)) {
836 if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
837 continue;
838 }
839
840 BMVert *vert = BM_vert_at_index(bm, i);
841 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
842 BMVert *orig_vert = BM_vert_at_index(bm, orig_vert_i);
843
844 const float3 normal = vert->no;
845 const float3 dir = float3(orig_vert->co) - float3(vert->co);
846 boundary.bend.pivot_rotation_axis[orig_vert_i] = math::normalize(math::cross(dir, normal));
847 boundary.bend.pivot_positions[boundary.edit_info.original_vertex_i[i]] = vert->co;
848 }
849
850 for (const int i : IndexRange(num_elements)) {
851 if (boundary.edit_info.propagation_steps_num[i] == BOUNDARY_STEPS_NONE) {
852 continue;
853 }
854 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
855 boundary.bend.pivot_positions[i] = boundary.bend.pivot_positions[orig_vert_i];
856 boundary.bend.pivot_rotation_axis[i] = boundary.bend.pivot_rotation_axis[orig_vert_i];
857 }
858}
859
860static void slide_data_init_mesh(const Span<float3> vert_positions, SculptBoundary &boundary)
861{
862 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
863 boundary.edit_info.propagation_steps_num.size());
864 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
865 boundary.edit_info.strength_factor.size());
866
867 const int num_elements = boundary.edit_info.strength_factor.size();
868 boundary.slide.directions = Array<float3>(num_elements, float3(0));
869
870 for (const int i : IndexRange(num_elements)) {
871 if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
872 continue;
873 }
874 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
875 boundary.slide.directions[orig_vert_i] = math::normalize(vert_positions[orig_vert_i] -
876 vert_positions[i]);
877 }
878
879 for (const int i : IndexRange(num_elements)) {
880 if (boundary.edit_info.propagation_steps_num[i] == BOUNDARY_STEPS_NONE) {
881 continue;
882 }
883 boundary.slide.directions[i] =
884 boundary.slide.directions[boundary.edit_info.original_vertex_i[i]];
885 }
886}
887
889{
890 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
891 boundary.edit_info.propagation_steps_num.size());
892 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
893 boundary.edit_info.strength_factor.size());
894
895 const int num_elements = boundary.edit_info.strength_factor.size();
896 const Span<float3> positions = subdiv_ccg.positions;
897
898 boundary.slide.directions = Array<float3>(num_elements, float3(0));
899
900 for (const int i : IndexRange(num_elements)) {
901 if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
902 continue;
903 }
904 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
905
906 boundary.slide.directions[orig_vert_i] = math::normalize(positions[orig_vert_i] -
907 positions[i]);
908 }
909
910 for (const int i : IndexRange(num_elements)) {
911 if (boundary.edit_info.propagation_steps_num[i] == BOUNDARY_STEPS_NONE) {
912 continue;
913 }
914 boundary.slide.directions[i] =
915 boundary.slide.directions[boundary.edit_info.original_vertex_i[i]];
916 }
917}
918
920{
921 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
922 boundary.edit_info.propagation_steps_num.size());
923 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
924 boundary.edit_info.strength_factor.size());
925
926 const int num_elements = boundary.edit_info.strength_factor.size();
927 boundary.slide.directions = Array<float3>(num_elements, float3(0));
928
929 for (const int i : IndexRange(num_elements)) {
930 if (boundary.edit_info.propagation_steps_num[i] != boundary.max_propagation_steps) {
931 continue;
932 }
933 BMVert *vert = BM_vert_at_index(bm, i);
934 const int orig_vert_i = boundary.edit_info.original_vertex_i[i];
935 BMVert *orig_vert = BM_vert_at_index(bm, orig_vert_i);
936 boundary.slide.directions[orig_vert_i] = math::normalize(float3(orig_vert->co) -
937 float3(vert->co));
938 }
939
940 for (const int i : IndexRange(num_elements)) {
941 if (boundary.edit_info.propagation_steps_num[i] == BOUNDARY_STEPS_NONE) {
942 continue;
943 }
944 boundary.slide.directions[i] =
945 boundary.slide.directions[boundary.edit_info.original_vertex_i[i]];
946 }
947}
948
950{
951 boundary.twist.pivot_position = float3(0);
952 for (const float3 &position : positions) {
953 boundary.twist.pivot_position += position;
954 }
955 boundary.twist.pivot_position *= 1.0f / boundary.verts.size();
956 boundary.twist.rotation_axis = math::normalize(boundary.pivot_position -
957 boundary.initial_vert_position);
958}
959
960static void twist_data_init_mesh(const Span<float3> vert_positions, SculptBoundary &boundary)
961{
962 Array<float3> positions(boundary.verts.size());
963 array_utils::gather(vert_positions, boundary.verts.as_span(), positions.as_mutable_span());
964 populate_twist_data(positions, boundary);
965}
966
968{
969 const Span<float3> vert_positions = subdiv_ccg.positions;
970 Array<float3> positions(boundary.verts.size());
971 array_utils::gather(vert_positions, boundary.verts.as_span(), positions.as_mutable_span());
972 populate_twist_data(positions, boundary);
973}
974
976{
977 Array<float3> positions(boundary.verts.size());
978 for (const int i : positions.index_range()) {
979 BMVert *vert = BM_vert_at_index(bm, i);
980 positions[i] = vert->co;
981 }
982 populate_twist_data(positions, boundary);
983}
984
986
987/* -------------------------------------------------------------------- */
990
991BLI_NOINLINE static void filter_uninitialized_verts(const Span<int> propagation_steps,
992 const MutableSpan<float> factors)
993{
994 BLI_assert(propagation_steps.size() == factors.size());
995
996 for (const int i : factors.index_range()) {
997 if (propagation_steps[i] == BOUNDARY_STEPS_NONE) {
998 factors[i] = 0.0f;
999 }
1000 }
1001}
1002
1025
1048
1071
1073
1074/* -------------------------------------------------------------------- */
1077
1079 const Span<float3> pivot_positions,
1080 const Span<float3> pivot_axes,
1081 const Span<float> factors,
1082 const MutableSpan<float3> new_positions)
1083{
1084 BLI_assert(positions.size() == pivot_positions.size());
1085 BLI_assert(positions.size() == pivot_axes.size());
1086 BLI_assert(positions.size() == factors.size());
1087 BLI_assert(positions.size() == new_positions.size());
1088
1089 for (const int i : positions.index_range()) {
1090 float3 from_pivot_to_pos = positions[i] - pivot_positions[i];
1091 float3 rotated;
1092 rotate_v3_v3v3fl(rotated, from_pivot_to_pos, pivot_axes[i], factors[i]);
1093 new_positions[i] = rotated + pivot_positions[i];
1094 }
1095}
1096
1097static void calc_bend_mesh(const Depsgraph &depsgraph,
1098 const Sculpt &sd,
1099 Object &object,
1100 const Span<int> vert_propagation_steps,
1101 const Span<float> vert_factors,
1102 const Span<float3> vert_pivot_positions,
1103 const Span<float3> vert_pivot_axes,
1104 const bke::pbvh::MeshNode &node,
1105 LocalDataMesh &tls,
1106 const float3 symmetry_pivot,
1107 const float strength,
1108 const eBrushDeformTarget deform_target,
1109 const PositionDeformData &position_data)
1110{
1111 SculptSession &ss = *object.sculpt;
1112 const StrokeCache &cache = *ss.cache;
1113
1114 const Span<int> verts = node.verts();
1115 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1116
1118
1119 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1120
1121 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1122
1123 const Span<int> propagation_steps = gather_data_mesh(
1124 vert_propagation_steps, verts, tls.propagation_steps);
1125
1126 filter_uninitialized_verts(propagation_steps, factors);
1127 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1128
1129 scale_factors(factors, strength);
1130
1131 const Span<float3> pivot_positions = gather_data_mesh(
1132 vert_pivot_positions, verts, tls.pivot_positions);
1133 const Span<float3> pivot_axes = gather_data_mesh(vert_pivot_axes, verts, tls.pivot_axes);
1134
1135 tls.new_positions.resize(verts.size());
1136 const MutableSpan<float3> new_positions = tls.new_positions;
1137 calc_bend_position(orig_data.positions, pivot_positions, pivot_axes, factors, new_positions);
1138
1139 switch (eBrushDeformTarget(deform_target)) {
1141 tls.translations.resize(verts.size());
1142 const MutableSpan<float3> translations = tls.translations;
1143 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1144 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1145 position_data.deform(translations, verts);
1146 break;
1147 }
1150 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1151 break;
1152 }
1153}
1154
1155static void calc_bend_grids(const Depsgraph &depsgraph,
1156 const Sculpt &sd,
1157 Object &object,
1158 SubdivCCG &subdiv_ccg,
1159 const Span<int> vert_propagation_steps,
1160 const Span<float> vert_factors,
1161 const Span<float3> vert_pivot_positions,
1162 const Span<float3> vert_pivot_axes,
1163 const bke::pbvh::GridsNode &node,
1164 LocalDataGrids &tls,
1165 const float3 symmetry_pivot,
1166 const float strength,
1167 const eBrushDeformTarget deform_target)
1168{
1169 SculptSession &ss = *object.sculpt;
1170 const StrokeCache &cache = *ss.cache;
1171 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1172
1173 const Span<int> grids = node.grids();
1174 const int grid_verts_num = grids.size() * key.grid_area;
1175 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
1176
1178
1179 const MutableSpan<float> factors = gather_data_grids(
1180 subdiv_ccg, vert_factors, grids, tls.factors);
1181
1182 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
1183
1184 const Span<int> propagation_steps = gather_data_grids(
1185 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
1186
1187 filter_uninitialized_verts(propagation_steps, factors);
1188 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1189
1190 scale_factors(factors, strength);
1191
1192 const Span<float3> pivot_positions = gather_data_grids(
1193 subdiv_ccg, vert_pivot_positions, grids, tls.pivot_positions);
1194 const Span<float3> pivot_axes = gather_data_grids(
1195 subdiv_ccg, vert_pivot_axes, grids, tls.pivot_axes);
1196
1197 tls.new_positions.resize(grid_verts_num);
1198 const MutableSpan<float3> new_positions = tls.new_positions;
1199 calc_bend_position(orig_data.positions, pivot_positions, pivot_axes, factors, new_positions);
1200
1201 switch (eBrushDeformTarget(deform_target)) {
1203 tls.translations.resize(grid_verts_num);
1204 const MutableSpan<float3> translations = tls.translations;
1205 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1206 translations_from_new_positions(new_positions, positions, translations);
1207
1208 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
1209 apply_translations(translations, grids, subdiv_ccg);
1210 break;
1211 }
1213 scatter_data_grids(subdiv_ccg,
1214 new_positions.as_span(),
1215 grids,
1216 cache.cloth_sim->deformation_pos.as_mutable_span());
1217 break;
1218 }
1219}
1220
1221static void calc_bend_bmesh(const Depsgraph &depsgraph,
1222 const Sculpt &sd,
1223 Object &object,
1224 const Span<int> vert_propagation_steps,
1225 const Span<float> vert_factors,
1226 const Span<float3> vert_pivot_positions,
1227 const Span<float3> vert_pivot_axes,
1229 LocalDataBMesh &tls,
1230 const float3 symmetry_pivot,
1231 const float strength,
1232 const eBrushDeformTarget deform_target)
1233
1234{
1235 SculptSession &ss = *object.sculpt;
1236 const StrokeCache &cache = *ss.cache;
1237
1239 Array<float3> orig_positions(verts.size());
1240 Array<float3> orig_normals(verts.size());
1241 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
1242
1244
1245 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
1246
1247 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1248
1249 const Span<int> propagation_steps = gather_data_bmesh(
1250 vert_propagation_steps, verts, tls.propagation_steps);
1251
1252 filter_uninitialized_verts(propagation_steps, factors);
1253 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
1254
1255 scale_factors(factors, strength);
1256
1257 const Span<float3> pivot_positions = gather_data_bmesh(
1258 vert_pivot_positions, verts, tls.pivot_positions);
1259 const Span<float3> pivot_axes = gather_data_bmesh(vert_pivot_axes, verts, tls.pivot_axes);
1260
1261 tls.new_positions.resize(verts.size());
1262 const MutableSpan<float3> new_positions = tls.new_positions;
1263 calc_bend_position(orig_positions, pivot_positions, pivot_axes, factors, new_positions);
1264
1265 switch (eBrushDeformTarget(deform_target)) {
1268 tls.translations.resize(verts.size());
1269 const MutableSpan<float3> translations = tls.translations;
1270 translations_from_new_positions(new_positions, positions, translations);
1271
1272 clip_and_lock_translations(sd, ss, orig_positions, translations);
1273 apply_translations(translations, verts);
1274 break;
1275 }
1278 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1279 break;
1280 }
1281}
1282
1283static void do_bend_brush(const Depsgraph &depsgraph,
1284 const Sculpt &sd,
1285 Object &object,
1286 const IndexMask &node_mask,
1287 const SculptBoundary &boundary,
1288 const float strength,
1289 const eBrushDeformTarget deform_target)
1290{
1291 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1292 switch (pbvh.type()) {
1293 case bke::pbvh::Type::Mesh: {
1294 const PositionDeformData position_data(depsgraph, object);
1295
1298 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1299 LocalDataMesh &tls = all_tls.local();
1301 sd,
1302 object,
1303 boundary.edit_info.propagation_steps_num,
1304 boundary.edit_info.strength_factor,
1305 boundary.bend.pivot_positions,
1306 boundary.bend.pivot_rotation_axis,
1307 nodes[i],
1308 tls,
1309 boundary.initial_vert_position,
1310 strength,
1311 deform_target,
1312 position_data);
1313 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
1314 });
1315 break;
1316 }
1318 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1319 MutableSpan<float3> positions = subdiv_ccg.positions;
1322 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1323 LocalDataGrids &tls = all_tls.local();
1325 sd,
1326 object,
1327 subdiv_ccg,
1328 boundary.edit_info.propagation_steps_num,
1329 boundary.edit_info.strength_factor,
1330 boundary.bend.pivot_positions,
1331 boundary.bend.pivot_rotation_axis,
1332 nodes[i],
1333 tls,
1334 boundary.initial_vert_position,
1335 strength,
1336 deform_target);
1337 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1338 });
1339 break;
1340 }
1344 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1345 LocalDataBMesh &tls = all_tls.local();
1347 sd,
1348 object,
1349 boundary.edit_info.propagation_steps_num,
1350 boundary.edit_info.strength_factor,
1351 boundary.bend.pivot_positions,
1352 boundary.bend.pivot_rotation_axis,
1353 nodes[i],
1354 tls,
1355 boundary.initial_vert_position,
1356 strength,
1357 deform_target);
1359 });
1360 break;
1361 }
1362 }
1363 pbvh.tag_positions_changed(node_mask);
1365}
1366
1368
1369/* -------------------------------------------------------------------- */
1372
1374 const Span<float3> directions,
1375 const Span<float> factors,
1376 const MutableSpan<float3> new_positions)
1377{
1378 BLI_assert(positions.size() == directions.size());
1379 BLI_assert(positions.size() == factors.size());
1380 BLI_assert(positions.size() == new_positions.size());
1381
1382 for (const int i : positions.index_range()) {
1383 new_positions[i] = positions[i] + (directions[i] * factors[i]);
1384 }
1385}
1386
1387static void calc_slide_mesh(const Depsgraph &depsgraph,
1388 const Sculpt &sd,
1389 Object &object,
1390 const Span<int> vert_propagation_steps,
1391 const Span<float> vert_factors,
1392 const Span<float3> vert_slide_directions,
1393 const bke::pbvh::MeshNode &node,
1394 LocalDataMesh &tls,
1395 const float3 symmetry_pivot,
1396 const float strength,
1397 const eBrushDeformTarget deform_target,
1398 const PositionDeformData &position_data)
1399{
1400 SculptSession &ss = *object.sculpt;
1401 const StrokeCache &cache = *ss.cache;
1402
1403 const Span<int> verts = node.verts();
1404 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1405
1407
1408 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1409
1410 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1411
1412 const Span<int> propagation_steps = gather_data_mesh(
1413 vert_propagation_steps, verts, tls.propagation_steps);
1414
1415 filter_uninitialized_verts(propagation_steps, factors);
1416 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1417
1418 scale_factors(factors, strength);
1419
1420 tls.new_positions.resize(verts.size());
1421 const MutableSpan<float3> new_positions = tls.new_positions;
1422
1423 const Span<float3> slide_directions = gather_data_mesh(
1424 vert_slide_directions, verts, tls.slide_directions);
1425
1426 calc_slide_position(orig_data.positions, slide_directions, factors, new_positions);
1427
1428 switch (eBrushDeformTarget(deform_target)) {
1430 tls.translations.resize(verts.size());
1431 const MutableSpan<float3> translations = tls.translations;
1432 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1433 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1434 position_data.deform(translations, verts);
1435 break;
1436 }
1439 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1440 break;
1441 }
1442}
1443
1444static void calc_slide_grids(const Depsgraph &depsgraph,
1445 const Sculpt &sd,
1446 Object &object,
1447 SubdivCCG &subdiv_ccg,
1448 const Span<int> vert_propagation_steps,
1449 const Span<float> vert_factors,
1450 const Span<float3> vert_slide_directions,
1451 const bke::pbvh::GridsNode &node,
1452 LocalDataGrids &tls,
1453 const float3 symmetry_pivot,
1454 const float strength,
1455 const eBrushDeformTarget deform_target)
1456{
1457 SculptSession &ss = *object.sculpt;
1458 const StrokeCache &cache = *ss.cache;
1459 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1460
1461 const Span<int> grids = node.grids();
1462 const int grid_verts_num = grids.size() * key.grid_area;
1463 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
1464
1466
1467 const MutableSpan<float> factors = gather_data_grids(
1468 subdiv_ccg, vert_factors, grids, tls.factors);
1469
1470 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
1471
1472 const Span<int> propagation_steps = gather_data_grids(
1473 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
1474
1475 filter_uninitialized_verts(propagation_steps, factors);
1476 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1477
1478 scale_factors(factors, strength);
1479
1480 tls.new_positions.resize(grid_verts_num);
1481 const MutableSpan<float3> new_positions = tls.new_positions;
1482
1483 const Span<float3> slide_directions = gather_data_grids(
1484 subdiv_ccg, vert_slide_directions, grids, tls.pivot_positions);
1485
1486 calc_slide_position(orig_data.positions, slide_directions, factors, new_positions);
1487
1488 switch (eBrushDeformTarget(deform_target)) {
1490 tls.translations.resize(grid_verts_num);
1491 const MutableSpan<float3> translations = tls.translations;
1492 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1493 translations_from_new_positions(new_positions, positions, translations);
1494
1495 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
1496 apply_translations(translations, grids, subdiv_ccg);
1497 break;
1498 }
1500 scatter_data_grids(subdiv_ccg,
1501 new_positions.as_span(),
1502 grids,
1503 cache.cloth_sim->deformation_pos.as_mutable_span());
1504 break;
1505 }
1506}
1507
1508static void calc_slide_bmesh(const Depsgraph &depsgraph,
1509 const Sculpt &sd,
1510 Object &object,
1511 const Span<int> vert_propagation_steps,
1512 const Span<float> vert_factors,
1513 const Span<float3> vert_slide_directions,
1515 LocalDataBMesh &tls,
1516 const float3 symmetry_pivot,
1517 const float strength,
1518 const eBrushDeformTarget deform_target)
1519
1520{
1521 SculptSession &ss = *object.sculpt;
1522 const StrokeCache &cache = *ss.cache;
1523
1525 Array<float3> orig_positions(verts.size());
1526 Array<float3> orig_normals(verts.size());
1527 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
1528
1530
1531 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
1532
1533 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1534
1535 const Span<int> propagation_steps = gather_data_bmesh(
1536 vert_propagation_steps, verts, tls.propagation_steps);
1537
1538 filter_uninitialized_verts(propagation_steps, factors);
1539 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
1540
1541 scale_factors(factors, strength);
1542
1543 const Span<float3> slide_directions = gather_data_bmesh(
1544 vert_slide_directions, verts, tls.pivot_positions);
1545
1546 tls.new_positions.resize(verts.size());
1547 const MutableSpan<float3> new_positions = tls.new_positions;
1548 calc_slide_position(orig_positions, slide_directions, factors, new_positions);
1549
1550 switch (eBrushDeformTarget(deform_target)) {
1553 tls.translations.resize(verts.size());
1554 const MutableSpan<float3> translations = tls.translations;
1555 translations_from_new_positions(new_positions, positions, translations);
1556
1557 clip_and_lock_translations(sd, ss, orig_positions, translations);
1558 apply_translations(translations, verts);
1559 break;
1560 }
1563 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1564 break;
1565 }
1566}
1567
1568static void do_slide_brush(const Depsgraph &depsgraph,
1569 const Sculpt &sd,
1570 Object &object,
1571 const IndexMask &node_mask,
1572 const SculptBoundary &boundary,
1573 const float strength,
1574 const eBrushDeformTarget deform_target)
1575{
1576 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1577 switch (pbvh.type()) {
1578 case bke::pbvh::Type::Mesh: {
1579 const PositionDeformData position_data(depsgraph, object);
1580
1583 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1584 LocalDataMesh &tls = all_tls.local();
1586 sd,
1587 object,
1588 boundary.edit_info.propagation_steps_num,
1589 boundary.edit_info.strength_factor,
1590 boundary.slide.directions,
1591 nodes[i],
1592 tls,
1593 boundary.initial_vert_position,
1594 strength,
1595 deform_target,
1596 position_data);
1597 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
1598 });
1599 break;
1600 }
1602 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1603 MutableSpan<float3> positions = subdiv_ccg.positions;
1606 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1607 LocalDataGrids &tls = all_tls.local();
1609 sd,
1610 object,
1611 subdiv_ccg,
1612 boundary.edit_info.propagation_steps_num,
1613 boundary.edit_info.strength_factor,
1614 boundary.slide.directions,
1615 nodes[i],
1616 tls,
1617 boundary.initial_vert_position,
1618 strength,
1619 deform_target);
1620 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1621 });
1622 break;
1623 }
1627 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1628 LocalDataBMesh &tls = all_tls.local();
1630 sd,
1631 object,
1632 boundary.edit_info.propagation_steps_num,
1633 boundary.edit_info.strength_factor,
1634 boundary.slide.directions,
1635 nodes[i],
1636 tls,
1637 boundary.initial_vert_position,
1638 strength,
1639 deform_target);
1641 });
1642 break;
1643 }
1644 }
1645 pbvh.tag_positions_changed(node_mask);
1647}
1648
1650
1651/* -------------------------------------------------------------------- */
1654
1656 const Span<float3> normals,
1657 const Span<float> factors,
1658 const MutableSpan<float3> new_positions)
1659{
1660 BLI_assert(positions.size() == normals.size());
1661 BLI_assert(positions.size() == factors.size());
1662 BLI_assert(positions.size() == new_positions.size());
1663
1664 for (const int i : positions.index_range()) {
1665 new_positions[i] = positions[i] + (normals[i] * factors[i]);
1666 }
1667}
1668
1669static void calc_inflate_mesh(const Depsgraph &depsgraph,
1670 const Sculpt &sd,
1671 Object &object,
1672 const Span<int> vert_propagation_steps,
1673 const Span<float> vert_factors,
1674 const bke::pbvh::MeshNode &node,
1675 LocalDataMesh &tls,
1676 const float3 symmetry_pivot,
1677 const float strength,
1678 const eBrushDeformTarget deform_target,
1679 const PositionDeformData &position_data)
1680{
1681 SculptSession &ss = *object.sculpt;
1682 const StrokeCache &cache = *ss.cache;
1683
1684 const Span<int> verts = node.verts();
1685 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1686
1688
1689 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1690
1691 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1692
1693 const Span<int> propagation_steps = gather_data_mesh(
1694 vert_propagation_steps, verts, tls.propagation_steps);
1695
1696 filter_uninitialized_verts(propagation_steps, factors);
1697 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1698
1699 scale_factors(factors, strength);
1700
1701 tls.new_positions.resize(verts.size());
1702 const MutableSpan<float3> new_positions = tls.new_positions;
1703 calc_inflate_position(orig_data.positions, orig_data.normals, factors, new_positions);
1704
1705 switch (eBrushDeformTarget(deform_target)) {
1707 tls.translations.resize(verts.size());
1708 const MutableSpan<float3> translations = tls.translations;
1709 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1710 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1711 position_data.deform(translations, verts);
1712 break;
1713 }
1716 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1717 break;
1718 }
1719}
1720
1721static void calc_inflate_grids(const Depsgraph &depsgraph,
1722 const Sculpt &sd,
1723 Object &object,
1724 SubdivCCG &subdiv_ccg,
1725 const Span<int> vert_propagation_steps,
1726 const Span<float> vert_factors,
1727 const bke::pbvh::GridsNode &node,
1728 LocalDataGrids &tls,
1729 const float3 symmetry_pivot,
1730 const float strength,
1731 const eBrushDeformTarget deform_target)
1732{
1733 SculptSession &ss = *object.sculpt;
1734 const StrokeCache &cache = *ss.cache;
1735 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1736
1737 const Span<int> grids = node.grids();
1738 const int grid_verts_num = grids.size() * key.grid_area;
1739 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
1740
1742
1743 const MutableSpan<float> factors = gather_data_grids(
1744 subdiv_ccg, vert_factors, grids, tls.factors);
1745
1746 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
1747
1748 const Span<int> propagation_steps = gather_data_grids(
1749 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
1750
1751 filter_uninitialized_verts(propagation_steps, factors);
1752 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1753
1754 scale_factors(factors, strength);
1755
1756 tls.new_positions.resize(grid_verts_num);
1757 const MutableSpan<float3> new_positions = tls.new_positions;
1758 calc_inflate_position(orig_data.positions, orig_data.normals, factors, new_positions);
1759
1760 switch (eBrushDeformTarget(deform_target)) {
1762 tls.translations.resize(grid_verts_num);
1763 const MutableSpan<float3> translations = tls.translations;
1764 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1765 translations_from_new_positions(new_positions, positions, translations);
1766
1767 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
1768 apply_translations(translations, grids, subdiv_ccg);
1769 break;
1770 }
1772 scatter_data_grids(subdiv_ccg,
1773 new_positions.as_span(),
1774 grids,
1775 cache.cloth_sim->deformation_pos.as_mutable_span());
1776 break;
1777 }
1778}
1779
1780static void calc_inflate_bmesh(const Depsgraph &depsgraph,
1781 const Sculpt &sd,
1782 Object &object,
1783 const Span<int> vert_propagation_steps,
1784 const Span<float> vert_factors,
1786 LocalDataBMesh &tls,
1787 const float3 symmetry_pivot,
1788 const float strength,
1789 const eBrushDeformTarget deform_target)
1790
1791{
1792 SculptSession &ss = *object.sculpt;
1793 const StrokeCache &cache = *ss.cache;
1794
1796 Array<float3> orig_positions(verts.size());
1797 Array<float3> orig_normals(verts.size());
1798 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
1799
1801
1802 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
1803
1804 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1805
1806 const Span<int> propagation_steps = gather_data_bmesh(
1807 vert_propagation_steps, verts, tls.propagation_steps);
1808
1809 filter_uninitialized_verts(propagation_steps, factors);
1810 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
1811
1812 scale_factors(factors, strength);
1813
1814 tls.new_positions.resize(verts.size());
1815 const MutableSpan<float3> new_positions = tls.new_positions;
1816 calc_inflate_position(orig_positions, orig_normals, factors, new_positions);
1817
1818 switch (eBrushDeformTarget(deform_target)) {
1821 tls.translations.resize(verts.size());
1822 const MutableSpan<float3> translations = tls.translations;
1823 translations_from_new_positions(new_positions, positions, translations);
1824
1825 clip_and_lock_translations(sd, ss, orig_positions, translations);
1826 apply_translations(translations, verts);
1827 break;
1828 }
1831 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1832 break;
1833 }
1834}
1835
1836static void do_inflate_brush(const Depsgraph &depsgraph,
1837 const Sculpt &sd,
1838 Object &object,
1839 const IndexMask &node_mask,
1840 const SculptBoundary &boundary,
1841 const float strength,
1842 const eBrushDeformTarget deform_target)
1843{
1844 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1845 switch (pbvh.type()) {
1846 case bke::pbvh::Type::Mesh: {
1847 const PositionDeformData position_data(depsgraph, object);
1848
1851 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1852 LocalDataMesh &tls = all_tls.local();
1854 sd,
1855 object,
1856 boundary.edit_info.propagation_steps_num,
1857 boundary.edit_info.strength_factor,
1858 nodes[i],
1859 tls,
1860 boundary.initial_vert_position,
1861 strength,
1862 deform_target,
1863 position_data);
1864 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
1865 });
1866 break;
1867 }
1869 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1870 MutableSpan<float3> positions = subdiv_ccg.positions;
1873 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1874 LocalDataGrids &tls = all_tls.local();
1876 sd,
1877 object,
1878 subdiv_ccg,
1879 boundary.edit_info.propagation_steps_num,
1880 boundary.edit_info.strength_factor,
1881 nodes[i],
1882 tls,
1883 boundary.initial_vert_position,
1884 strength,
1885 deform_target);
1886 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1887 });
1888 break;
1889 }
1893 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1894 LocalDataBMesh &tls = all_tls.local();
1896 sd,
1897 object,
1898 boundary.edit_info.propagation_steps_num,
1899 boundary.edit_info.strength_factor,
1900 nodes[i],
1901 tls,
1902 boundary.initial_vert_position,
1903 strength,
1904 deform_target);
1906 });
1907 break;
1908 }
1909 }
1910 pbvh.tag_positions_changed(node_mask);
1912}
1913
1915
1916/* -------------------------------------------------------------------- */
1919
1921 const float3 grab_delta,
1922 const Span<float> factors,
1923 const MutableSpan<float3> new_positions)
1924{
1925 BLI_assert(positions.size() == factors.size());
1926 BLI_assert(positions.size() == new_positions.size());
1927
1928 for (const int i : positions.index_range()) {
1929 new_positions[i] = positions[i] + (grab_delta * factors[i]);
1930 }
1931}
1932
1933static void calc_grab_mesh(const Depsgraph &depsgraph,
1934 const Sculpt &sd,
1935 Object &object,
1936 const Span<int> vert_propagation_steps,
1937 const Span<float> vert_factors,
1938 const bke::pbvh::MeshNode &node,
1939 LocalDataMesh &tls,
1940 const float3 grab_delta_symmetry,
1941 const float3 symmetry_pivot,
1942 const float strength,
1943 const eBrushDeformTarget deform_target,
1944 const PositionDeformData &position_data)
1945{
1946 SculptSession &ss = *object.sculpt;
1947 const StrokeCache &cache = *ss.cache;
1948
1949 const Span<int> verts = node.verts();
1950 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1951
1953
1954 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1955
1956 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1957
1958 const Span<int> propagation_steps = gather_data_mesh(
1959 vert_propagation_steps, verts, tls.propagation_steps);
1960
1961 filter_uninitialized_verts(propagation_steps, factors);
1962 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1963
1964 scale_factors(factors, strength);
1965
1966 tls.new_positions.resize(verts.size());
1967 const MutableSpan<float3> new_positions = tls.new_positions;
1968 calc_grab_position(orig_data.positions, grab_delta_symmetry, factors, new_positions);
1969
1970 switch (eBrushDeformTarget(deform_target)) {
1972 tls.translations.resize(verts.size());
1973 const MutableSpan<float3> translations = tls.translations;
1974 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1975 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1976 position_data.deform(translations, verts);
1977 break;
1978 }
1981 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1982 break;
1983 }
1984}
1985
1986static void calc_grab_grids(const Depsgraph &depsgraph,
1987 const Sculpt &sd,
1988 Object &object,
1989 SubdivCCG &subdiv_ccg,
1990 const Span<int> vert_propagation_steps,
1991 const Span<float> vert_factors,
1992 const bke::pbvh::GridsNode &node,
1993 LocalDataGrids &tls,
1994 const float3 grab_delta_symmetry,
1995 const float3 symmetry_pivot,
1996 const float strength,
1997 const eBrushDeformTarget deform_target)
1998{
1999 SculptSession &ss = *object.sculpt;
2000 const StrokeCache &cache = *ss.cache;
2001 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2002
2003 const Span<int> grids = node.grids();
2004 const int grid_verts_num = grids.size() * key.grid_area;
2005 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
2006
2008
2009 const MutableSpan<float> factors = gather_data_grids(
2010 subdiv_ccg, vert_factors, grids, tls.factors);
2011
2012 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
2013
2014 const Span<int> propagation_steps = gather_data_grids(
2015 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
2016
2017 filter_uninitialized_verts(propagation_steps, factors);
2018 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2019
2020 scale_factors(factors, strength);
2021
2022 tls.new_positions.resize(grid_verts_num);
2023 const MutableSpan<float3> new_positions = tls.new_positions;
2024 calc_grab_position(orig_data.positions, grab_delta_symmetry, factors, new_positions);
2025
2026 switch (eBrushDeformTarget(deform_target)) {
2028 tls.translations.resize(grid_verts_num);
2029 const MutableSpan<float3> translations = tls.translations;
2030 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
2031 translations_from_new_positions(new_positions, positions, translations);
2032
2033 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
2034 apply_translations(translations, grids, subdiv_ccg);
2035 break;
2036 }
2038 scatter_data_grids(subdiv_ccg,
2039 new_positions.as_span(),
2040 grids,
2041 cache.cloth_sim->deformation_pos.as_mutable_span());
2042 break;
2043 }
2044}
2045
2046static void calc_grab_bmesh(const Depsgraph &depsgraph,
2047 const Sculpt &sd,
2048 Object &object,
2049 const Span<int> vert_propagation_steps,
2050 const Span<float> vert_factors,
2052 LocalDataBMesh &tls,
2053 const float3 grab_delta_symmetry,
2054 const float3 symmetry_pivot,
2055 const float strength,
2056 const eBrushDeformTarget deform_target)
2057
2058{
2059 SculptSession &ss = *object.sculpt;
2060 const StrokeCache &cache = *ss.cache;
2061
2063 Array<float3> orig_positions(verts.size());
2064 Array<float3> orig_normals(verts.size());
2065 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
2066
2068
2069 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
2070
2071 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
2072
2073 const Span<int> propagation_steps = gather_data_bmesh(
2074 vert_propagation_steps, verts, tls.propagation_steps);
2075
2076 filter_uninitialized_verts(propagation_steps, factors);
2077 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
2078
2079 scale_factors(factors, strength);
2080
2081 tls.new_positions.resize(verts.size());
2082 const MutableSpan<float3> new_positions = tls.new_positions;
2083 calc_grab_position(orig_positions, grab_delta_symmetry, factors, new_positions);
2084
2085 switch (eBrushDeformTarget(deform_target)) {
2088 tls.translations.resize(verts.size());
2089 const MutableSpan<float3> translations = tls.translations;
2090 translations_from_new_positions(new_positions, positions, translations);
2091
2092 clip_and_lock_translations(sd, ss, orig_positions, translations);
2093 apply_translations(translations, verts);
2094 break;
2095 }
2098 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2099 break;
2100 }
2101}
2102
2103static void do_grab_brush(const Depsgraph &depsgraph,
2104 const Sculpt &sd,
2105 Object &object,
2106 const IndexMask &node_mask,
2107 const SculptBoundary &boundary,
2108 const float strength,
2109 const eBrushDeformTarget deform_target)
2110{
2111 SculptSession &ss = *object.sculpt;
2112 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2113 switch (pbvh.type()) {
2114 case bke::pbvh::Type::Mesh: {
2115 const PositionDeformData position_data(depsgraph, object);
2116
2119 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2120 LocalDataMesh &tls = all_tls.local();
2122 sd,
2123 object,
2124 boundary.edit_info.propagation_steps_num,
2125 boundary.edit_info.strength_factor,
2126 nodes[i],
2127 tls,
2129 boundary.initial_vert_position,
2130 strength,
2131 deform_target,
2132 position_data);
2133 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
2134 });
2135 break;
2136 }
2138 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2139 MutableSpan<float3> positions = subdiv_ccg.positions;
2142 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2143 LocalDataGrids &tls = all_tls.local();
2145 sd,
2146 object,
2147 subdiv_ccg,
2148 boundary.edit_info.propagation_steps_num,
2149 boundary.edit_info.strength_factor,
2150 nodes[i],
2151 tls,
2153 boundary.initial_vert_position,
2154 strength,
2155 deform_target);
2156 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2157 });
2158 break;
2159 }
2163 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2164 LocalDataBMesh &tls = all_tls.local();
2166 sd,
2167 object,
2168 boundary.edit_info.propagation_steps_num,
2169 boundary.edit_info.strength_factor,
2170 nodes[i],
2171 tls,
2173 boundary.initial_vert_position,
2174 strength,
2175 deform_target);
2177 });
2178 break;
2179 }
2180 }
2181 pbvh.tag_positions_changed(node_mask);
2183}
2184
2186
2187/* -------------------------------------------------------------------- */
2190
2192 const float3 pivot_point,
2193 const float3 pivot_axis,
2194 const Span<float> factors,
2195 const MutableSpan<float3> new_positions)
2196{
2197 BLI_assert(positions.size() == factors.size());
2198 BLI_assert(positions.size() == new_positions.size());
2199
2200 for (const int i : positions.index_range()) {
2201 new_positions[i] = math::rotate_around_axis(positions[i], pivot_point, pivot_axis, factors[i]);
2202 }
2203}
2204
2205static void calc_twist_mesh(const Depsgraph &depsgraph,
2206 const Sculpt &sd,
2207 Object &object,
2208 const Span<int> vert_propagation_steps,
2209 const Span<float> vert_factors,
2210 const bke::pbvh::MeshNode &node,
2211 LocalDataMesh &tls,
2212 const float3 twist_pivot_position,
2213 const float3 twist_axis,
2214 const float3 symmetry_pivot,
2215 const float strength,
2216 const eBrushDeformTarget deform_target,
2217 const PositionDeformData &position_data)
2218{
2219 SculptSession &ss = *object.sculpt;
2220 const StrokeCache &cache = *ss.cache;
2221
2222 const Span<int> verts = node.verts();
2223 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
2224
2226
2227 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
2228
2229 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
2230
2231 const Span<int> propagation_steps = gather_data_mesh(
2232 vert_propagation_steps, verts, tls.propagation_steps);
2233
2234 filter_uninitialized_verts(propagation_steps, factors);
2235 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2236
2237 scale_factors(factors, strength);
2238
2239 tls.new_positions.resize(verts.size());
2240 const MutableSpan<float3> new_positions = tls.new_positions;
2242 orig_data.positions, twist_pivot_position, twist_axis, factors, new_positions);
2243
2244 switch (eBrushDeformTarget(deform_target)) {
2246 tls.translations.resize(verts.size());
2247 const MutableSpan<float3> translations = tls.translations;
2248 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
2249 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
2250 position_data.deform(translations, verts);
2251 break;
2252 }
2255 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2256 break;
2257 }
2258}
2259
2260static void calc_twist_grids(const Depsgraph &depsgraph,
2261 const Sculpt &sd,
2262 Object &object,
2263 SubdivCCG &subdiv_ccg,
2264 const Span<int> vert_propagation_steps,
2265 const Span<float> vert_factors,
2266 const float3 twist_pivot_position,
2267 const float3 twist_axis,
2268 const bke::pbvh::GridsNode &node,
2269 LocalDataGrids &tls,
2270 const float3 symmetry_pivot,
2271 const float strength,
2272 const eBrushDeformTarget deform_target)
2273{
2274 SculptSession &ss = *object.sculpt;
2275 const StrokeCache &cache = *ss.cache;
2276 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2277
2278 const Span<int> grids = node.grids();
2279 const int grid_verts_num = grids.size() * key.grid_area;
2280 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
2281
2283
2284 const MutableSpan<float> factors = gather_data_grids(
2285 subdiv_ccg, vert_factors, grids, tls.factors);
2286
2287 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
2288
2289 const Span<int> propagation_steps = gather_data_grids(
2290 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
2291
2292 filter_uninitialized_verts(propagation_steps, factors);
2293 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2294
2295 scale_factors(factors, strength);
2296
2297 tls.new_positions.resize(grid_verts_num);
2298 const MutableSpan<float3> new_positions = tls.new_positions;
2300 orig_data.positions, twist_pivot_position, twist_axis, factors, new_positions);
2301
2302 switch (eBrushDeformTarget(deform_target)) {
2304 tls.translations.resize(grid_verts_num);
2305 const MutableSpan<float3> translations = tls.translations;
2306 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
2307 translations_from_new_positions(new_positions, positions, translations);
2308
2309 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
2310 apply_translations(translations, grids, subdiv_ccg);
2311 break;
2312 }
2314 scatter_data_grids(subdiv_ccg,
2315 new_positions.as_span(),
2316 grids,
2317 cache.cloth_sim->deformation_pos.as_mutable_span());
2318 break;
2319 }
2320}
2321
2322static void calc_twist_bmesh(const Depsgraph &depsgraph,
2323 const Sculpt &sd,
2324 Object &object,
2325 const Span<int> vert_propagation_steps,
2326 const Span<float> vert_factors,
2327 const float3 twist_pivot_position,
2328 const float3 twist_axis,
2330 LocalDataBMesh &tls,
2331 const float3 symmetry_pivot,
2332 const float strength,
2333 const eBrushDeformTarget deform_target)
2334
2335{
2336 SculptSession &ss = *object.sculpt;
2337 const StrokeCache &cache = *ss.cache;
2338
2340 Array<float3> orig_positions(verts.size());
2341 Array<float3> orig_normals(verts.size());
2342 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
2343
2345
2346 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
2347
2348 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
2349
2350 const Span<int> propagation_steps = gather_data_bmesh(
2351 vert_propagation_steps, verts, tls.propagation_steps);
2352
2353 filter_uninitialized_verts(propagation_steps, factors);
2354 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
2355
2356 scale_factors(factors, strength);
2357
2358 tls.new_positions.resize(verts.size());
2359 const MutableSpan<float3> new_positions = tls.new_positions;
2360 calc_twist_position(orig_positions, twist_pivot_position, twist_axis, factors, new_positions);
2361
2362 switch (eBrushDeformTarget(deform_target)) {
2365 tls.translations.resize(verts.size());
2366 const MutableSpan<float3> translations = tls.translations;
2367 translations_from_new_positions(new_positions, positions, translations);
2368
2369 clip_and_lock_translations(sd, ss, orig_positions, translations);
2370 apply_translations(translations, verts);
2371 break;
2372 }
2375 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2376 break;
2377 }
2378}
2379
2380static void do_twist_brush(const Depsgraph &depsgraph,
2381 const Sculpt &sd,
2382 Object &object,
2383 const IndexMask &node_mask,
2384 const SculptBoundary &boundary,
2385 const float strength,
2386 const eBrushDeformTarget deform_target)
2387{
2388 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2389 switch (pbvh.type()) {
2390 case bke::pbvh::Type::Mesh: {
2391 const PositionDeformData position_data(depsgraph, object);
2392
2395 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2396 LocalDataMesh &tls = all_tls.local();
2398 sd,
2399 object,
2400 boundary.edit_info.propagation_steps_num,
2401 boundary.edit_info.strength_factor,
2402 nodes[i],
2403 tls,
2404 boundary.twist.pivot_position,
2405 boundary.twist.rotation_axis,
2406 boundary.initial_vert_position,
2407 strength,
2408 deform_target,
2409 position_data);
2410 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
2411 });
2412 break;
2413 }
2415 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2416 MutableSpan<float3> positions = subdiv_ccg.positions;
2419 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2420 LocalDataGrids &tls = all_tls.local();
2422 sd,
2423 object,
2424 subdiv_ccg,
2425 boundary.edit_info.propagation_steps_num,
2426 boundary.edit_info.strength_factor,
2427 boundary.twist.pivot_position,
2428 boundary.twist.rotation_axis,
2429 nodes[i],
2430 tls,
2431 boundary.initial_vert_position,
2432 strength,
2433 deform_target);
2434 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2435 });
2436 break;
2437 }
2441 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2442 LocalDataBMesh &tls = all_tls.local();
2444 sd,
2445 object,
2446 boundary.edit_info.propagation_steps_num,
2447 boundary.edit_info.strength_factor,
2448 boundary.twist.pivot_position,
2449 boundary.twist.rotation_axis,
2450 nodes[i],
2451 tls,
2452 boundary.initial_vert_position,
2453 strength,
2454 deform_target);
2456 });
2457 break;
2458 }
2459 }
2460 pbvh.tag_positions_changed(node_mask);
2462}
2463
2465
2466/* -------------------------------------------------------------------- */
2469
2471 const Span<float3> average_position,
2472 const Span<float> factors,
2473 const MutableSpan<float3> new_positions)
2474{
2475 BLI_assert(positions.size() == average_position.size());
2476 BLI_assert(positions.size() == factors.size());
2477 BLI_assert(positions.size() == new_positions.size());
2478
2479 for (const int i : positions.index_range()) {
2480 const float3 to_smooth = average_position[i] - positions[i];
2481 new_positions[i] = positions[i] + (to_smooth * factors[i]);
2482 }
2483}
2484
2485BLI_NOINLINE static void calc_average_position(const Span<float3> vert_positions,
2486 const Span<int> vert_propagation_steps,
2487 const GroupedSpan<int> neighbors,
2488 const Span<int> propagation_steps,
2489 const MutableSpan<float> factors,
2490 const MutableSpan<float3> average_positions)
2491{
2492 BLI_assert(vert_positions.size() == vert_propagation_steps.size());
2493 BLI_assert(factors.size() == neighbors.size());
2494 BLI_assert(factors.size() == propagation_steps.size());
2495 BLI_assert(factors.size() == average_positions.size());
2496
2497 for (const int i : neighbors.index_range()) {
2498 average_positions[i] = float3(0.0f);
2499 int valid_neighbors = 0;
2500 for (const int neighbor : neighbors[i]) {
2501 if (propagation_steps[i] == vert_propagation_steps[neighbor]) {
2502 average_positions[i] += vert_positions[neighbor];
2503 valid_neighbors++;
2504 }
2505 }
2506 average_positions[i] *= math::safe_rcp(float(valid_neighbors));
2507 if (valid_neighbors == 0) {
2508 factors[i] = 0.0f;
2509 }
2510 }
2511}
2512
2513BLI_NOINLINE static void calc_average_position(const Span<int> vert_propagation_steps,
2514 const GroupedSpan<BMVert *> neighbors,
2515 const Span<int> propagation_steps,
2516 const MutableSpan<float> factors,
2517 const MutableSpan<float3> average_positions)
2518{
2519 BLI_assert(neighbors.size() == propagation_steps.size());
2520 BLI_assert(neighbors.size() == factors.size());
2521 BLI_assert(neighbors.size() == average_positions.size());
2522
2523 for (const int i : neighbors.index_range()) {
2524 average_positions[i] = float3(0.0f);
2525 int valid_neighbors = 0;
2526 for (BMVert *neighbor : neighbors[i]) {
2527 const int neighbor_idx = BM_elem_index_get(neighbor);
2528 if (propagation_steps[i] == vert_propagation_steps[neighbor_idx]) {
2529 average_positions[i] += neighbor->co;
2530 valid_neighbors++;
2531 }
2532 }
2533 average_positions[i] *= math::safe_rcp(float(valid_neighbors));
2534 if (valid_neighbors == 0) {
2535 factors[i] = 0.0f;
2536 }
2537 }
2538}
2539
2540static void calc_smooth_mesh(const Sculpt &sd,
2541 Object &object,
2543 const Span<int> corner_verts,
2544 const GroupedSpan<int> vert_to_face,
2545 const Span<bool> hide_poly,
2546 const Span<int> vert_propagation_steps,
2547 const Span<float> vert_factors,
2548 const bke::pbvh::MeshNode &node,
2549 LocalDataMesh &tls,
2550 const float3 symmetry_pivot,
2551 const float strength,
2552 const eBrushDeformTarget deform_target,
2553 const PositionDeformData &position_data)
2554{
2555 SculptSession &ss = *object.sculpt;
2556 const StrokeCache &cache = *ss.cache;
2557
2558 const Span<int> verts = node.verts();
2559 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
2560
2562
2563 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
2564
2565 const Span<int> propagation_steps = gather_data_mesh(
2566 vert_propagation_steps, verts, tls.propagation_steps);
2567
2568 filter_uninitialized_verts(propagation_steps, factors);
2569 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2570
2571 scale_factors(factors, strength);
2572
2573 const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
2574 corner_verts,
2575 vert_to_face,
2576 hide_poly,
2577 verts,
2578 tls.neighbor_offsets,
2579 tls.neighbor_data);
2580 tls.average_positions.resize(verts.size());
2581
2582 const Span<float3> positions = gather_data_mesh(position_data.eval, verts, tls.positions);
2583 const MutableSpan<float3> average_positions = tls.average_positions;
2584 calc_average_position(position_data.eval,
2585 vert_propagation_steps,
2586 neighbors,
2587 propagation_steps,
2588 factors,
2589 average_positions);
2590
2591 tls.new_positions.resize(verts.size());
2592 const MutableSpan<float3> new_positions = tls.new_positions;
2593 calc_smooth_position(positions, average_positions, factors, new_positions);
2594
2595 switch (eBrushDeformTarget(deform_target)) {
2597 tls.translations.resize(verts.size());
2598 const MutableSpan<float3> translations = tls.translations;
2599 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
2600 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
2601 position_data.deform(translations, verts);
2602 break;
2603 }
2606 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2607 break;
2608 }
2609}
2610
2611static void calc_smooth_grids(const Sculpt &sd,
2612 Object &object,
2613 SubdivCCG &subdiv_ccg,
2614 const Span<int> vert_propagation_steps,
2615 const Span<float> vert_factors,
2616 const bke::pbvh::GridsNode &node,
2617 LocalDataGrids &tls,
2618 const float3 symmetry_pivot,
2619 const float strength,
2620 const eBrushDeformTarget deform_target)
2621{
2622 SculptSession &ss = *object.sculpt;
2623 const StrokeCache &cache = *ss.cache;
2624 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2625
2626 const Span<int> grids = node.grids();
2627 const int grid_verts_num = grids.size() * key.grid_area;
2628 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
2629
2631
2632 const MutableSpan<float> factors = gather_data_grids(
2633 subdiv_ccg, vert_factors, grids, tls.factors);
2634
2635 const Span<int> propagation_steps = gather_data_grids(
2636 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
2637
2638 filter_uninitialized_verts(propagation_steps, factors);
2639 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2640
2641 scale_factors(factors, strength);
2642
2643 const GroupedSpan<int> neighbors = calc_vert_neighbors(
2644 subdiv_ccg, grids, tls.neighbor_offsets, tls.neighbor_data);
2645
2646 tls.average_positions.resize(grid_verts_num);
2647 const MutableSpan<float3> average_positions = tls.average_positions;
2649 vert_propagation_steps,
2650 neighbors,
2651 propagation_steps,
2652 factors,
2653 average_positions);
2654
2655 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
2656
2657 tls.new_positions.resize(grid_verts_num);
2658 const MutableSpan<float3> new_positions = tls.new_positions;
2659 calc_smooth_position(positions, average_positions, factors, new_positions);
2660
2661 switch (eBrushDeformTarget(deform_target)) {
2663 tls.translations.resize(grid_verts_num);
2664 const MutableSpan<float3> translations = tls.translations;
2665 translations_from_new_positions(new_positions, positions, translations);
2666
2667 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
2668 apply_translations(translations, grids, subdiv_ccg);
2669 break;
2670 }
2672 scatter_data_grids(subdiv_ccg,
2673 new_positions.as_span(),
2674 grids,
2675 cache.cloth_sim->deformation_pos.as_mutable_span());
2676 break;
2677 }
2678}
2679
2680static void calc_smooth_bmesh(const Sculpt &sd,
2681 Object &object,
2682 const Span<int> vert_propagation_steps,
2683 const Span<float> vert_factors,
2685 LocalDataBMesh &tls,
2686 const float3 symmetry_pivot,
2687 const float strength,
2688 const eBrushDeformTarget deform_target)
2689
2690{
2691 SculptSession &ss = *object.sculpt;
2692 const StrokeCache &cache = *ss.cache;
2693
2695 Array<float3> orig_positions(verts.size());
2696 Array<float3> orig_normals(verts.size());
2697 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
2698
2700
2701 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
2702
2703 const Span<int> propagation_steps = gather_data_bmesh(
2704 vert_propagation_steps, verts, tls.propagation_steps);
2705
2706 filter_uninitialized_verts(propagation_steps, factors);
2707 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
2708
2709 scale_factors(factors, strength);
2710
2713
2714 tls.average_positions.resize(verts.size());
2715 const MutableSpan<float3> average_positions = tls.average_positions;
2717 vert_propagation_steps, neighbors, propagation_steps, factors, average_positions);
2718 const Span<float3> positions = gather_bmesh_positions(verts, tls.positions);
2719
2720 tls.new_positions.resize(verts.size());
2721 const MutableSpan<float3> new_positions = tls.new_positions;
2722 calc_smooth_position(positions, average_positions, factors, new_positions);
2723
2724 switch (eBrushDeformTarget(deform_target)) {
2726 tls.translations.resize(verts.size());
2727 const MutableSpan<float3> translations = tls.translations;
2728 translations_from_new_positions(new_positions, positions, translations);
2729
2730 clip_and_lock_translations(sd, ss, orig_positions, translations);
2731 apply_translations(translations, verts);
2732 break;
2733 }
2736 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2737 break;
2738 }
2739}
2740
2741static void do_smooth_brush(const Depsgraph &depsgraph,
2742 const Sculpt &sd,
2743 Object &object,
2744 const IndexMask &node_mask,
2745 const SculptBoundary &boundary,
2746 const float strength,
2747 const eBrushDeformTarget deform_target)
2748{
2749 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2750 switch (pbvh.type()) {
2751 case bke::pbvh::Type::Mesh: {
2752 Mesh &mesh = *static_cast<Mesh *>(object.data);
2753 const PositionDeformData position_data(depsgraph, object);
2754 const OffsetIndices<int> faces = mesh.faces();
2755 const Span<int> corner_verts = mesh.corner_verts();
2756 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
2757 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
2758 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
2759
2762 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2763 LocalDataMesh &tls = all_tls.local();
2765 object,
2766 faces,
2767 corner_verts,
2768 vert_to_face_map,
2769 hide_poly,
2770 boundary.edit_info.propagation_steps_num,
2771 boundary.edit_info.strength_factor,
2772 nodes[i],
2773 tls,
2774 boundary.initial_vert_position,
2775 strength,
2776 deform_target,
2777 position_data);
2778 bke::pbvh::update_node_bounds_mesh(position_data.eval, nodes[i]);
2779 });
2780 break;
2781 }
2783 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2784 MutableSpan<float3> positions = subdiv_ccg.positions;
2787 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2788 LocalDataGrids &tls = all_tls.local();
2790 object,
2791 subdiv_ccg,
2792 boundary.edit_info.propagation_steps_num,
2793 boundary.edit_info.strength_factor,
2794 nodes[i],
2795 tls,
2796 boundary.initial_vert_position,
2797 strength,
2798 deform_target);
2799 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2800 });
2801 break;
2802 }
2806 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2807 LocalDataBMesh &tls = all_tls.local();
2809 object,
2810 boundary.edit_info.propagation_steps_num,
2811 boundary.edit_info.strength_factor,
2812 nodes[i],
2813 tls,
2814 boundary.initial_vert_position,
2815 strength,
2816 deform_target);
2818 });
2819 break;
2820 }
2821 }
2822 pbvh.tag_positions_changed(node_mask);
2824}
2825
2826/* -------------------------------------------------------------------- */
2829
2831 const SculptBoundary &boundary)
2832{
2833 float4 plane;
2834 const float3 normal = math::normalize(ss.cache->initial_location_symm - boundary.pivot_position);
2836
2838 return dist_signed_to_plane_v3(pos, plane);
2839}
2840
2841static std::pair<float, float> calc_boundary_falloff(const SculptBoundary &boundary,
2842 const Brush &brush,
2843 const float radius,
2844 const int index)
2845{
2846 const float boundary_distance = boundary.distance.lookup_default(index, 0.0f);
2847 float falloff_distance = 0.0f;
2848 float direction = 1.0f;
2849
2850 switch (brush.boundary_falloff_type) {
2852 falloff_distance = boundary_distance;
2853 break;
2855 const int div = boundary_distance / radius;
2856 const float mod = fmodf(boundary_distance, radius);
2857 falloff_distance = div % 2 == 0 ? mod : radius - mod;
2858 break;
2859 }
2861 const int div = boundary_distance / radius;
2862 const float mod = fmodf(boundary_distance, radius);
2863 falloff_distance = div % 2 == 0 ? mod : radius - mod;
2864 /* Inverts the falloff in the intervals 1 2 5 6 9 10 ... etc. */
2865 if (((div - 1) & 2) == 0) {
2866 direction = -1.0f;
2867 }
2868 break;
2869 }
2871 /* For constant falloff distances are not allocated, so this should never happen. */
2873 break;
2874 }
2875
2876 return {falloff_distance, direction};
2877}
2878
2884 const Brush &brush,
2885 const float radius,
2887{
2888 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2889 boundary.edit_info.propagation_steps_num.size());
2890 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2891 boundary.edit_info.strength_factor.size());
2892
2893 const int num_elements = boundary.edit_info.strength_factor.size();
2895
2896 for (const int i : IndexRange(num_elements)) {
2897 if (boundary.edit_info.propagation_steps_num[i] != BOUNDARY_STEPS_NONE) {
2898 const float mask_factor = mask.is_empty() ? 1.0f : 1.0f - mask[i];
2899 boundary.edit_info.strength_factor[i] = mask_factor *
2901 &brush,
2902 boundary.edit_info.propagation_steps_num[i],
2903 boundary.max_propagation_steps);
2904 }
2905
2906 if (boundary.edit_info.original_vertex_i[i] == boundary.initial_vert_i) {
2907 /* All vertices that are propagated from the original vertex won't be affected by the
2908 * boundary falloff, so there is no need to calculate anything else. */
2909 continue;
2910 }
2911
2912 const bool use_boundary_distances = brush.boundary_falloff_type !=
2914
2915 if (!use_boundary_distances) {
2916 /* There are falloff modes that do not require to modify the previously calculated falloff
2917 * based on boundary distances. */
2918 continue;
2919 }
2920
2921 auto [falloff_distance, direction] = calc_boundary_falloff(
2922 boundary, brush, radius, boundary.edit_info.original_vertex_i[i]);
2923 boundary.edit_info.strength_factor[i] *= direction * BKE_brush_curve_strength(
2924 &brush, falloff_distance, radius);
2925 }
2926}
2927
2928static void init_falloff_grids(const SubdivCCG &subdiv_ccg,
2929 const Brush &brush,
2930 const float radius,
2932{
2933 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2934 boundary.edit_info.propagation_steps_num.size());
2935 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2936 boundary.edit_info.strength_factor.size());
2937
2938 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2939
2941
2942 for (const int grid : IndexRange(subdiv_ccg.grids_num)) {
2943 for (const int index : bke::ccg::grid_range(key, grid)) {
2944 if (boundary.edit_info.propagation_steps_num[index] != BOUNDARY_STEPS_NONE) {
2945 const float mask_factor = subdiv_ccg.masks.is_empty() ? 1.0f :
2946 1.0f - subdiv_ccg.masks[index];
2947 boundary.edit_info.strength_factor[index] =
2948 mask_factor * BKE_brush_curve_strength(&brush,
2949 boundary.edit_info.propagation_steps_num[index],
2950 boundary.max_propagation_steps);
2951 }
2952
2953 if (boundary.edit_info.original_vertex_i[index] == boundary.initial_vert_i) {
2954 /* All vertices that are propagated from the original vertex won't be affected by the
2955 * boundary falloff, so there is no need to calculate anything else. */
2956 continue;
2957 }
2958
2959 const bool use_boundary_distances = brush.boundary_falloff_type !=
2961
2962 if (!use_boundary_distances) {
2963 /* There are falloff modes that do not require to modify the previously calculated falloff
2964 * based on boundary distances. */
2965 continue;
2966 }
2967
2968 auto [falloff_distance, direction] = calc_boundary_falloff(
2969 boundary, brush, radius, boundary.edit_info.original_vertex_i[index]);
2970 boundary.edit_info.strength_factor[index] *= direction *
2972 &brush, falloff_distance, radius);
2973 }
2974 }
2975}
2976
2978 const Brush &brush,
2979 const float radius,
2981{
2982 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2983 boundary.edit_info.propagation_steps_num.size());
2984 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2985 boundary.edit_info.strength_factor.size());
2986
2987 const int num_elements = boundary.edit_info.strength_factor.size();
2988
2990
2991 for (const int i : IndexRange(num_elements)) {
2992 if (boundary.edit_info.propagation_steps_num[i] != BOUNDARY_STEPS_NONE) {
2993 BMVert *vert = BM_vert_at_index(bm, i);
2994 const int mask_offset = CustomData_get_offset_named(
2995 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
2996 const float mask_factor = mask_offset == -1 ? 1.0f :
2997 1.0f - BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
2998
2999 boundary.edit_info.strength_factor[i] = mask_factor *
3001 &brush,
3002 boundary.edit_info.propagation_steps_num[i],
3003 boundary.max_propagation_steps);
3004 }
3005
3006 if (boundary.edit_info.original_vertex_i[i] == boundary.initial_vert_i) {
3007 /* All vertices that are propagated from the original vertex won't be affected by the
3008 * boundary falloff, so there is no need to calculate anything else. */
3009 continue;
3010 }
3011
3012 const bool use_boundary_distances = brush.boundary_falloff_type !=
3014
3015 if (!use_boundary_distances) {
3016 /* There are falloff modes that do not require to modify the previously calculated falloff
3017 * based on boundary distances. */
3018 continue;
3019 }
3020
3021 auto [falloff_distance, direction] = calc_boundary_falloff(
3022 boundary, brush, radius, boundary.edit_info.original_vertex_i[i]);
3023 boundary.edit_info.strength_factor[i] *= direction * BKE_brush_curve_strength(
3024 &brush, falloff_distance, radius);
3025 }
3026}
3027
3028static void init_boundary_mesh(const Depsgraph &depsgraph,
3029 Object &object,
3030 const Brush &brush,
3031 const ePaintSymmetryFlags symm_area)
3032{
3033 const SculptSession &ss = *object.sculpt;
3034 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3035
3036 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
3037 const bke::AttributeAccessor attributes = mesh.attributes();
3038 VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
3039 VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
3040
3041 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
3042 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
3043
3044 ActiveVert initial_vert_ref = ss.active_vert();
3045 if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
3046 return;
3047 }
3048
3049 std::optional<int> initial_vert;
3050 if (ss.cache->mirror_symmetry_pass == 0) {
3051 initial_vert = std::get<int>(initial_vert_ref);
3052 }
3053 else {
3054 float3 location = symmetry_flip(positions_eval[std::get<int>(initial_vert_ref)], symm_area);
3055 initial_vert = nearest_vert_calc_mesh(
3056 pbvh, positions_eval, hide_vert, location, ss.cache->radius_squared, false);
3057 }
3058
3059 if (!initial_vert) {
3060 return;
3061 }
3062
3063 ss.cache->boundaries[symm_area] = boundary::data_init_mesh(
3064 depsgraph, object, &brush, *initial_vert, ss.cache->initial_radius);
3065
3066 if (ss.cache->boundaries[symm_area]) {
3067 switch (brush.boundary_deform_type) {
3069 bend_data_init_mesh(positions_eval, vert_normals, *ss.cache->boundaries[symm_area]);
3070 break;
3072 slide_data_init_mesh(positions_eval, *ss.cache->boundaries[symm_area]);
3073 break;
3075 twist_data_init_mesh(positions_eval, *ss.cache->boundaries[symm_area]);
3076 break;
3080 /* Do nothing. These deform modes don't need any extra data to be precomputed. */
3081 break;
3082 }
3083
3084 init_falloff_mesh(mask, brush, ss.cache->initial_radius, *ss.cache->boundaries[symm_area]);
3085 }
3086}
3087
3088static void init_boundary_grids(Object &object,
3089 const Brush &brush,
3090 const ePaintSymmetryFlags symm_area)
3091{
3092 const SculptSession &ss = *object.sculpt;
3093 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3094
3095 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
3096 const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
3097 const Span<float3> positions = subdiv_ccg.positions;
3098
3099 ActiveVert initial_vert_ref = ss.active_vert();
3100 if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
3101 return;
3102 }
3103
3104 std::optional<SubdivCCGCoord> initial_vert;
3105 if (ss.cache->mirror_symmetry_pass == 0) {
3106 initial_vert = SubdivCCGCoord::from_index(key, std::get<int>(initial_vert_ref));
3107 }
3108 else {
3109 const int active_vert = std::get<int>(initial_vert_ref);
3110 float3 location = symmetry_flip(positions[active_vert], symm_area);
3111 initial_vert = nearest_vert_calc_grids(
3112 pbvh, subdiv_ccg, location, ss.cache->radius_squared, false);
3113 }
3114
3115 if (!initial_vert) {
3116 return;
3117 }
3118
3120 object, &brush, *initial_vert, ss.cache->initial_radius);
3121
3122 if (ss.cache->boundaries[symm_area]) {
3123 switch (brush.boundary_deform_type) {
3125 bend_data_init_grids(subdiv_ccg, *ss.cache->boundaries[symm_area]);
3126 break;
3128 slide_data_init_grids(subdiv_ccg, *ss.cache->boundaries[symm_area]);
3129 break;
3131 twist_data_init_grids(subdiv_ccg, *ss.cache->boundaries[symm_area]);
3132 break;
3136 /* Do nothing. These deform modes don't need any extra data to be precomputed. */
3137 break;
3138 }
3139
3141 subdiv_ccg, brush, ss.cache->initial_radius, *ss.cache->boundaries[symm_area]);
3142 }
3143}
3144
3145static void init_boundary_bmesh(Object &object,
3146 const Brush &brush,
3147 const ePaintSymmetryFlags symm_area)
3148{
3149 const SculptSession &ss = *object.sculpt;
3150 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3151
3152 BMesh *bm = ss.bm;
3153
3154 ActiveVert initial_vert_ref = ss.active_vert();
3155 if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
3156 return;
3157 }
3158
3159 std::optional<BMVert *> initial_vert;
3160 if (ss.cache->mirror_symmetry_pass == 0) {
3161 initial_vert = std::get<BMVert *>(initial_vert_ref);
3162 }
3163 else {
3164 BMVert *active_vert = std::get<BMVert *>(initial_vert_ref);
3165 float3 location = symmetry_flip(active_vert->co, symm_area);
3166 initial_vert = nearest_vert_calc_bmesh(pbvh, location, ss.cache->radius_squared, false);
3167 }
3168
3169 if (!initial_vert) {
3170 return;
3171 }
3172
3174 object, &brush, *initial_vert, ss.cache->initial_radius);
3175
3176 if (ss.cache->boundaries[symm_area]) {
3177 switch (brush.boundary_deform_type) {
3179 bend_data_init_bmesh(bm, *ss.cache->boundaries[symm_area]);
3180 break;
3182 slide_data_init_bmesh(bm, *ss.cache->boundaries[symm_area]);
3183 break;
3185 twist_data_init_bmesh(bm, *ss.cache->boundaries[symm_area]);
3186 break;
3190 /* Do nothing. These deform modes don't need any extra data to be precomputed. */
3191 break;
3192 }
3193
3194 init_falloff_bmesh(bm, brush, ss.cache->initial_radius, *ss.cache->boundaries[symm_area]);
3195 }
3196}
3197
3198static float get_mesh_strength(const SculptSession &ss, const Brush &brush)
3199{
3200 const int symm_area = ss.cache->mirror_symmetry_pass;
3201 SculptBoundary &boundary = *ss.cache->boundaries[symm_area];
3202
3203 const float strength = ss.cache->bstrength;
3204
3205 switch (brush.boundary_deform_type) {
3207 const float disp = strength * displacement_from_grab_delta_get(ss, boundary);
3208 float angle_factor = disp / ss.cache->radius;
3209 /* Angle Snapping when inverting the brush. */
3210 if (ss.cache->invert) {
3211 angle_factor = floorf(angle_factor * 10) / 10.0f;
3212 }
3213 return angle_factor * M_PI;
3214 }
3216 return strength * displacement_from_grab_delta_get(ss, boundary);
3217 }
3219 return strength * displacement_from_grab_delta_get(ss, boundary);
3220 }
3222 return strength;
3224 const float disp = strength * displacement_from_grab_delta_get(ss, boundary);
3225 float angle_factor = disp / ss.cache->radius;
3226 /* Angle Snapping when inverting the brush. */
3227 if (ss.cache->invert) {
3228 angle_factor = floorf(angle_factor * 10) / 10.0f;
3229 }
3230 return angle_factor * M_PI;
3231 }
3233 return strength;
3234 }
3235
3237 return 0.0f;
3238}
3239
3240void do_boundary_brush(const Depsgraph &depsgraph,
3241 const Sculpt &sd,
3242 Object &ob,
3243 const IndexMask &node_mask)
3244{
3245 SculptSession &ss = *ob.sculpt;
3247 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3248
3249 const ePaintSymmetryFlags symm_area = ss.cache->mirror_symmetry_pass;
3251 switch (pbvh.type()) {
3253 init_boundary_mesh(depsgraph, ob, brush, symm_area);
3254 break;
3256 init_boundary_grids(ob, brush, symm_area);
3257 break;
3259 init_boundary_bmesh(ob, brush, symm_area);
3260 break;
3261 }
3262 }
3263
3264 /* No active boundary under the cursor. */
3265 if (!ss.cache->boundaries[symm_area]) {
3266 return;
3267 }
3268
3269 const float strength = get_mesh_strength(ss, brush);
3270
3271 switch (brush.boundary_deform_type) {
3274 sd,
3275 ob,
3276 node_mask,
3277 *ss.cache->boundaries[symm_area],
3278 strength,
3280 break;
3283 sd,
3284 ob,
3285 node_mask,
3286 *ss.cache->boundaries[symm_area],
3287 strength,
3289 break;
3292 sd,
3293 ob,
3294 node_mask,
3295 *ss.cache->boundaries[symm_area],
3296 strength,
3298 break;
3301 sd,
3302 ob,
3303 node_mask,
3304 *ss.cache->boundaries[symm_area],
3305 strength,
3307 break;
3310 sd,
3311 ob,
3312 node_mask,
3313 *ss.cache->boundaries[symm_area],
3314 strength,
3316 break;
3319 sd,
3320 ob,
3321 node_mask,
3322 *ss.cache->boundaries[symm_area],
3323 strength,
3325 break;
3326 }
3327}
3328
3330
3331/* -------------------------------------------------------------------- */
3334
3335std::unique_ptr<SculptBoundary> data_init(const Depsgraph &depsgraph,
3336 Object &object,
3337 const Brush *brush,
3338 const int initial_vert,
3339 const float radius)
3340{
3341 /* TODO: Temporary bridge method to help in refactoring, this method should be deprecated
3342 * entirely. */
3343 const SculptSession &ss = *object.sculpt;
3344 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3345
3346 switch (pbvh.type()) {
3347 case (bke::pbvh::Type::Mesh): {
3348 return data_init_mesh(depsgraph, object, brush, initial_vert, radius);
3349 }
3350 case (bke::pbvh::Type::Grids): {
3352 const SubdivCCGCoord vert = SubdivCCGCoord::from_index(key, initial_vert);
3353 return data_init_grids(object, brush, vert, radius);
3354 }
3355 case (bke::pbvh::Type::BMesh): {
3356 BMVert *vert = BM_vert_at_index(ss.bm, initial_vert);
3357 return data_init_bmesh(object, brush, vert, radius);
3358 }
3359 }
3360
3362 return nullptr;
3363}
3364
3365std::unique_ptr<SculptBoundary> data_init_mesh(const Depsgraph &depsgraph,
3366 Object &object,
3367 const Brush *brush,
3368 const int initial_vert,
3369 const float radius)
3370{
3371 SculptSession &ss = *object.sculpt;
3372
3374
3375 Mesh &mesh = *static_cast<Mesh *>(object.data);
3376 const OffsetIndices faces = mesh.faces();
3377 const Span<int> corner_verts = mesh.corner_verts();
3378 const bke::AttributeAccessor attributes = mesh.attributes();
3379 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
3380 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
3381 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
3382
3383 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
3384
3385 const std::optional<int> boundary_initial_vert = get_closest_boundary_vert_mesh(
3386 object,
3387 vert_to_face_map,
3388 positions_eval,
3389 hide_vert,
3390 hide_poly,
3392 initial_vert,
3393 radius);
3394
3395 if (!boundary_initial_vert) {
3396 return nullptr;
3397 }
3398
3399 /* Starting from a vertex that is the limit of a boundary is ambiguous, so return nullptr instead
3400 * of forcing a random active boundary from a corner. */
3401 /* TODO: Investigate whether initial_vert should actually be boundary_initial_vert. If
3402 * initial_vert is correct, the above comment and the doc-string for the relevant function should
3403 * be fixed. */
3405 corner_verts,
3406 vert_to_face_map,
3407 hide_vert,
3408 hide_poly,
3410 initial_vert))
3411 {
3412 return nullptr;
3413 }
3414
3415 std::unique_ptr<SculptBoundary> boundary = std::make_unique<SculptBoundary>();
3416 *boundary = {};
3417
3418 const int boundary_initial_vert_index = *boundary_initial_vert;
3419 boundary->initial_vert_i = boundary_initial_vert_index;
3420 boundary->initial_vert_position = positions_eval[boundary_initial_vert_index];
3421
3422 indices_init_mesh(object,
3423 faces,
3424 corner_verts,
3425 vert_to_face_map,
3426 hide_vert,
3427 hide_poly,
3429 positions_eval,
3430 *boundary_initial_vert,
3431 *boundary);
3432
3433 const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
3435 corner_verts,
3436 vert_to_face_map,
3437 positions_eval,
3438 hide_vert,
3439 hide_poly,
3440 boundary_initial_vert_index,
3441 boundary_radius,
3442 *boundary);
3443
3444 return boundary;
3445}
3446
3447std::unique_ptr<SculptBoundary> data_init_grids(Object &object,
3448 const Brush *brush,
3449 const SubdivCCGCoord initial_vert,
3450 const float radius)
3451{
3452 SculptSession &ss = *object.sculpt;
3453
3455
3456 Mesh &mesh = *static_cast<Mesh *>(object.data);
3457 const OffsetIndices faces = mesh.faces();
3458 const Span<int> corner_verts = mesh.corner_verts();
3459 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
3460 const Span<float3> positions = subdiv_ccg.positions;
3461 const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
3462
3463 const std::optional<SubdivCCGCoord> boundary_initial_vert = get_closest_boundary_vert_grids(
3464 object, faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, initial_vert, radius);
3465
3466 if (!boundary_initial_vert) {
3467 return nullptr;
3468 }
3469
3470 /* Starting from a vertex that is the limit of a boundary is ambiguous, so return nullptr instead
3471 * of forcing a random active boundary from a corner. */
3473 faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, initial_vert))
3474 {
3475 return nullptr;
3476 }
3477
3478 std::unique_ptr<SculptBoundary> boundary = std::make_unique<SculptBoundary>();
3479 *boundary = {};
3480
3481 SubdivCCGCoord boundary_vert = *boundary_initial_vert;
3482 const int boundary_initial_vert_index = boundary_vert.to_index(key);
3483 boundary->initial_vert_i = boundary_initial_vert_index;
3484 boundary->initial_vert_position = positions[boundary_initial_vert_index];
3485
3487 object, faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, boundary_vert, *boundary);
3488
3489 const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
3490 edit_data_init_grids(subdiv_ccg, boundary_initial_vert_index, boundary_radius, *boundary);
3491
3492 return boundary;
3493}
3494
3495std::unique_ptr<SculptBoundary> data_init_bmesh(Object &object,
3496 const Brush *brush,
3497 BMVert *initial_vert,
3498 const float radius)
3499{
3500 SculptSession &ss = *object.sculpt;
3501
3504
3505 const std::optional<BMVert *> boundary_initial_vert = get_closest_boundary_vert_bmesh(
3506 object, ss.bm, *initial_vert, radius);
3507
3508 if (!boundary_initial_vert) {
3509 return nullptr;
3510 }
3511
3512 /* Starting from a vertex that is the limit of a boundary is ambiguous, so return nullptr instead
3513 * of forcing a random active boundary from a corner. */
3514 if (!is_vert_in_editable_boundary_bmesh(*initial_vert)) {
3515 return nullptr;
3516 }
3517
3518 std::unique_ptr<SculptBoundary> boundary = std::make_unique<SculptBoundary>();
3519 *boundary = {};
3520
3521 const int boundary_initial_vert_index = BM_elem_index_get(*boundary_initial_vert);
3522 boundary->initial_vert_i = boundary_initial_vert_index;
3523 boundary->initial_vert_position = (*boundary_initial_vert)->co;
3524
3525 indices_init_bmesh(object, ss.bm, **boundary_initial_vert, *boundary);
3526
3527 const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
3528 edit_data_init_bmesh(ss.bm, boundary_initial_vert_index, boundary_radius, *boundary);
3529
3530 return boundary;
3531}
3532
3534
3535/* -------------------------------------------------------------------- */
3540
3541std::unique_ptr<SculptBoundaryPreview> preview_data_init(const Depsgraph &depsgraph,
3542 Object &object,
3543 const Brush *brush,
3544 const float radius)
3545{
3546 const SculptSession &ss = *object.sculpt;
3547 ActiveVert initial_vert = ss.active_vert();
3548
3549 if (std::holds_alternative<std::monostate>(initial_vert)) {
3550 return nullptr;
3551 }
3552
3553 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3554
3555 std::unique_ptr<SculptBoundary> boundary = nullptr;
3556 switch (pbvh.type()) {
3558 boundary = data_init_mesh(depsgraph, object, brush, std::get<int>(initial_vert), radius);
3559 break;
3561 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
3562 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
3564 object, brush, SubdivCCGCoord::from_index(key, std::get<int>(initial_vert)), radius);
3565 break;
3566 }
3568 boundary = data_init_bmesh(object, brush, std::get<BMVert *>(initial_vert), radius);
3569 break;
3570 }
3571
3572 if (boundary == nullptr) {
3573 return nullptr;
3574 }
3575 std::unique_ptr<SculptBoundaryPreview> preview = std::make_unique<SculptBoundaryPreview>();
3576 preview->edges = boundary->edges;
3577 preview->pivot_position = boundary->pivot_position;
3578 preview->initial_vert_position = boundary->initial_vert_position;
3579
3580 return preview;
3581}
3582
3583void edges_preview_draw(const uint gpuattr,
3584 SculptSession &ss,
3585 const float outline_col[3],
3586 const float outline_alpha)
3587{
3588 if (!ss.boundary_preview) {
3589 return;
3590 }
3591 immUniformColor3fvAlpha(outline_col, outline_alpha);
3592 GPU_line_width(2.0f);
3593 immBegin(GPU_PRIM_LINES, ss.boundary_preview->edges.size() * 2);
3594 for (const int i : ss.boundary_preview->edges.index_range()) {
3595 immVertex3fv(gpuattr, ss.boundary_preview->edges[i].first);
3596 immVertex3fv(gpuattr, ss.boundary_preview->edges[i].second);
3597 }
3598 immEnd();
3599}
3600
3602{
3603 if (!ss.boundary_preview) {
3604 return;
3605 }
3606 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
3607 GPU_line_width(2.0f);
3609 immVertex3fv(gpuattr, ss.boundary_preview->pivot_position);
3610 immVertex3fv(gpuattr, ss.boundary_preview->initial_vert_position);
3611 immEnd();
3612}
3613
3615
3616} // namespace blender::ed::sculpt_paint::boundary
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Definition brush.cc:1577
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:73
void BKE_curvemapping_init(CurveMapping *cumap)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
std::variant< std::monostate, int, BMVert * > ActiveVert
Definition BKE_paint.hh:360
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
A BVH for high poly meshes.
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
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_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
#define M_PI
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:495
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], float angle)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
eBrushDeformTarget
@ BRUSH_DEFORM_TARGET_CLOTH_SIM
@ BRUSH_DEFORM_TARGET_GEOMETRY
@ BRUSH_BOUNDARY_DEFORM_GRAB
@ BRUSH_BOUNDARY_DEFORM_TWIST
@ BRUSH_BOUNDARY_DEFORM_BEND
@ BRUSH_BOUNDARY_DEFORM_EXPAND
@ BRUSH_BOUNDARY_DEFORM_INFLATE
@ BRUSH_BOUNDARY_DEFORM_SMOOTH
@ BRUSH_BOUNDARY_FALLOFF_CONSTANT
@ BRUSH_BOUNDARY_FALLOFF_LOOP
@ BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT
@ BRUSH_BOUNDARY_FALLOFF_RADIUS
@ CD_PROP_FLOAT
Object is a sort of wrapper for general info.
ePaintSymmetryFlags
void immEnd()
void immUniformColor4f(float r, float g, float b, float a)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fvAlpha(const float rgb[3], float a)
@ GPU_PRIM_LINES
void GPU_line_width(float width)
Definition gpu_state.cc:166
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
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
bool is_empty() const
Definition BLI_array.hh:264
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
IndexRange index_range() const
Definition BLI_array.hh:360
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
bool add(const Key &key)
Definition BLI_set.hh:248
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
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:635
Span< NodeT > nodes() const
void flush_bounds_to_parents()
Definition pbvh.cc:1306
void foreach_index(Fn &&fn) const
#define fmodf(x, y)
static float verts[][3]
static float normals[][3]
uint pos
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
static char faces[256]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
IndexRange grid_range(const int grid_area, const int grid)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
void update_node_bounds_bmesh(BMeshNode &node)
Definition pbvh.cc:1294
void update_node_bounds_mesh(Span< float3 > positions, MeshNode &node)
Definition pbvh.cc:1274
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
void update_node_bounds_grids(int grid_area, Span< float3 > positions, GridsNode &node)
Definition pbvh.cc:1283
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
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)
static void slide_data_init_bmesh(BMesh *bm, SculptBoundary &boundary)
static BLI_NOINLINE void calc_inflate_position(const Span< float3 > positions, const Span< float3 > normals, const Span< float > factors, const MutableSpan< float3 > new_positions)
static void slide_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &boundary)
static void twist_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &boundary)
static void calc_slide_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const Span< float3 > vert_slide_directions, bke::pbvh::BMeshNode &node, LocalDataBMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static BLI_NOINLINE void calc_slide_position(const Span< float3 > positions, const Span< float3 > directions, const Span< float > factors, const MutableSpan< float3 > new_positions)
static void calc_twist_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const float3 twist_pivot_position, const float3 twist_axis, bke::pbvh::BMeshNode &node, LocalDataBMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static std::optional< SubdivCCGCoord > get_closest_boundary_vert_grids(Object &object, const OffsetIndices< int > faces, const Span< int > corner_verts, const SubdivCCG &subdiv_ccg, const BitSpan boundary, const SubdivCCGCoord initial_vert, const float radius)
void pivot_line_preview_draw(const uint gpuattr, SculptSession &ss)
static void indices_init_bmesh(Object &object, BMesh *bm, BMVert &initial_boundary_vert, SculptBoundary &boundary)
static void init_boundary_grids(Object &object, const Brush &brush, const ePaintSymmetryFlags symm_area)
static void edit_data_init_grids(const SubdivCCG &subdiv_ccg, const int initial_vert_i, const float radius, SculptBoundary &boundary)
static BLI_NOINLINE void calc_average_position(const Span< float3 > vert_positions, const Span< int > vert_propagation_steps, const GroupedSpan< int > neighbors, const Span< int > propagation_steps, const MutableSpan< float > factors, const MutableSpan< float3 > average_positions)
static void calc_twist_mesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::MeshNode &node, LocalDataMesh &tls, const float3 twist_pivot_position, const float3 twist_axis, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target, const PositionDeformData &position_data)
static void calc_inflate_mesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::MeshNode &node, LocalDataMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target, const PositionDeformData &position_data)
static bool is_vert_in_editable_boundary_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_vert, const Span< bool > hide_poly, const BitSpan boundary, const int initial_vert)
std::unique_ptr< SculptBoundary > data_init_bmesh(Object &object, const Brush *brush, BMVert *initial_vert, const float radius)
static void init_falloff_bmesh(BMesh *bm, const Brush &brush, const float radius, SculptBoundary &boundary)
static bool check_counts(const int neighbor_count, const int boundary_vertex_count)
std::unique_ptr< SculptBoundaryPreview > preview_data_init(const Depsgraph &depsgraph, Object &object, const Brush *brush, const float radius)
static void calc_bend_mesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const Span< float3 > vert_pivot_positions, const Span< float3 > vert_pivot_axes, const bke::pbvh::MeshNode &node, LocalDataMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target, const PositionDeformData &position_data)
static void indices_init_mesh(Object &object, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_vert, const Span< bool > hide_poly, const BitSpan boundary_verts, const Span< float3 > vert_positions, const int initial_boundary_vert, SculptBoundary &boundary)
static void calc_smooth_bmesh(const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, bke::pbvh::BMeshNode &node, LocalDataBMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static void twist_data_init_bmesh(BMesh *bm, SculptBoundary &boundary)
static BLI_NOINLINE void calc_smooth_position(const Span< float3 > positions, const Span< float3 > average_position, const Span< float > factors, const MutableSpan< float3 > new_positions)
static float get_mesh_strength(const SculptSession &ss, const Brush &brush)
static void calc_smooth_grids(const Sculpt &sd, Object &object, SubdivCCG &subdiv_ccg, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::GridsNode &node, LocalDataGrids &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static void calc_slide_mesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const Span< float3 > vert_slide_directions, const bke::pbvh::MeshNode &node, LocalDataMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target, const PositionDeformData &position_data)
static void do_slide_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const SculptBoundary &boundary, const float strength, const eBrushDeformTarget deform_target)
static void init_boundary_mesh(const Depsgraph &depsgraph, Object &object, const Brush &brush, const ePaintSymmetryFlags symm_area)
static BLI_NOINLINE void calc_twist_position(const Span< float3 > positions, const float3 pivot_point, const float3 pivot_axis, const Span< float > factors, const MutableSpan< float3 > new_positions)
static void bend_data_init_grids(const SubdivCCG &subdiv_ccg, SculptBoundary &boundary)
static void calc_bend_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SubdivCCG &subdiv_ccg, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const Span< float3 > vert_pivot_positions, const Span< float3 > vert_pivot_axes, const bke::pbvh::GridsNode &node, LocalDataGrids &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static bool is_vert_in_editable_boundary_bmesh(BMVert &initial_vert)
static void init_boundary_bmesh(Object &object, const Brush &brush, const ePaintSymmetryFlags symm_area)
static BLI_NOINLINE void calc_bend_position(const Span< float3 > positions, const Span< float3 > pivot_positions, const Span< float3 > pivot_axes, const Span< float > factors, const MutableSpan< float3 > new_positions)
static BLI_NOINLINE void filter_uninitialized_verts(const Span< int > propagation_steps, const MutableSpan< float > factors)
static void bend_data_init_mesh(const Span< float3 > vert_positions, const Span< float3 > vert_normals, SculptBoundary &boundary)
static void edit_data_init_bmesh(BMesh *bm, const int initial_vert_i, const float radius, SculptBoundary &boundary)
static void calc_inflate_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SubdivCCG &subdiv_ccg, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::GridsNode &node, LocalDataGrids &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static void populate_twist_data(const Span< float3 > positions, SculptBoundary &boundary)
static std::pair< float, float > calc_boundary_falloff(const SculptBoundary &boundary, const Brush &brush, const float radius, const int index)
static void twist_data_init_mesh(const Span< float3 > vert_positions, SculptBoundary &boundary)
static void calc_grab_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, bke::pbvh::BMeshNode &node, LocalDataBMesh &tls, const float3 grab_delta_symmetry, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
std::unique_ptr< SculptBoundary > data_init(const Depsgraph &depsgraph, Object &object, const Brush *brush, const int initial_vert, const float radius)
bool vert_is_boundary(const GroupedSpan< int > vert_to_face_map, const Span< bool > hide_poly, const BitSpan boundary, const int vert)
Definition sculpt.cc:483
static void do_grab_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const SculptBoundary &boundary, const float strength, const eBrushDeformTarget deform_target)
static void do_bend_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const SculptBoundary &boundary, const float strength, const eBrushDeformTarget deform_target)
static void calc_grab_mesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::MeshNode &node, LocalDataMesh &tls, const float3 grab_delta_symmetry, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target, const PositionDeformData &position_data)
void edges_preview_draw(const uint gpuattr, SculptSession &ss, const float outline_col[3], const float outline_alpha)
static bool is_vert_in_editable_boundary_grids(const OffsetIndices< int > faces, const Span< int > corner_verts, const SubdivCCG &subdiv_ccg, const BitSpan boundary, const SubdivCCGCoord initial_vert)
static float displacement_from_grab_delta_get(const SculptSession &ss, const SculptBoundary &boundary)
static void calc_twist_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SubdivCCG &subdiv_ccg, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const float3 twist_pivot_position, const float3 twist_axis, const bke::pbvh::GridsNode &node, LocalDataGrids &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static std::optional< BMVert * > get_closest_boundary_vert_bmesh(Object &object, BMesh *bm, BMVert &initial_vert, const float radius)
std::unique_ptr< SculptBoundary > data_init_mesh(const Depsgraph &depsgraph, Object &object, const Brush *brush, const int initial_vert, const float radius)
static void bend_data_init_bmesh(BMesh *bm, SculptBoundary &boundary)
static void calc_inflate_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, bke::pbvh::BMeshNode &node, LocalDataBMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static void calc_bend_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const Span< float3 > vert_pivot_positions, const Span< float3 > vert_pivot_axes, bke::pbvh::BMeshNode &node, LocalDataBMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static void calc_grab_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SubdivCCG &subdiv_ccg, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::GridsNode &node, LocalDataGrids &tls, const float3 grab_delta_symmetry, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
void do_boundary_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
static void calc_smooth_mesh(const Sculpt &sd, Object &object, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const bke::pbvh::MeshNode &node, LocalDataMesh &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target, const PositionDeformData &position_data)
static void edit_data_init_mesh(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< float3 > vert_positions, Span< bool > hide_vert, Span< bool > hide_poly, const int initial_vert_i, const float radius, SculptBoundary &boundary)
static void do_inflate_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const SculptBoundary &boundary, const float strength, const eBrushDeformTarget deform_target)
static void calc_slide_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SubdivCCG &subdiv_ccg, const Span< int > vert_propagation_steps, const Span< float > vert_factors, const Span< float3 > vert_slide_directions, const bke::pbvh::GridsNode &node, LocalDataGrids &tls, const float3 symmetry_pivot, const float strength, const eBrushDeformTarget deform_target)
static void do_twist_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const SculptBoundary &boundary, const float strength, const eBrushDeformTarget deform_target)
void ensure_boundary_info(Object &object)
Definition sculpt.cc:6073
static void init_falloff_mesh(const Span< float > mask, const Brush &brush, const float radius, SculptBoundary &boundary)
static void init_falloff_grids(const SubdivCCG &subdiv_ccg, const Brush &brush, const float radius, SculptBoundary &boundary)
static void do_smooth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const SculptBoundary &boundary, const float strength, const eBrushDeformTarget deform_target)
static void add_index(SculptBoundary &boundary, const int new_index, const float distance, Set< int, BOUNDARY_INDICES_BLOCK_SIZE > &included_verts)
static void indices_init_grids(Object &object, const OffsetIndices< int > faces, const Span< int > corner_verts, const SubdivCCG &subdiv_ccg, const BitSpan boundary_verts, const SubdivCCGCoord initial_vert, SculptBoundary &boundary)
static std::optional< int > get_closest_boundary_vert_mesh(Object &object, const GroupedSpan< int > vert_to_face, const Span< float3 > vert_positions, const Span< bool > hide_vert, const Span< bool > hide_poly, const BitSpan boundary, const int initial_vert, const float radius)
static BLI_NOINLINE void calc_grab_position(const Span< float3 > positions, const float3 grab_delta, const Span< float > factors, const MutableSpan< float3 > new_positions)
std::unique_ptr< SculptBoundary > data_init_grids(Object &object, const Brush *brush, const SubdivCCGCoord initial_vert, const float radius)
static void slide_data_init_mesh(const Span< float3 > vert_positions, SculptBoundary &boundary)
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
void scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6461
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6367
void gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6405
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:141
std::optional< int > nearest_vert_calc_mesh(const bke::pbvh::Tree &pbvh, const Span< float3 > vert_positions, const Span< bool > hide_vert, const float3 &location, const float max_distance, const bool use_original)
Definition sculpt.cc:592
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7597
Vector< BMVert *, 64 > BMeshNeighborVerts
void gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6421
float3 symmetry_flip(const float3 &src, const ePaintSymmetryFlags symm)
void orig_position_data_gather_bmesh(const BMLog &bm_log, const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions, MutableSpan< float3 > normals)
void filter_verts_outside_symmetry_area(Span< float3 > positions, const float3 &pivot, ePaintSymmetryFlags symm, MutableSpan< float > factors)
Definition sculpt.cc:7849
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void translations_from_new_positions(Span< float3 > new_positions, Span< int > verts, Span< float3 > old_positions, MutableSpan< float3 > translations)
Definition sculpt.cc:7542
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7335
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6435
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
void apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7268
OrigPositionData orig_position_data_get_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
OrigPositionData orig_position_data_get_grids(const Object &object, const bke::pbvh::GridsNode &node)
std::optional< BMVert * > nearest_vert_calc_bmesh(const bke::pbvh::Tree &pbvh, const float3 &location, const float max_distance, const bool use_original)
Definition sculpt.cc:693
std::optional< SubdivCCGCoord > nearest_vert_calc_grids(const bke::pbvh::Tree &pbvh, const SubdivCCG &subdiv_ccg, const float3 &location, const float max_distance, const bool use_original)
Definition sculpt.cc:639
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:429
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6445
T safe_rcp(const T &a)
T distance(const T &a, const T &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
float3 rotate_around_axis(const float3 &vector, const float3 &center, const float3 &axis, float angle)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
#define floorf
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:542
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:184
#define BOUNDARY_STEPS_NONE
#define BOUNDARY_VERTEX_NONE
float co[3]
float no[3]
int boundary_falloff_type
struct CurveMapping * curve_distance_falloff
float boundary_offset
int deform_target
int boundary_deform_type
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
BMLog * bm_log
Definition BKE_paint.hh:392
SculptVertexInfo vertex_info
Definition BKE_paint.hh:462
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
std::unique_ptr< SculptBoundaryPreview > boundary_preview
Definition BKE_paint.hh:446
ActiveVert active_vert() const
Definition paint.cc:2367
blender::BitVector boundary
Definition BKE_paint.hh:334
int to_index(const CCGKey &key) const
static SubdivCCGCoord from_index(const CCGKey &key, int index)
SubdivCCGNeighborCoords coords
blender::Span< SubdivCCGCoord > duplicates() const
blender::Span< SubdivCCGCoord > unique() const
blender::Array< blender::float3 > normals
blender::BitGroupVector grid_hidden
blender::Array< float > masks
blender::Array< blender::float3 > positions
std::unique_ptr< auto_mask::Cache > automasking
std::unique_ptr< cloth::SimulationData > cloth_sim
std::array< std::unique_ptr< boundary::SculptBoundary >, PAINT_SYMM_AREAS > boundaries
i
Definition text_draw.cc:230