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