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 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1146 position_data.deform(translations, verts);
1147 break;
1148 }
1151 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1152 break;
1153 }
1154}
1155
1156static void calc_bend_grids(const Depsgraph &depsgraph,
1157 const Sculpt &sd,
1158 Object &object,
1159 SubdivCCG &subdiv_ccg,
1160 const Span<int> vert_propagation_steps,
1161 const Span<float> vert_factors,
1162 const Span<float3> vert_pivot_positions,
1163 const Span<float3> vert_pivot_axes,
1164 const bke::pbvh::GridsNode &node,
1165 LocalDataGrids &tls,
1166 const float3 symmetry_pivot,
1167 const float strength,
1168 const eBrushDeformTarget deform_target)
1169{
1170 SculptSession &ss = *object.sculpt;
1171 const StrokeCache &cache = *ss.cache;
1172 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1173
1174 const Span<int> grids = node.grids();
1175 const int grid_verts_num = grids.size() * key.grid_area;
1176 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
1177
1179
1180 const MutableSpan<float> factors = gather_data_grids(
1181 subdiv_ccg, vert_factors, grids, tls.factors);
1182
1183 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
1184
1185 const Span<int> propagation_steps = gather_data_grids(
1186 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
1187
1188 filter_uninitialized_verts(propagation_steps, factors);
1189 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1190
1191 scale_factors(factors, strength);
1192
1193 const Span<float3> pivot_positions = gather_data_grids(
1194 subdiv_ccg, vert_pivot_positions, grids, tls.pivot_positions);
1195 const Span<float3> pivot_axes = gather_data_grids(
1196 subdiv_ccg, vert_pivot_axes, grids, tls.pivot_axes);
1197
1198 tls.new_positions.resize(grid_verts_num);
1199 const MutableSpan<float3> new_positions = tls.new_positions;
1200 calc_bend_position(orig_data.positions, pivot_positions, pivot_axes, factors, new_positions);
1201
1202 switch (eBrushDeformTarget(deform_target)) {
1204 tls.translations.resize(grid_verts_num);
1205 const MutableSpan<float3> translations = tls.translations;
1206 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1207 translations_from_new_positions(new_positions, positions, translations);
1208
1209 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
1210 apply_translations(translations, grids, subdiv_ccg);
1211 break;
1212 }
1214 scatter_data_grids(subdiv_ccg,
1215 new_positions.as_span(),
1216 grids,
1217 cache.cloth_sim->deformation_pos.as_mutable_span());
1218 break;
1219 }
1220}
1221
1222static void calc_bend_bmesh(const Depsgraph &depsgraph,
1223 const Sculpt &sd,
1224 Object &object,
1225 const Span<int> vert_propagation_steps,
1226 const Span<float> vert_factors,
1227 const Span<float3> vert_pivot_positions,
1228 const Span<float3> vert_pivot_axes,
1230 LocalDataBMesh &tls,
1231 const float3 symmetry_pivot,
1232 const float strength,
1233 const eBrushDeformTarget deform_target)
1234
1235{
1236 SculptSession &ss = *object.sculpt;
1237 const StrokeCache &cache = *ss.cache;
1238
1240 Array<float3> orig_positions(verts.size());
1241 Array<float3> orig_normals(verts.size());
1242 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
1243
1245
1246 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
1247
1248 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1249
1250 const Span<int> propagation_steps = gather_data_bmesh(
1251 vert_propagation_steps, verts, tls.propagation_steps);
1252
1253 filter_uninitialized_verts(propagation_steps, factors);
1254 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
1255
1256 scale_factors(factors, strength);
1257
1258 const Span<float3> pivot_positions = gather_data_bmesh(
1259 vert_pivot_positions, verts, tls.pivot_positions);
1260 const Span<float3> pivot_axes = gather_data_bmesh(vert_pivot_axes, verts, tls.pivot_axes);
1261
1262 tls.new_positions.resize(verts.size());
1263 const MutableSpan<float3> new_positions = tls.new_positions;
1264 calc_bend_position(orig_positions, pivot_positions, pivot_axes, factors, new_positions);
1265
1266 switch (eBrushDeformTarget(deform_target)) {
1269 tls.translations.resize(verts.size());
1270 const MutableSpan<float3> translations = tls.translations;
1271 translations_from_new_positions(new_positions, positions, translations);
1272
1273 clip_and_lock_translations(sd, ss, orig_positions, translations);
1274 apply_translations(translations, verts);
1275 break;
1276 }
1279 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1280 break;
1281 }
1282}
1283
1284static void do_bend_brush(const Depsgraph &depsgraph,
1285 const Sculpt &sd,
1286 Object &object,
1287 const IndexMask &node_mask,
1288 const SculptBoundary &boundary,
1289 const float strength,
1290 const eBrushDeformTarget deform_target)
1291{
1292 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1293 switch (pbvh.type()) {
1294 case bke::pbvh::Type::Mesh: {
1295 const PositionDeformData position_data(depsgraph, object);
1296
1299 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1300 LocalDataMesh &tls = all_tls.local();
1302 sd,
1303 object,
1304 boundary.edit_info.propagation_steps_num,
1305 boundary.edit_info.strength_factor,
1306 boundary.bend.pivot_positions,
1307 boundary.bend.pivot_rotation_axis,
1308 nodes[i],
1309 tls,
1310 boundary.initial_vert_position,
1311 strength,
1312 deform_target,
1313 position_data);
1315 });
1316 break;
1317 }
1319 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1320 MutableSpan<float3> positions = subdiv_ccg.positions;
1323 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1324 LocalDataGrids &tls = all_tls.local();
1326 sd,
1327 object,
1328 subdiv_ccg,
1329 boundary.edit_info.propagation_steps_num,
1330 boundary.edit_info.strength_factor,
1331 boundary.bend.pivot_positions,
1332 boundary.bend.pivot_rotation_axis,
1333 nodes[i],
1334 tls,
1335 boundary.initial_vert_position,
1336 strength,
1337 deform_target);
1338 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1339 });
1340 break;
1341 }
1345 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1346 LocalDataBMesh &tls = all_tls.local();
1348 sd,
1349 object,
1350 boundary.edit_info.propagation_steps_num,
1351 boundary.edit_info.strength_factor,
1352 boundary.bend.pivot_positions,
1353 boundary.bend.pivot_rotation_axis,
1354 nodes[i],
1355 tls,
1356 boundary.initial_vert_position,
1357 strength,
1358 deform_target);
1360 });
1361 break;
1362 }
1363 }
1364 pbvh.tag_positions_changed(node_mask);
1366}
1367
1369
1370/* -------------------------------------------------------------------- */
1373
1375 const Span<float3> directions,
1376 const Span<float> factors,
1377 const MutableSpan<float3> new_positions)
1378{
1379 BLI_assert(positions.size() == directions.size());
1380 BLI_assert(positions.size() == factors.size());
1381 BLI_assert(positions.size() == new_positions.size());
1382
1383 for (const int i : positions.index_range()) {
1384 new_positions[i] = positions[i] + (directions[i] * factors[i]);
1385 }
1386}
1387
1388static void calc_slide_mesh(const Depsgraph &depsgraph,
1389 const Sculpt &sd,
1390 Object &object,
1391 const Span<int> vert_propagation_steps,
1392 const Span<float> vert_factors,
1393 const Span<float3> vert_slide_directions,
1394 const bke::pbvh::MeshNode &node,
1395 LocalDataMesh &tls,
1396 const float3 symmetry_pivot,
1397 const float strength,
1398 const eBrushDeformTarget deform_target,
1399 const PositionDeformData &position_data)
1400{
1401 SculptSession &ss = *object.sculpt;
1402 const StrokeCache &cache = *ss.cache;
1403
1404 const Span<int> verts = node.verts();
1405 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1406
1408
1409 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1410
1411 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1412
1413 const Span<int> propagation_steps = gather_data_mesh(
1414 vert_propagation_steps, verts, tls.propagation_steps);
1415
1416 filter_uninitialized_verts(propagation_steps, factors);
1417 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1418
1419 scale_factors(factors, strength);
1420
1421 tls.new_positions.resize(verts.size());
1422 const MutableSpan<float3> new_positions = tls.new_positions;
1423
1424 const Span<float3> slide_directions = gather_data_mesh(
1425 vert_slide_directions, verts, tls.slide_directions);
1426
1427 calc_slide_position(orig_data.positions, slide_directions, factors, new_positions);
1428
1429 switch (eBrushDeformTarget(deform_target)) {
1431 tls.translations.resize(verts.size());
1432 const MutableSpan<float3> translations = tls.translations;
1433 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1434 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1435 position_data.deform(translations, verts);
1436 break;
1437 }
1440 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1441 break;
1442 }
1443}
1444
1445static void calc_slide_grids(const Depsgraph &depsgraph,
1446 const Sculpt &sd,
1447 Object &object,
1448 SubdivCCG &subdiv_ccg,
1449 const Span<int> vert_propagation_steps,
1450 const Span<float> vert_factors,
1451 const Span<float3> vert_slide_directions,
1452 const bke::pbvh::GridsNode &node,
1453 LocalDataGrids &tls,
1454 const float3 symmetry_pivot,
1455 const float strength,
1456 const eBrushDeformTarget deform_target)
1457{
1458 SculptSession &ss = *object.sculpt;
1459 const StrokeCache &cache = *ss.cache;
1460 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1461
1462 const Span<int> grids = node.grids();
1463 const int grid_verts_num = grids.size() * key.grid_area;
1464 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
1465
1467
1468 const MutableSpan<float> factors = gather_data_grids(
1469 subdiv_ccg, vert_factors, grids, tls.factors);
1470
1471 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
1472
1473 const Span<int> propagation_steps = gather_data_grids(
1474 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
1475
1476 filter_uninitialized_verts(propagation_steps, factors);
1477 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1478
1479 scale_factors(factors, strength);
1480
1481 tls.new_positions.resize(grid_verts_num);
1482 const MutableSpan<float3> new_positions = tls.new_positions;
1483
1484 const Span<float3> slide_directions = gather_data_grids(
1485 subdiv_ccg, vert_slide_directions, grids, tls.pivot_positions);
1486
1487 calc_slide_position(orig_data.positions, slide_directions, factors, new_positions);
1488
1489 switch (eBrushDeformTarget(deform_target)) {
1491 tls.translations.resize(grid_verts_num);
1492 const MutableSpan<float3> translations = tls.translations;
1493 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1494 translations_from_new_positions(new_positions, positions, translations);
1495
1496 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
1497 apply_translations(translations, grids, subdiv_ccg);
1498 break;
1499 }
1501 scatter_data_grids(subdiv_ccg,
1502 new_positions.as_span(),
1503 grids,
1504 cache.cloth_sim->deformation_pos.as_mutable_span());
1505 break;
1506 }
1507}
1508
1509static void calc_slide_bmesh(const Depsgraph &depsgraph,
1510 const Sculpt &sd,
1511 Object &object,
1512 const Span<int> vert_propagation_steps,
1513 const Span<float> vert_factors,
1514 const Span<float3> vert_slide_directions,
1516 LocalDataBMesh &tls,
1517 const float3 symmetry_pivot,
1518 const float strength,
1519 const eBrushDeformTarget deform_target)
1520
1521{
1522 SculptSession &ss = *object.sculpt;
1523 const StrokeCache &cache = *ss.cache;
1524
1526 Array<float3> orig_positions(verts.size());
1527 Array<float3> orig_normals(verts.size());
1528 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
1529
1531
1532 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
1533
1534 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1535
1536 const Span<int> propagation_steps = gather_data_bmesh(
1537 vert_propagation_steps, verts, tls.propagation_steps);
1538
1539 filter_uninitialized_verts(propagation_steps, factors);
1540 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
1541
1542 scale_factors(factors, strength);
1543
1544 const Span<float3> slide_directions = gather_data_bmesh(
1545 vert_slide_directions, verts, tls.pivot_positions);
1546
1547 tls.new_positions.resize(verts.size());
1548 const MutableSpan<float3> new_positions = tls.new_positions;
1549 calc_slide_position(orig_positions, slide_directions, factors, new_positions);
1550
1551 switch (eBrushDeformTarget(deform_target)) {
1554 tls.translations.resize(verts.size());
1555 const MutableSpan<float3> translations = tls.translations;
1556 translations_from_new_positions(new_positions, positions, translations);
1557
1558 clip_and_lock_translations(sd, ss, orig_positions, translations);
1559 apply_translations(translations, verts);
1560 break;
1561 }
1564 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1565 break;
1566 }
1567}
1568
1569static void do_slide_brush(const Depsgraph &depsgraph,
1570 const Sculpt &sd,
1571 Object &object,
1572 const IndexMask &node_mask,
1573 const SculptBoundary &boundary,
1574 const float strength,
1575 const eBrushDeformTarget deform_target)
1576{
1577 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1578 switch (pbvh.type()) {
1579 case bke::pbvh::Type::Mesh: {
1580 const PositionDeformData position_data(depsgraph, object);
1581
1584 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1585 LocalDataMesh &tls = all_tls.local();
1587 sd,
1588 object,
1589 boundary.edit_info.propagation_steps_num,
1590 boundary.edit_info.strength_factor,
1591 boundary.slide.directions,
1592 nodes[i],
1593 tls,
1594 boundary.initial_vert_position,
1595 strength,
1596 deform_target,
1597 position_data);
1599 });
1600 break;
1601 }
1603 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1604 MutableSpan<float3> positions = subdiv_ccg.positions;
1607 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1608 LocalDataGrids &tls = all_tls.local();
1610 sd,
1611 object,
1612 subdiv_ccg,
1613 boundary.edit_info.propagation_steps_num,
1614 boundary.edit_info.strength_factor,
1615 boundary.slide.directions,
1616 nodes[i],
1617 tls,
1618 boundary.initial_vert_position,
1619 strength,
1620 deform_target);
1621 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1622 });
1623 break;
1624 }
1628 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1629 LocalDataBMesh &tls = all_tls.local();
1631 sd,
1632 object,
1633 boundary.edit_info.propagation_steps_num,
1634 boundary.edit_info.strength_factor,
1635 boundary.slide.directions,
1636 nodes[i],
1637 tls,
1638 boundary.initial_vert_position,
1639 strength,
1640 deform_target);
1642 });
1643 break;
1644 }
1645 }
1646 pbvh.tag_positions_changed(node_mask);
1648}
1649
1651
1652/* -------------------------------------------------------------------- */
1655
1657 const Span<float3> normals,
1658 const Span<float> factors,
1659 const MutableSpan<float3> new_positions)
1660{
1661 BLI_assert(positions.size() == normals.size());
1662 BLI_assert(positions.size() == factors.size());
1663 BLI_assert(positions.size() == new_positions.size());
1664
1665 for (const int i : positions.index_range()) {
1666 new_positions[i] = positions[i] + (normals[i] * factors[i]);
1667 }
1668}
1669
1670static void calc_inflate_mesh(const Depsgraph &depsgraph,
1671 const Sculpt &sd,
1672 Object &object,
1673 const Span<int> vert_propagation_steps,
1674 const Span<float> vert_factors,
1675 const bke::pbvh::MeshNode &node,
1676 LocalDataMesh &tls,
1677 const float3 symmetry_pivot,
1678 const float strength,
1679 const eBrushDeformTarget deform_target,
1680 const PositionDeformData &position_data)
1681{
1682 SculptSession &ss = *object.sculpt;
1683 const StrokeCache &cache = *ss.cache;
1684
1685 const Span<int> verts = node.verts();
1686 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1687
1689
1690 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1691
1692 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1693
1694 const Span<int> propagation_steps = gather_data_mesh(
1695 vert_propagation_steps, verts, tls.propagation_steps);
1696
1697 filter_uninitialized_verts(propagation_steps, factors);
1698 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1699
1700 scale_factors(factors, strength);
1701
1702 tls.new_positions.resize(verts.size());
1703 const MutableSpan<float3> new_positions = tls.new_positions;
1704 calc_inflate_position(orig_data.positions, orig_data.normals, factors, new_positions);
1705
1706 switch (eBrushDeformTarget(deform_target)) {
1708 tls.translations.resize(verts.size());
1709 const MutableSpan<float3> translations = tls.translations;
1710 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1711 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1712 position_data.deform(translations, verts);
1713 break;
1714 }
1717 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1718 break;
1719 }
1720}
1721
1722static void calc_inflate_grids(const Depsgraph &depsgraph,
1723 const Sculpt &sd,
1724 Object &object,
1725 SubdivCCG &subdiv_ccg,
1726 const Span<int> vert_propagation_steps,
1727 const Span<float> vert_factors,
1728 const bke::pbvh::GridsNode &node,
1729 LocalDataGrids &tls,
1730 const float3 symmetry_pivot,
1731 const float strength,
1732 const eBrushDeformTarget deform_target)
1733{
1734 SculptSession &ss = *object.sculpt;
1735 const StrokeCache &cache = *ss.cache;
1736 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1737
1738 const Span<int> grids = node.grids();
1739 const int grid_verts_num = grids.size() * key.grid_area;
1740 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
1741
1743
1744 const MutableSpan<float> factors = gather_data_grids(
1745 subdiv_ccg, vert_factors, grids, tls.factors);
1746
1747 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
1748
1749 const Span<int> propagation_steps = gather_data_grids(
1750 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
1751
1752 filter_uninitialized_verts(propagation_steps, factors);
1753 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1754
1755 scale_factors(factors, strength);
1756
1757 tls.new_positions.resize(grid_verts_num);
1758 const MutableSpan<float3> new_positions = tls.new_positions;
1759 calc_inflate_position(orig_data.positions, orig_data.normals, factors, new_positions);
1760
1761 switch (eBrushDeformTarget(deform_target)) {
1763 tls.translations.resize(grid_verts_num);
1764 const MutableSpan<float3> translations = tls.translations;
1765 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1766 translations_from_new_positions(new_positions, positions, translations);
1767
1768 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
1769 apply_translations(translations, grids, subdiv_ccg);
1770 break;
1771 }
1773 scatter_data_grids(subdiv_ccg,
1774 new_positions.as_span(),
1775 grids,
1776 cache.cloth_sim->deformation_pos.as_mutable_span());
1777 break;
1778 }
1779}
1780
1781static void calc_inflate_bmesh(const Depsgraph &depsgraph,
1782 const Sculpt &sd,
1783 Object &object,
1784 const Span<int> vert_propagation_steps,
1785 const Span<float> vert_factors,
1787 LocalDataBMesh &tls,
1788 const float3 symmetry_pivot,
1789 const float strength,
1790 const eBrushDeformTarget deform_target)
1791
1792{
1793 SculptSession &ss = *object.sculpt;
1794 const StrokeCache &cache = *ss.cache;
1795
1797 Array<float3> orig_positions(verts.size());
1798 Array<float3> orig_normals(verts.size());
1799 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
1800
1802
1803 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
1804
1805 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1806
1807 const Span<int> propagation_steps = gather_data_bmesh(
1808 vert_propagation_steps, verts, tls.propagation_steps);
1809
1810 filter_uninitialized_verts(propagation_steps, factors);
1811 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
1812
1813 scale_factors(factors, strength);
1814
1815 tls.new_positions.resize(verts.size());
1816 const MutableSpan<float3> new_positions = tls.new_positions;
1817 calc_inflate_position(orig_positions, orig_normals, factors, new_positions);
1818
1819 switch (eBrushDeformTarget(deform_target)) {
1822 tls.translations.resize(verts.size());
1823 const MutableSpan<float3> translations = tls.translations;
1824 translations_from_new_positions(new_positions, positions, translations);
1825
1826 clip_and_lock_translations(sd, ss, orig_positions, translations);
1827 apply_translations(translations, verts);
1828 break;
1829 }
1832 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1833 break;
1834 }
1835}
1836
1837static void do_inflate_brush(const Depsgraph &depsgraph,
1838 const Sculpt &sd,
1839 Object &object,
1840 const IndexMask &node_mask,
1841 const SculptBoundary &boundary,
1842 const float strength,
1843 const eBrushDeformTarget deform_target)
1844{
1845 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1846 switch (pbvh.type()) {
1847 case bke::pbvh::Type::Mesh: {
1848 const PositionDeformData position_data(depsgraph, object);
1849
1852 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1853 LocalDataMesh &tls = all_tls.local();
1855 sd,
1856 object,
1857 boundary.edit_info.propagation_steps_num,
1858 boundary.edit_info.strength_factor,
1859 nodes[i],
1860 tls,
1861 boundary.initial_vert_position,
1862 strength,
1863 deform_target,
1864 position_data);
1866 });
1867 break;
1868 }
1870 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1871 MutableSpan<float3> positions = subdiv_ccg.positions;
1874 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1875 LocalDataGrids &tls = all_tls.local();
1877 sd,
1878 object,
1879 subdiv_ccg,
1880 boundary.edit_info.propagation_steps_num,
1881 boundary.edit_info.strength_factor,
1882 nodes[i],
1883 tls,
1884 boundary.initial_vert_position,
1885 strength,
1886 deform_target);
1887 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
1888 });
1889 break;
1890 }
1894 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1895 LocalDataBMesh &tls = all_tls.local();
1897 sd,
1898 object,
1899 boundary.edit_info.propagation_steps_num,
1900 boundary.edit_info.strength_factor,
1901 nodes[i],
1902 tls,
1903 boundary.initial_vert_position,
1904 strength,
1905 deform_target);
1907 });
1908 break;
1909 }
1910 }
1911 pbvh.tag_positions_changed(node_mask);
1913}
1914
1916
1917/* -------------------------------------------------------------------- */
1920
1922 const float3 grab_delta,
1923 const Span<float> factors,
1924 const MutableSpan<float3> new_positions)
1925{
1926 BLI_assert(positions.size() == factors.size());
1927 BLI_assert(positions.size() == new_positions.size());
1928
1929 for (const int i : positions.index_range()) {
1930 new_positions[i] = positions[i] + (grab_delta * factors[i]);
1931 }
1932}
1933
1934static void calc_grab_mesh(const Depsgraph &depsgraph,
1935 const Sculpt &sd,
1936 Object &object,
1937 const Span<int> vert_propagation_steps,
1938 const Span<float> vert_factors,
1939 const bke::pbvh::MeshNode &node,
1940 LocalDataMesh &tls,
1941 const float3 grab_delta_symmetry,
1942 const float3 symmetry_pivot,
1943 const float strength,
1944 const eBrushDeformTarget deform_target,
1945 const PositionDeformData &position_data)
1946{
1947 SculptSession &ss = *object.sculpt;
1948 const StrokeCache &cache = *ss.cache;
1949
1950 const Span<int> verts = node.verts();
1951 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
1952
1954
1955 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
1956
1957 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
1958
1959 const Span<int> propagation_steps = gather_data_mesh(
1960 vert_propagation_steps, verts, tls.propagation_steps);
1961
1962 filter_uninitialized_verts(propagation_steps, factors);
1963 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
1964
1965 scale_factors(factors, strength);
1966
1967 tls.new_positions.resize(verts.size());
1968 const MutableSpan<float3> new_positions = tls.new_positions;
1969 calc_grab_position(orig_data.positions, grab_delta_symmetry, factors, new_positions);
1970
1971 switch (eBrushDeformTarget(deform_target)) {
1973 tls.translations.resize(verts.size());
1974 const MutableSpan<float3> translations = tls.translations;
1975 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
1976 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
1977 position_data.deform(translations, verts);
1978 break;
1979 }
1982 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
1983 break;
1984 }
1985}
1986
1987static void calc_grab_grids(const Depsgraph &depsgraph,
1988 const Sculpt &sd,
1989 Object &object,
1990 SubdivCCG &subdiv_ccg,
1991 const Span<int> vert_propagation_steps,
1992 const Span<float> vert_factors,
1993 const bke::pbvh::GridsNode &node,
1994 LocalDataGrids &tls,
1995 const float3 grab_delta_symmetry,
1996 const float3 symmetry_pivot,
1997 const float strength,
1998 const eBrushDeformTarget deform_target)
1999{
2000 SculptSession &ss = *object.sculpt;
2001 const StrokeCache &cache = *ss.cache;
2002 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2003
2004 const Span<int> grids = node.grids();
2005 const int grid_verts_num = grids.size() * key.grid_area;
2006 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
2007
2009
2010 const MutableSpan<float> factors = gather_data_grids(
2011 subdiv_ccg, vert_factors, grids, tls.factors);
2012
2013 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
2014
2015 const Span<int> propagation_steps = gather_data_grids(
2016 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
2017
2018 filter_uninitialized_verts(propagation_steps, factors);
2019 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2020
2021 scale_factors(factors, strength);
2022
2023 tls.new_positions.resize(grid_verts_num);
2024 const MutableSpan<float3> new_positions = tls.new_positions;
2025 calc_grab_position(orig_data.positions, grab_delta_symmetry, factors, new_positions);
2026
2027 switch (eBrushDeformTarget(deform_target)) {
2029 tls.translations.resize(grid_verts_num);
2030 const MutableSpan<float3> translations = tls.translations;
2031 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
2032 translations_from_new_positions(new_positions, positions, translations);
2033
2034 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
2035 apply_translations(translations, grids, subdiv_ccg);
2036 break;
2037 }
2039 scatter_data_grids(subdiv_ccg,
2040 new_positions.as_span(),
2041 grids,
2042 cache.cloth_sim->deformation_pos.as_mutable_span());
2043 break;
2044 }
2045}
2046
2047static void calc_grab_bmesh(const Depsgraph &depsgraph,
2048 const Sculpt &sd,
2049 Object &object,
2050 const Span<int> vert_propagation_steps,
2051 const Span<float> vert_factors,
2053 LocalDataBMesh &tls,
2054 const float3 grab_delta_symmetry,
2055 const float3 symmetry_pivot,
2056 const float strength,
2057 const eBrushDeformTarget deform_target)
2058
2059{
2060 SculptSession &ss = *object.sculpt;
2061 const StrokeCache &cache = *ss.cache;
2062
2064 Array<float3> orig_positions(verts.size());
2065 Array<float3> orig_normals(verts.size());
2066 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
2067
2069
2070 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
2071
2072 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
2073
2074 const Span<int> propagation_steps = gather_data_bmesh(
2075 vert_propagation_steps, verts, tls.propagation_steps);
2076
2077 filter_uninitialized_verts(propagation_steps, factors);
2078 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
2079
2080 scale_factors(factors, strength);
2081
2082 tls.new_positions.resize(verts.size());
2083 const MutableSpan<float3> new_positions = tls.new_positions;
2084 calc_grab_position(orig_positions, grab_delta_symmetry, factors, new_positions);
2085
2086 switch (eBrushDeformTarget(deform_target)) {
2089 tls.translations.resize(verts.size());
2090 const MutableSpan<float3> translations = tls.translations;
2091 translations_from_new_positions(new_positions, positions, translations);
2092
2093 clip_and_lock_translations(sd, ss, orig_positions, translations);
2094 apply_translations(translations, verts);
2095 break;
2096 }
2099 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2100 break;
2101 }
2102}
2103
2104static void do_grab_brush(const Depsgraph &depsgraph,
2105 const Sculpt &sd,
2106 Object &object,
2107 const IndexMask &node_mask,
2108 const SculptBoundary &boundary,
2109 const float strength,
2110 const eBrushDeformTarget deform_target)
2111{
2112 SculptSession &ss = *object.sculpt;
2113 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2114 switch (pbvh.type()) {
2115 case bke::pbvh::Type::Mesh: {
2116 const PositionDeformData position_data(depsgraph, object);
2117
2120 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2121 LocalDataMesh &tls = all_tls.local();
2123 sd,
2124 object,
2125 boundary.edit_info.propagation_steps_num,
2126 boundary.edit_info.strength_factor,
2127 nodes[i],
2128 tls,
2130 boundary.initial_vert_position,
2131 strength,
2132 deform_target,
2133 position_data);
2135 });
2136 break;
2137 }
2139 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2140 MutableSpan<float3> positions = subdiv_ccg.positions;
2143 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2144 LocalDataGrids &tls = all_tls.local();
2146 sd,
2147 object,
2148 subdiv_ccg,
2149 boundary.edit_info.propagation_steps_num,
2150 boundary.edit_info.strength_factor,
2151 nodes[i],
2152 tls,
2154 boundary.initial_vert_position,
2155 strength,
2156 deform_target);
2157 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2158 });
2159 break;
2160 }
2164 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2165 LocalDataBMesh &tls = all_tls.local();
2167 sd,
2168 object,
2169 boundary.edit_info.propagation_steps_num,
2170 boundary.edit_info.strength_factor,
2171 nodes[i],
2172 tls,
2174 boundary.initial_vert_position,
2175 strength,
2176 deform_target);
2178 });
2179 break;
2180 }
2181 }
2182 pbvh.tag_positions_changed(node_mask);
2184}
2185
2187
2188/* -------------------------------------------------------------------- */
2191
2193 const float3 pivot_point,
2194 const float3 pivot_axis,
2195 const Span<float> factors,
2196 const MutableSpan<float3> new_positions)
2197{
2198 BLI_assert(positions.size() == factors.size());
2199 BLI_assert(positions.size() == new_positions.size());
2200
2201 for (const int i : positions.index_range()) {
2202 new_positions[i] = math::rotate_around_axis(positions[i], pivot_point, pivot_axis, factors[i]);
2203 }
2204}
2205
2206static void calc_twist_mesh(const Depsgraph &depsgraph,
2207 const Sculpt &sd,
2208 Object &object,
2209 const Span<int> vert_propagation_steps,
2210 const Span<float> vert_factors,
2211 const bke::pbvh::MeshNode &node,
2212 LocalDataMesh &tls,
2213 const float3 twist_pivot_position,
2214 const float3 twist_axis,
2215 const float3 symmetry_pivot,
2216 const float strength,
2217 const eBrushDeformTarget deform_target,
2218 const PositionDeformData &position_data)
2219{
2220 SculptSession &ss = *object.sculpt;
2221 const StrokeCache &cache = *ss.cache;
2222
2223 const Span<int> verts = node.verts();
2224 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
2225
2227
2228 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
2229
2230 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
2231
2232 const Span<int> propagation_steps = gather_data_mesh(
2233 vert_propagation_steps, verts, tls.propagation_steps);
2234
2235 filter_uninitialized_verts(propagation_steps, factors);
2236 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2237
2238 scale_factors(factors, strength);
2239
2240 tls.new_positions.resize(verts.size());
2241 const MutableSpan<float3> new_positions = tls.new_positions;
2243 orig_data.positions, twist_pivot_position, twist_axis, factors, new_positions);
2244
2245 switch (eBrushDeformTarget(deform_target)) {
2247 tls.translations.resize(verts.size());
2248 const MutableSpan<float3> translations = tls.translations;
2249 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
2250 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
2251 position_data.deform(translations, verts);
2252 break;
2253 }
2256 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2257 break;
2258 }
2259}
2260
2261static void calc_twist_grids(const Depsgraph &depsgraph,
2262 const Sculpt &sd,
2263 Object &object,
2264 SubdivCCG &subdiv_ccg,
2265 const Span<int> vert_propagation_steps,
2266 const Span<float> vert_factors,
2267 const float3 twist_pivot_position,
2268 const float3 twist_axis,
2269 const bke::pbvh::GridsNode &node,
2270 LocalDataGrids &tls,
2271 const float3 symmetry_pivot,
2272 const float strength,
2273 const eBrushDeformTarget deform_target)
2274{
2275 SculptSession &ss = *object.sculpt;
2276 const StrokeCache &cache = *ss.cache;
2277 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2278
2279 const Span<int> grids = node.grids();
2280 const int grid_verts_num = grids.size() * key.grid_area;
2281 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
2282
2284
2285 const MutableSpan<float> factors = gather_data_grids(
2286 subdiv_ccg, vert_factors, grids, tls.factors);
2287
2288 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
2289
2290 const Span<int> propagation_steps = gather_data_grids(
2291 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
2292
2293 filter_uninitialized_verts(propagation_steps, factors);
2294 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2295
2296 scale_factors(factors, strength);
2297
2298 tls.new_positions.resize(grid_verts_num);
2299 const MutableSpan<float3> new_positions = tls.new_positions;
2301 orig_data.positions, twist_pivot_position, twist_axis, factors, new_positions);
2302
2303 switch (eBrushDeformTarget(deform_target)) {
2305 tls.translations.resize(grid_verts_num);
2306 const MutableSpan<float3> translations = tls.translations;
2307 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
2308 translations_from_new_positions(new_positions, positions, translations);
2309
2310 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
2311 apply_translations(translations, grids, subdiv_ccg);
2312 break;
2313 }
2315 scatter_data_grids(subdiv_ccg,
2316 new_positions.as_span(),
2317 grids,
2318 cache.cloth_sim->deformation_pos.as_mutable_span());
2319 break;
2320 }
2321}
2322
2323static void calc_twist_bmesh(const Depsgraph &depsgraph,
2324 const Sculpt &sd,
2325 Object &object,
2326 const Span<int> vert_propagation_steps,
2327 const Span<float> vert_factors,
2328 const float3 twist_pivot_position,
2329 const float3 twist_axis,
2331 LocalDataBMesh &tls,
2332 const float3 symmetry_pivot,
2333 const float strength,
2334 const eBrushDeformTarget deform_target)
2335
2336{
2337 SculptSession &ss = *object.sculpt;
2338 const StrokeCache &cache = *ss.cache;
2339
2341 Array<float3> orig_positions(verts.size());
2342 Array<float3> orig_normals(verts.size());
2343 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
2344
2346
2347 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
2348
2349 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
2350
2351 const Span<int> propagation_steps = gather_data_bmesh(
2352 vert_propagation_steps, verts, tls.propagation_steps);
2353
2354 filter_uninitialized_verts(propagation_steps, factors);
2355 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
2356
2357 scale_factors(factors, strength);
2358
2359 tls.new_positions.resize(verts.size());
2360 const MutableSpan<float3> new_positions = tls.new_positions;
2361 calc_twist_position(orig_positions, twist_pivot_position, twist_axis, factors, new_positions);
2362
2363 switch (eBrushDeformTarget(deform_target)) {
2366 tls.translations.resize(verts.size());
2367 const MutableSpan<float3> translations = tls.translations;
2368 translations_from_new_positions(new_positions, positions, translations);
2369
2370 clip_and_lock_translations(sd, ss, orig_positions, translations);
2371 apply_translations(translations, verts);
2372 break;
2373 }
2376 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2377 break;
2378 }
2379}
2380
2381static void do_twist_brush(const Depsgraph &depsgraph,
2382 const Sculpt &sd,
2383 Object &object,
2384 const IndexMask &node_mask,
2385 const SculptBoundary &boundary,
2386 const float strength,
2387 const eBrushDeformTarget deform_target)
2388{
2389 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2390 switch (pbvh.type()) {
2391 case bke::pbvh::Type::Mesh: {
2392 const PositionDeformData position_data(depsgraph, object);
2393
2396 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2397 LocalDataMesh &tls = all_tls.local();
2399 sd,
2400 object,
2401 boundary.edit_info.propagation_steps_num,
2402 boundary.edit_info.strength_factor,
2403 nodes[i],
2404 tls,
2405 boundary.twist.pivot_position,
2406 boundary.twist.rotation_axis,
2407 boundary.initial_vert_position,
2408 strength,
2409 deform_target,
2410 position_data);
2412 });
2413 break;
2414 }
2416 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2417 MutableSpan<float3> positions = subdiv_ccg.positions;
2420 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2421 LocalDataGrids &tls = all_tls.local();
2423 sd,
2424 object,
2425 subdiv_ccg,
2426 boundary.edit_info.propagation_steps_num,
2427 boundary.edit_info.strength_factor,
2428 boundary.twist.pivot_position,
2429 boundary.twist.rotation_axis,
2430 nodes[i],
2431 tls,
2432 boundary.initial_vert_position,
2433 strength,
2434 deform_target);
2435 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2436 });
2437 break;
2438 }
2442 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2443 LocalDataBMesh &tls = all_tls.local();
2445 sd,
2446 object,
2447 boundary.edit_info.propagation_steps_num,
2448 boundary.edit_info.strength_factor,
2449 boundary.twist.pivot_position,
2450 boundary.twist.rotation_axis,
2451 nodes[i],
2452 tls,
2453 boundary.initial_vert_position,
2454 strength,
2455 deform_target);
2457 });
2458 break;
2459 }
2460 }
2461 pbvh.tag_positions_changed(node_mask);
2463}
2464
2466
2467/* -------------------------------------------------------------------- */
2470
2472 const Span<float3> average_position,
2473 const Span<float> factors,
2474 const MutableSpan<float3> new_positions)
2475{
2476 BLI_assert(positions.size() == average_position.size());
2477 BLI_assert(positions.size() == factors.size());
2478 BLI_assert(positions.size() == new_positions.size());
2479
2480 for (const int i : positions.index_range()) {
2481 const float3 to_smooth = average_position[i] - positions[i];
2482 new_positions[i] = positions[i] + (to_smooth * factors[i]);
2483 }
2484}
2485
2486BLI_NOINLINE static void calc_average_position(const Span<float3> vert_positions,
2487 const Span<int> vert_propagation_steps,
2488 const GroupedSpan<int> neighbors,
2489 const Span<int> propagation_steps,
2490 const MutableSpan<float> factors,
2491 const MutableSpan<float3> average_positions)
2492{
2493 BLI_assert(vert_positions.size() == vert_propagation_steps.size());
2494 BLI_assert(factors.size() == neighbors.size());
2495 BLI_assert(factors.size() == propagation_steps.size());
2496 BLI_assert(factors.size() == average_positions.size());
2497
2498 for (const int i : neighbors.index_range()) {
2499 average_positions[i] = float3(0.0f);
2500 int valid_neighbors = 0;
2501 for (const int neighbor : neighbors[i]) {
2502 if (propagation_steps[i] == vert_propagation_steps[neighbor]) {
2503 average_positions[i] += vert_positions[neighbor];
2504 valid_neighbors++;
2505 }
2506 }
2507 average_positions[i] *= math::safe_rcp(float(valid_neighbors));
2508 if (valid_neighbors == 0) {
2509 factors[i] = 0.0f;
2510 }
2511 }
2512}
2513
2514BLI_NOINLINE static void calc_average_position(const Span<int> vert_propagation_steps,
2515 const GroupedSpan<BMVert *> neighbors,
2516 const Span<int> propagation_steps,
2517 const MutableSpan<float> factors,
2518 const MutableSpan<float3> average_positions)
2519{
2520 BLI_assert(neighbors.size() == propagation_steps.size());
2521 BLI_assert(neighbors.size() == factors.size());
2522 BLI_assert(neighbors.size() == average_positions.size());
2523
2524 for (const int i : neighbors.index_range()) {
2525 average_positions[i] = float3(0.0f);
2526 int valid_neighbors = 0;
2527 for (BMVert *neighbor : neighbors[i]) {
2528 const int neighbor_idx = BM_elem_index_get(neighbor);
2529 if (propagation_steps[i] == vert_propagation_steps[neighbor_idx]) {
2530 average_positions[i] += neighbor->co;
2531 valid_neighbors++;
2532 }
2533 }
2534 average_positions[i] *= math::safe_rcp(float(valid_neighbors));
2535 if (valid_neighbors == 0) {
2536 factors[i] = 0.0f;
2537 }
2538 }
2539}
2540
2541static void calc_smooth_mesh(const Sculpt &sd,
2542 Object &object,
2544 const Span<int> corner_verts,
2545 const GroupedSpan<int> vert_to_face,
2546 const Span<bool> hide_poly,
2547 const Span<int> vert_propagation_steps,
2548 const Span<float> vert_factors,
2549 const bke::pbvh::MeshNode &node,
2550 LocalDataMesh &tls,
2551 const float3 symmetry_pivot,
2552 const float strength,
2553 const eBrushDeformTarget deform_target,
2554 const PositionDeformData &position_data)
2555{
2556 SculptSession &ss = *object.sculpt;
2557 const StrokeCache &cache = *ss.cache;
2558
2559 const Span<int> verts = node.verts();
2560 const OrigPositionData orig_data = orig_position_data_get_mesh(object, node);
2561
2563
2564 const MutableSpan<float> factors = gather_data_mesh(vert_factors, verts, tls.factors);
2565
2566 const Span<int> propagation_steps = gather_data_mesh(
2567 vert_propagation_steps, verts, tls.propagation_steps);
2568
2569 filter_uninitialized_verts(propagation_steps, factors);
2570 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2571
2572 scale_factors(factors, strength);
2573
2574 const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
2575 corner_verts,
2576 vert_to_face,
2577 hide_poly,
2578 verts,
2579 tls.neighbor_offsets,
2580 tls.neighbor_data);
2581 tls.average_positions.resize(verts.size());
2582
2583 const Span<float3> positions = gather_data_mesh(position_data.eval, verts, tls.positions);
2584 const MutableSpan<float3> average_positions = tls.average_positions;
2585 calc_average_position(position_data.eval,
2586 vert_propagation_steps,
2587 neighbors,
2588 propagation_steps,
2589 factors,
2590 average_positions);
2591
2592 tls.new_positions.resize(verts.size());
2593 const MutableSpan<float3> new_positions = tls.new_positions;
2594 calc_smooth_position(positions, average_positions, factors, new_positions);
2595
2596 switch (eBrushDeformTarget(deform_target)) {
2598 tls.translations.resize(verts.size());
2599 const MutableSpan<float3> translations = tls.translations;
2600 translations_from_new_positions(new_positions, verts, position_data.eval, translations);
2601 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
2602 position_data.deform(translations, verts);
2603 break;
2604 }
2607 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2608 break;
2609 }
2610}
2611
2612static void calc_smooth_grids(const Sculpt &sd,
2613 Object &object,
2614 SubdivCCG &subdiv_ccg,
2615 const Span<int> vert_propagation_steps,
2616 const Span<float> vert_factors,
2617 const bke::pbvh::GridsNode &node,
2618 LocalDataGrids &tls,
2619 const float3 symmetry_pivot,
2620 const float strength,
2621 const eBrushDeformTarget deform_target)
2622{
2623 SculptSession &ss = *object.sculpt;
2624 const StrokeCache &cache = *ss.cache;
2625 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2626
2627 const Span<int> grids = node.grids();
2628 const int grid_verts_num = grids.size() * key.grid_area;
2629 const OrigPositionData orig_data = orig_position_data_get_grids(object, node);
2630
2632
2633 const MutableSpan<float> factors = gather_data_grids(
2634 subdiv_ccg, vert_factors, grids, tls.factors);
2635
2636 const Span<int> propagation_steps = gather_data_grids(
2637 subdiv_ccg, vert_propagation_steps, grids, tls.propagation_steps);
2638
2639 filter_uninitialized_verts(propagation_steps, factors);
2640 filter_verts_outside_symmetry_area(orig_data.positions, symmetry_pivot, symm, factors);
2641
2642 scale_factors(factors, strength);
2643
2644 const GroupedSpan<int> neighbors = calc_vert_neighbors(
2645 subdiv_ccg, grids, tls.neighbor_offsets, tls.neighbor_data);
2646
2647 tls.average_positions.resize(grid_verts_num);
2648 const MutableSpan<float3> average_positions = tls.average_positions;
2650 vert_propagation_steps,
2651 neighbors,
2652 propagation_steps,
2653 factors,
2654 average_positions);
2655
2656 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
2657
2658 tls.new_positions.resize(grid_verts_num);
2659 const MutableSpan<float3> new_positions = tls.new_positions;
2660 calc_smooth_position(positions, average_positions, factors, new_positions);
2661
2662 switch (eBrushDeformTarget(deform_target)) {
2664 tls.translations.resize(grid_verts_num);
2665 const MutableSpan<float3> translations = tls.translations;
2666 translations_from_new_positions(new_positions, positions, translations);
2667
2668 clip_and_lock_translations(sd, ss, orig_data.positions, translations);
2669 apply_translations(translations, grids, subdiv_ccg);
2670 break;
2671 }
2673 scatter_data_grids(subdiv_ccg,
2674 new_positions.as_span(),
2675 grids,
2676 cache.cloth_sim->deformation_pos.as_mutable_span());
2677 break;
2678 }
2679}
2680
2681static void calc_smooth_bmesh(const Sculpt &sd,
2682 Object &object,
2683 const Span<int> vert_propagation_steps,
2684 const Span<float> vert_factors,
2686 LocalDataBMesh &tls,
2687 const float3 symmetry_pivot,
2688 const float strength,
2689 const eBrushDeformTarget deform_target)
2690
2691{
2692 SculptSession &ss = *object.sculpt;
2693 const StrokeCache &cache = *ss.cache;
2694
2696 Array<float3> orig_positions(verts.size());
2697 Array<float3> orig_normals(verts.size());
2698 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
2699
2701
2702 const MutableSpan<float> factors = gather_data_bmesh(vert_factors, verts, tls.factors);
2703
2704 const Span<int> propagation_steps = gather_data_bmesh(
2705 vert_propagation_steps, verts, tls.propagation_steps);
2706
2707 filter_uninitialized_verts(propagation_steps, factors);
2708 filter_verts_outside_symmetry_area(orig_positions, symmetry_pivot, symm, factors);
2709
2710 scale_factors(factors, strength);
2711
2714
2715 tls.average_positions.resize(verts.size());
2716 const MutableSpan<float3> average_positions = tls.average_positions;
2718 vert_propagation_steps, neighbors, propagation_steps, factors, average_positions);
2719 const Span<float3> positions = gather_bmesh_positions(verts, tls.positions);
2720
2721 tls.new_positions.resize(verts.size());
2722 const MutableSpan<float3> new_positions = tls.new_positions;
2723 calc_smooth_position(positions, average_positions, factors, new_positions);
2724
2725 switch (eBrushDeformTarget(deform_target)) {
2727 tls.translations.resize(verts.size());
2728 const MutableSpan<float3> translations = tls.translations;
2729 translations_from_new_positions(new_positions, positions, translations);
2730
2731 clip_and_lock_translations(sd, ss, orig_positions, translations);
2732 apply_translations(translations, verts);
2733 break;
2734 }
2737 new_positions.as_span(), verts, cache.cloth_sim->deformation_pos.as_mutable_span());
2738 break;
2739 }
2740}
2741
2742static void do_smooth_brush(const Depsgraph &depsgraph,
2743 const Sculpt &sd,
2744 Object &object,
2745 const IndexMask &node_mask,
2746 const SculptBoundary &boundary,
2747 const float strength,
2748 const eBrushDeformTarget deform_target)
2749{
2750 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
2751 switch (pbvh.type()) {
2752 case bke::pbvh::Type::Mesh: {
2753 Mesh &mesh = *static_cast<Mesh *>(object.data);
2754 const PositionDeformData position_data(depsgraph, object);
2755 const OffsetIndices<int> faces = mesh.faces();
2756 const Span<int> corner_verts = mesh.corner_verts();
2757 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
2758 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
2759 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
2760
2763 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2764 LocalDataMesh &tls = all_tls.local();
2766 object,
2767 faces,
2768 corner_verts,
2769 vert_to_face_map,
2770 hide_poly,
2771 boundary.edit_info.propagation_steps_num,
2772 boundary.edit_info.strength_factor,
2773 nodes[i],
2774 tls,
2775 boundary.initial_vert_position,
2776 strength,
2777 deform_target,
2778 position_data);
2780 });
2781 break;
2782 }
2784 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
2785 MutableSpan<float3> positions = subdiv_ccg.positions;
2788 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2789 LocalDataGrids &tls = all_tls.local();
2791 object,
2792 subdiv_ccg,
2793 boundary.edit_info.propagation_steps_num,
2794 boundary.edit_info.strength_factor,
2795 nodes[i],
2796 tls,
2797 boundary.initial_vert_position,
2798 strength,
2799 deform_target);
2800 bke::pbvh::update_node_bounds_grids(subdiv_ccg.grid_area, positions, nodes[i]);
2801 });
2802 break;
2803 }
2807 node_mask.foreach_index(GrainSize(1), [&](const int i) {
2808 LocalDataBMesh &tls = all_tls.local();
2810 object,
2811 boundary.edit_info.propagation_steps_num,
2812 boundary.edit_info.strength_factor,
2813 nodes[i],
2814 tls,
2815 boundary.initial_vert_position,
2816 strength,
2817 deform_target);
2819 });
2820 break;
2821 }
2822 }
2823 pbvh.tag_positions_changed(node_mask);
2825}
2826
2827/* -------------------------------------------------------------------- */
2830
2832 const SculptBoundary &boundary)
2833{
2834 float4 plane;
2835 const float3 normal = math::normalize(ss.cache->initial_location_symm - boundary.pivot_position);
2837
2839 return dist_signed_to_plane_v3(pos, plane);
2840}
2841
2842static std::pair<float, float> calc_boundary_falloff(const SculptBoundary &boundary,
2843 const Brush &brush,
2844 const float radius,
2845 const int index)
2846{
2847 const float boundary_distance = boundary.distance.lookup_default(index, 0.0f);
2848 float falloff_distance = 0.0f;
2849 float direction = 1.0f;
2850
2851 switch (brush.boundary_falloff_type) {
2853 falloff_distance = boundary_distance;
2854 break;
2856 const int div = boundary_distance / radius;
2857 const float mod = fmodf(boundary_distance, radius);
2858 falloff_distance = div % 2 == 0 ? mod : radius - mod;
2859 break;
2860 }
2862 const int div = boundary_distance / radius;
2863 const float mod = fmodf(boundary_distance, radius);
2864 falloff_distance = div % 2 == 0 ? mod : radius - mod;
2865 /* Inverts the falloff in the intervals 1 2 5 6 9 10 ... etc. */
2866 if (((div - 1) & 2) == 0) {
2867 direction = -1.0f;
2868 }
2869 break;
2870 }
2872 /* For constant falloff distances are not allocated, so this should never happen. */
2874 break;
2875 }
2876
2877 return {falloff_distance, direction};
2878}
2879
2885 const Brush &brush,
2886 const float radius,
2888{
2889 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2890 boundary.edit_info.propagation_steps_num.size());
2891 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2892 boundary.edit_info.strength_factor.size());
2893
2894 const int num_elements = boundary.edit_info.strength_factor.size();
2896
2897 for (const int i : IndexRange(num_elements)) {
2898 if (boundary.edit_info.propagation_steps_num[i] != BOUNDARY_STEPS_NONE) {
2899 const float mask_factor = mask.is_empty() ? 1.0f : 1.0f - mask[i];
2900 boundary.edit_info.strength_factor[i] = mask_factor *
2902 &brush,
2903 boundary.edit_info.propagation_steps_num[i],
2904 boundary.max_propagation_steps);
2905 }
2906
2907 if (boundary.edit_info.original_vertex_i[i] == boundary.initial_vert_i) {
2908 /* All vertices that are propagated from the original vertex won't be affected by the
2909 * boundary falloff, so there is no need to calculate anything else. */
2910 continue;
2911 }
2912
2913 const bool use_boundary_distances = brush.boundary_falloff_type !=
2915
2916 if (!use_boundary_distances) {
2917 /* There are falloff modes that do not require to modify the previously calculated falloff
2918 * based on boundary distances. */
2919 continue;
2920 }
2921
2922 auto [falloff_distance, direction] = calc_boundary_falloff(
2923 boundary, brush, radius, boundary.edit_info.original_vertex_i[i]);
2924 boundary.edit_info.strength_factor[i] *= direction * BKE_brush_curve_strength(
2925 &brush, falloff_distance, radius);
2926 }
2927}
2928
2929static void init_falloff_grids(const SubdivCCG &subdiv_ccg,
2930 const Brush &brush,
2931 const float radius,
2933{
2934 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2935 boundary.edit_info.propagation_steps_num.size());
2936 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2937 boundary.edit_info.strength_factor.size());
2938
2939 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
2940
2942
2943 for (const int grid : IndexRange(subdiv_ccg.grids_num)) {
2944 for (const int index : bke::ccg::grid_range(key, grid)) {
2945 if (boundary.edit_info.propagation_steps_num[index] != BOUNDARY_STEPS_NONE) {
2946 const float mask_factor = subdiv_ccg.masks.is_empty() ? 1.0f :
2947 1.0f - subdiv_ccg.masks[index];
2948 boundary.edit_info.strength_factor[index] =
2949 mask_factor * BKE_brush_curve_strength(&brush,
2950 boundary.edit_info.propagation_steps_num[index],
2951 boundary.max_propagation_steps);
2952 }
2953
2954 if (boundary.edit_info.original_vertex_i[index] == boundary.initial_vert_i) {
2955 /* All vertices that are propagated from the original vertex won't be affected by the
2956 * boundary falloff, so there is no need to calculate anything else. */
2957 continue;
2958 }
2959
2960 const bool use_boundary_distances = brush.boundary_falloff_type !=
2962
2963 if (!use_boundary_distances) {
2964 /* There are falloff modes that do not require to modify the previously calculated falloff
2965 * based on boundary distances. */
2966 continue;
2967 }
2968
2969 auto [falloff_distance, direction] = calc_boundary_falloff(
2970 boundary, brush, radius, boundary.edit_info.original_vertex_i[index]);
2971 boundary.edit_info.strength_factor[index] *= direction *
2973 &brush, falloff_distance, radius);
2974 }
2975 }
2976}
2977
2979 const Brush &brush,
2980 const float radius,
2982{
2983 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2984 boundary.edit_info.propagation_steps_num.size());
2985 BLI_assert(boundary.edit_info.original_vertex_i.size() ==
2986 boundary.edit_info.strength_factor.size());
2987
2988 const int num_elements = boundary.edit_info.strength_factor.size();
2989
2991
2992 for (const int i : IndexRange(num_elements)) {
2993 if (boundary.edit_info.propagation_steps_num[i] != BOUNDARY_STEPS_NONE) {
2994 BMVert *vert = BM_vert_at_index(bm, i);
2995 const int mask_offset = CustomData_get_offset_named(
2996 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
2997 const float mask_factor = mask_offset == -1 ? 1.0f :
2998 1.0f - BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
2999
3000 boundary.edit_info.strength_factor[i] = mask_factor *
3002 &brush,
3003 boundary.edit_info.propagation_steps_num[i],
3004 boundary.max_propagation_steps);
3005 }
3006
3007 if (boundary.edit_info.original_vertex_i[i] == boundary.initial_vert_i) {
3008 /* All vertices that are propagated from the original vertex won't be affected by the
3009 * boundary falloff, so there is no need to calculate anything else. */
3010 continue;
3011 }
3012
3013 const bool use_boundary_distances = brush.boundary_falloff_type !=
3015
3016 if (!use_boundary_distances) {
3017 /* There are falloff modes that do not require to modify the previously calculated falloff
3018 * based on boundary distances. */
3019 continue;
3020 }
3021
3022 auto [falloff_distance, direction] = calc_boundary_falloff(
3023 boundary, brush, radius, boundary.edit_info.original_vertex_i[i]);
3024 boundary.edit_info.strength_factor[i] *= direction * BKE_brush_curve_strength(
3025 &brush, falloff_distance, radius);
3026 }
3027}
3028
3029static void init_boundary_mesh(const Depsgraph &depsgraph,
3030 Object &object,
3031 const Brush &brush,
3032 const ePaintSymmetryFlags symm_area)
3033{
3034 const SculptSession &ss = *object.sculpt;
3035 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3036
3037 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
3038 const bke::AttributeAccessor attributes = mesh.attributes();
3039 VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
3040 VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
3041
3042 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
3043 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
3044
3045 ActiveVert initial_vert_ref = ss.active_vert();
3046 if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
3047 return;
3048 }
3049
3050 std::optional<int> initial_vert;
3051 if (ss.cache->mirror_symmetry_pass == 0) {
3052 initial_vert = std::get<int>(initial_vert_ref);
3053 }
3054 else {
3055 float3 location = symmetry_flip(positions_eval[std::get<int>(initial_vert_ref)], symm_area);
3056 initial_vert = nearest_vert_calc_mesh(
3057 pbvh, positions_eval, hide_vert, location, ss.cache->radius_squared, false);
3058 }
3059
3060 if (!initial_vert) {
3061 return;
3062 }
3063
3064 ss.cache->boundaries[symm_area] = boundary::data_init_mesh(
3065 depsgraph, object, &brush, *initial_vert, ss.cache->initial_radius);
3066
3067 if (ss.cache->boundaries[symm_area]) {
3068 switch (brush.boundary_deform_type) {
3070 bend_data_init_mesh(positions_eval, vert_normals, *ss.cache->boundaries[symm_area]);
3071 break;
3073 slide_data_init_mesh(positions_eval, *ss.cache->boundaries[symm_area]);
3074 break;
3076 twist_data_init_mesh(positions_eval, *ss.cache->boundaries[symm_area]);
3077 break;
3081 /* Do nothing. These deform modes don't need any extra data to be precomputed. */
3082 break;
3083 }
3084
3085 init_falloff_mesh(mask, brush, ss.cache->initial_radius, *ss.cache->boundaries[symm_area]);
3086 }
3087}
3088
3089static void init_boundary_grids(Object &object,
3090 const Brush &brush,
3091 const ePaintSymmetryFlags symm_area)
3092{
3093 const SculptSession &ss = *object.sculpt;
3094 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3095
3096 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
3097 const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
3098 const Span<float3> positions = subdiv_ccg.positions;
3099
3100 ActiveVert initial_vert_ref = ss.active_vert();
3101 if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
3102 return;
3103 }
3104
3105 std::optional<SubdivCCGCoord> initial_vert;
3106 if (ss.cache->mirror_symmetry_pass == 0) {
3107 initial_vert = SubdivCCGCoord::from_index(key, std::get<int>(initial_vert_ref));
3108 }
3109 else {
3110 const int active_vert = std::get<int>(initial_vert_ref);
3111 float3 location = symmetry_flip(positions[active_vert], symm_area);
3112 initial_vert = nearest_vert_calc_grids(
3113 pbvh, subdiv_ccg, location, ss.cache->radius_squared, false);
3114 }
3115
3116 if (!initial_vert) {
3117 return;
3118 }
3119
3121 object, &brush, *initial_vert, ss.cache->initial_radius);
3122
3123 if (ss.cache->boundaries[symm_area]) {
3124 switch (brush.boundary_deform_type) {
3126 bend_data_init_grids(subdiv_ccg, *ss.cache->boundaries[symm_area]);
3127 break;
3129 slide_data_init_grids(subdiv_ccg, *ss.cache->boundaries[symm_area]);
3130 break;
3132 twist_data_init_grids(subdiv_ccg, *ss.cache->boundaries[symm_area]);
3133 break;
3137 /* Do nothing. These deform modes don't need any extra data to be precomputed. */
3138 break;
3139 }
3140
3142 subdiv_ccg, brush, ss.cache->initial_radius, *ss.cache->boundaries[symm_area]);
3143 }
3144}
3145
3146static void init_boundary_bmesh(Object &object,
3147 const Brush &brush,
3148 const ePaintSymmetryFlags symm_area)
3149{
3150 const SculptSession &ss = *object.sculpt;
3151 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3152
3153 BMesh *bm = ss.bm;
3154
3155 ActiveVert initial_vert_ref = ss.active_vert();
3156 if (std::holds_alternative<std::monostate>(initial_vert_ref)) {
3157 return;
3158 }
3159
3160 std::optional<BMVert *> initial_vert;
3161 if (ss.cache->mirror_symmetry_pass == 0) {
3162 initial_vert = std::get<BMVert *>(initial_vert_ref);
3163 }
3164 else {
3165 BMVert *active_vert = std::get<BMVert *>(initial_vert_ref);
3166 float3 location = symmetry_flip(active_vert->co, symm_area);
3167 initial_vert = nearest_vert_calc_bmesh(pbvh, location, ss.cache->radius_squared, false);
3168 }
3169
3170 if (!initial_vert) {
3171 return;
3172 }
3173
3175 object, &brush, *initial_vert, ss.cache->initial_radius);
3176
3177 if (ss.cache->boundaries[symm_area]) {
3178 switch (brush.boundary_deform_type) {
3180 bend_data_init_bmesh(bm, *ss.cache->boundaries[symm_area]);
3181 break;
3183 slide_data_init_bmesh(bm, *ss.cache->boundaries[symm_area]);
3184 break;
3186 twist_data_init_bmesh(bm, *ss.cache->boundaries[symm_area]);
3187 break;
3191 /* Do nothing. These deform modes don't need any extra data to be precomputed. */
3192 break;
3193 }
3194
3195 init_falloff_bmesh(bm, brush, ss.cache->initial_radius, *ss.cache->boundaries[symm_area]);
3196 }
3197}
3198
3199static float get_mesh_strength(const SculptSession &ss, const Brush &brush)
3200{
3201 const int symm_area = ss.cache->mirror_symmetry_pass;
3202 SculptBoundary &boundary = *ss.cache->boundaries[symm_area];
3203
3204 const float strength = ss.cache->bstrength;
3205
3206 switch (brush.boundary_deform_type) {
3208 const float disp = strength * displacement_from_grab_delta_get(ss, boundary);
3209 float angle_factor = disp / ss.cache->radius;
3210 /* Angle Snapping when inverting the brush. */
3211 if (ss.cache->invert) {
3212 angle_factor = floorf(angle_factor * 10) / 10.0f;
3213 }
3214 return angle_factor * M_PI;
3215 }
3217 return strength * displacement_from_grab_delta_get(ss, boundary);
3218 }
3220 return strength * displacement_from_grab_delta_get(ss, boundary);
3221 }
3223 return strength;
3225 const float disp = strength * displacement_from_grab_delta_get(ss, boundary);
3226 float angle_factor = disp / ss.cache->radius;
3227 /* Angle Snapping when inverting the brush. */
3228 if (ss.cache->invert) {
3229 angle_factor = floorf(angle_factor * 10) / 10.0f;
3230 }
3231 return angle_factor * M_PI;
3232 }
3234 return strength;
3235 }
3236
3238 return 0.0f;
3239}
3240
3241void do_boundary_brush(const Depsgraph &depsgraph,
3242 const Sculpt &sd,
3243 Object &ob,
3244 const IndexMask &node_mask)
3245{
3246 SculptSession &ss = *ob.sculpt;
3248 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3249
3250 const ePaintSymmetryFlags symm_area = ss.cache->mirror_symmetry_pass;
3252 switch (pbvh.type()) {
3254 init_boundary_mesh(depsgraph, ob, brush, symm_area);
3255 break;
3257 init_boundary_grids(ob, brush, symm_area);
3258 break;
3260 init_boundary_bmesh(ob, brush, symm_area);
3261 break;
3262 }
3263 }
3264
3265 /* No active boundary under the cursor. */
3266 if (!ss.cache->boundaries[symm_area]) {
3267 return;
3268 }
3269
3270 const float strength = get_mesh_strength(ss, brush);
3271
3272 switch (brush.boundary_deform_type) {
3275 sd,
3276 ob,
3277 node_mask,
3278 *ss.cache->boundaries[symm_area],
3279 strength,
3281 break;
3284 sd,
3285 ob,
3286 node_mask,
3287 *ss.cache->boundaries[symm_area],
3288 strength,
3290 break;
3293 sd,
3294 ob,
3295 node_mask,
3296 *ss.cache->boundaries[symm_area],
3297 strength,
3299 break;
3302 sd,
3303 ob,
3304 node_mask,
3305 *ss.cache->boundaries[symm_area],
3306 strength,
3308 break;
3311 sd,
3312 ob,
3313 node_mask,
3314 *ss.cache->boundaries[symm_area],
3315 strength,
3317 break;
3320 sd,
3321 ob,
3322 node_mask,
3323 *ss.cache->boundaries[symm_area],
3324 strength,
3326 break;
3327 }
3328}
3329
3331
3332/* -------------------------------------------------------------------- */
3335
3336std::unique_ptr<SculptBoundary> data_init(const Depsgraph &depsgraph,
3337 Object &object,
3338 const Brush *brush,
3339 const int initial_vert,
3340 const float radius)
3341{
3342 /* TODO: Temporary bridge method to help in refactoring, this method should be deprecated
3343 * entirely. */
3344 const SculptSession &ss = *object.sculpt;
3345 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3346
3347 switch (pbvh.type()) {
3348 case (bke::pbvh::Type::Mesh): {
3349 return data_init_mesh(depsgraph, object, brush, initial_vert, radius);
3350 }
3351 case (bke::pbvh::Type::Grids): {
3353 const SubdivCCGCoord vert = SubdivCCGCoord::from_index(key, initial_vert);
3354 return data_init_grids(object, brush, vert, radius);
3355 }
3356 case (bke::pbvh::Type::BMesh): {
3357 BMVert *vert = BM_vert_at_index(ss.bm, initial_vert);
3358 return data_init_bmesh(object, brush, vert, radius);
3359 }
3360 }
3361
3363 return nullptr;
3364}
3365
3366std::unique_ptr<SculptBoundary> data_init_mesh(const Depsgraph &depsgraph,
3367 Object &object,
3368 const Brush *brush,
3369 const int initial_vert,
3370 const float radius)
3371{
3372 SculptSession &ss = *object.sculpt;
3373
3375
3376 Mesh &mesh = *static_cast<Mesh *>(object.data);
3377 const OffsetIndices faces = mesh.faces();
3378 const Span<int> corner_verts = mesh.corner_verts();
3379 const bke::AttributeAccessor attributes = mesh.attributes();
3380 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
3381 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
3382 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
3383
3384 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
3385
3386 const std::optional<int> boundary_initial_vert = get_closest_boundary_vert_mesh(
3387 object,
3388 vert_to_face_map,
3389 positions_eval,
3390 hide_vert,
3391 hide_poly,
3393 initial_vert,
3394 radius);
3395
3396 if (!boundary_initial_vert) {
3397 return nullptr;
3398 }
3399
3400 /* Starting from a vertex that is the limit of a boundary is ambiguous, so return nullptr instead
3401 * of forcing a random active boundary from a corner. */
3402 /* TODO: Investigate whether initial_vert should actually be boundary_initial_vert. If
3403 * initial_vert is correct, the above comment and the doc-string for the relevant function should
3404 * be fixed. */
3406 corner_verts,
3407 vert_to_face_map,
3408 hide_vert,
3409 hide_poly,
3411 initial_vert))
3412 {
3413 return nullptr;
3414 }
3415
3416 std::unique_ptr<SculptBoundary> boundary = std::make_unique<SculptBoundary>();
3417 *boundary = {};
3418
3419 const int boundary_initial_vert_index = *boundary_initial_vert;
3420 boundary->initial_vert_i = boundary_initial_vert_index;
3421 boundary->initial_vert_position = positions_eval[boundary_initial_vert_index];
3422
3423 indices_init_mesh(object,
3424 faces,
3425 corner_verts,
3426 vert_to_face_map,
3427 hide_vert,
3428 hide_poly,
3430 positions_eval,
3431 *boundary_initial_vert,
3432 *boundary);
3433
3434 const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
3436 corner_verts,
3437 vert_to_face_map,
3438 positions_eval,
3439 hide_vert,
3440 hide_poly,
3441 boundary_initial_vert_index,
3442 boundary_radius,
3443 *boundary);
3444
3445 return boundary;
3446}
3447
3448std::unique_ptr<SculptBoundary> data_init_grids(Object &object,
3449 const Brush *brush,
3450 const SubdivCCGCoord initial_vert,
3451 const float radius)
3452{
3453 SculptSession &ss = *object.sculpt;
3454
3456
3457 Mesh &mesh = *static_cast<Mesh *>(object.data);
3458 const OffsetIndices faces = mesh.faces();
3459 const Span<int> corner_verts = mesh.corner_verts();
3460 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
3461 const Span<float3> positions = subdiv_ccg.positions;
3462 const CCGKey &key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
3463
3464 const std::optional<SubdivCCGCoord> boundary_initial_vert = get_closest_boundary_vert_grids(
3465 object, faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, initial_vert, radius);
3466
3467 if (!boundary_initial_vert) {
3468 return nullptr;
3469 }
3470
3471 /* Starting from a vertex that is the limit of a boundary is ambiguous, so return nullptr instead
3472 * of forcing a random active boundary from a corner. */
3474 faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, initial_vert))
3475 {
3476 return nullptr;
3477 }
3478
3479 std::unique_ptr<SculptBoundary> boundary = std::make_unique<SculptBoundary>();
3480 *boundary = {};
3481
3482 SubdivCCGCoord boundary_vert = *boundary_initial_vert;
3483 const int boundary_initial_vert_index = boundary_vert.to_index(key);
3484 boundary->initial_vert_i = boundary_initial_vert_index;
3485 boundary->initial_vert_position = positions[boundary_initial_vert_index];
3486
3488 object, faces, corner_verts, subdiv_ccg, ss.vertex_info.boundary, boundary_vert, *boundary);
3489
3490 const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
3491 edit_data_init_grids(subdiv_ccg, boundary_initial_vert_index, boundary_radius, *boundary);
3492
3493 return boundary;
3494}
3495
3496std::unique_ptr<SculptBoundary> data_init_bmesh(Object &object,
3497 const Brush *brush,
3498 BMVert *initial_vert,
3499 const float radius)
3500{
3501 SculptSession &ss = *object.sculpt;
3502
3505
3506 const std::optional<BMVert *> boundary_initial_vert = get_closest_boundary_vert_bmesh(
3507 object, ss.bm, *initial_vert, radius);
3508
3509 if (!boundary_initial_vert) {
3510 return nullptr;
3511 }
3512
3513 /* Starting from a vertex that is the limit of a boundary is ambiguous, so return nullptr instead
3514 * of forcing a random active boundary from a corner. */
3515 if (!is_vert_in_editable_boundary_bmesh(*initial_vert)) {
3516 return nullptr;
3517 }
3518
3519 std::unique_ptr<SculptBoundary> boundary = std::make_unique<SculptBoundary>();
3520 *boundary = {};
3521
3522 const int boundary_initial_vert_index = BM_elem_index_get(*boundary_initial_vert);
3523 boundary->initial_vert_i = boundary_initial_vert_index;
3524 boundary->initial_vert_position = (*boundary_initial_vert)->co;
3525
3526 indices_init_bmesh(object, ss.bm, **boundary_initial_vert, *boundary);
3527
3528 const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
3529 edit_data_init_bmesh(ss.bm, boundary_initial_vert_index, boundary_radius, *boundary);
3530
3531 return boundary;
3532}
3533
3535
3536/* -------------------------------------------------------------------- */
3541
3542std::unique_ptr<SculptBoundaryPreview> preview_data_init(const Depsgraph &depsgraph,
3543 Object &object,
3544 const Brush *brush,
3545 const float radius)
3546{
3547 const SculptSession &ss = *object.sculpt;
3548 ActiveVert initial_vert = ss.active_vert();
3549
3550 if (std::holds_alternative<std::monostate>(initial_vert)) {
3551 return nullptr;
3552 }
3553
3554 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
3555
3556 std::unique_ptr<SculptBoundary> boundary = nullptr;
3557 switch (pbvh.type()) {
3559 boundary = data_init_mesh(depsgraph, object, brush, std::get<int>(initial_vert), radius);
3560 break;
3562 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
3563 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
3565 object, brush, SubdivCCGCoord::from_index(key, std::get<int>(initial_vert)), radius);
3566 break;
3567 }
3569 boundary = data_init_bmesh(object, brush, std::get<BMVert *>(initial_vert), radius);
3570 break;
3571 }
3572
3573 if (boundary == nullptr) {
3574 return nullptr;
3575 }
3576 std::unique_ptr<SculptBoundaryPreview> preview = std::make_unique<SculptBoundaryPreview>();
3577 preview->edges = boundary->edges;
3578 preview->pivot_position = boundary->pivot_position;
3579 preview->initial_vert_position = boundary->initial_vert_position;
3580
3581 return preview;
3582}
3583
3584void edges_preview_draw(const uint gpuattr,
3585 SculptSession &ss,
3586 const float outline_col[3],
3587 const float outline_alpha)
3588{
3589 if (!ss.boundary_preview) {
3590 return;
3591 }
3592 immUniformColor3fvAlpha(outline_col, outline_alpha);
3593 GPU_line_width(2.0f);
3594 immBegin(GPU_PRIM_LINES, ss.boundary_preview->edges.size() * 2);
3595 for (const int i : ss.boundary_preview->edges.index_range()) {
3596 immVertex3fv(gpuattr, ss.boundary_preview->edges[i].first);
3597 immVertex3fv(gpuattr, ss.boundary_preview->edges[i].second);
3598 }
3599 immEnd();
3600}
3601
3603{
3604 if (!ss.boundary_preview) {
3605 return;
3606 }
3607 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
3608 GPU_line_width(2.0f);
3610 immVertex3fv(gpuattr, ss.boundary_preview->pivot_position);
3611 immVertex3fv(gpuattr, ss.boundary_preview->initial_vert_position);
3612 immEnd();
3613}
3614
3616
3617} // 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:7443
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:6057
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:6445
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6351
void gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6389
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:7596
Vector< BMVert *, 64 > BMeshNeighborVerts
void gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6405
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:7845
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7493
void translations_from_new_positions(Span< float3 > new_positions, Span< int > verts, Span< float3 > old_positions, MutableSpan< float3 > translations)
Definition sculpt.cc:7523
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7316
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6419
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:7249
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:6379
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:6429
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