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