Blender V5.0
sculpt_smooth.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_smooth.hh"
9
11#include "BLI_math_base.hh"
12#include "BLI_math_geom.h"
13#include "BLI_math_vector.h"
14#include "BLI_math_vector.hh"
15
16#include "BKE_mesh.hh"
17#include "BKE_paint.hh"
18#include "BKE_paint_bvh.hh"
19#include "BKE_subdiv_ccg.hh"
20
21#include "mesh_brush_common.hh"
22#include "sculpt_automask.hh"
23#include "sculpt_color.hh"
24#include "sculpt_face_set.hh"
25#include "sculpt_hide.hh"
26#include "sculpt_intern.hh"
27
28#include "bmesh.hh"
29
30#include <cstdlib>
31
33
34template<typename T> T calc_average(const Span<T> values, const Span<int> indices)
35{
36 const float factor = math::safe_rcp(float(indices.size()));
37 T result{};
38 for (const int i : indices) {
39 result += values[i] * factor;
40 }
41 return result;
42}
43
44template<typename T>
46 const Span<int> verts,
47 const GroupedSpan<int> vert_neighbors,
48 const MutableSpan<T> dst)
49{
50 BLI_assert(verts.size() == dst.size());
51 BLI_assert(vert_neighbors.size() == dst.size());
52
53 for (const int i : vert_neighbors.index_range()) {
54 const Span<int> neighbors = vert_neighbors[i];
55 if (neighbors.is_empty()) {
56 dst[i] = src[verts[i]];
57 }
58 else {
59 dst[i] = calc_average(src, neighbors);
60 }
61 }
62}
63
72
73template<typename T>
75 const GroupedSpan<int> vert_neighbors,
76 const MutableSpan<T> dst)
77{
78 BLI_assert(vert_neighbors.size() == dst.size());
79
80 for (const int i : vert_neighbors.index_range()) {
81 dst[i] = calc_average(src, vert_neighbors[i]);
82 }
83}
84
92
94 const Span<float3> positions,
95 const Span<SubdivCCGCoord> coords)
96{
97 const float factor = math::rcp(float(coords.size()));
98 float3 result(0);
99 for (const SubdivCCGCoord coord : coords) {
100 result += positions[coord.to_index(key)] * factor;
101 }
102 return result;
103}
104
105template<bool use_factors>
107 const Span<int> corner_verts,
108 const BitSpan boundary_verts,
109 const SubdivCCG &subdiv_ccg,
110 const Span<int> grids,
111 const Span<float> factors,
112 const MutableSpan<float3> new_positions)
113{
114 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
115 const Span<float3> positions = subdiv_ccg.positions;
116
117 BLI_assert(grids.size() * key.grid_area == new_positions.size());
118 if constexpr (use_factors) {
119 BLI_assert(new_positions.size() == factors.size());
120 }
121
122 for (const int i : grids.index_range()) {
123 const int node_verts_start = i * key.grid_area;
124 const int grid = grids[i];
125 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
126
127 /* TODO: This loop could be optimized in the future by skipping unnecessary logic for
128 * non-boundary grid vertices. */
129 for (const int y : IndexRange(key.grid_size)) {
130 for (const int x : IndexRange(key.grid_size)) {
131 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
132 const int node_vert_index = node_verts_start + offset;
133 const int vert = grid_range[offset];
134
135 if constexpr (use_factors) {
136 if (factors[node_vert_index] == 0.0f) {
137 new_positions[node_vert_index] = positions[vert];
138 continue;
139 }
140 }
141
142 SubdivCCGCoord coord{};
143 coord.grid_index = grid;
144 coord.x = x;
145 coord.y = y;
146
147 SubdivCCGNeighbors neighbors;
148 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
149
151 faces, corner_verts, boundary_verts, subdiv_ccg, coord))
152 {
153 if (neighbors.coords.size() == 2) {
154 /* Do not include neighbors of corner vertices. */
155 neighbors.coords.clear();
156 }
157 else {
158 /* Only include other boundary vertices as neighbors of boundary vertices. */
159 neighbors.coords.remove_if([&](const SubdivCCGCoord coord) {
161 faces, corner_verts, boundary_verts, subdiv_ccg, coord);
162 });
163 }
164 }
165
166 if (neighbors.coords.is_empty()) {
167 new_positions[node_vert_index] = positions[vert];
168 }
169 else {
170 new_positions[node_vert_index] = average_positions(key, positions, neighbors.coords);
171 }
172 }
173 }
174 }
175}
176
178 const Span<int> corner_verts,
179 const BitSpan boundary_verts,
180 const SubdivCCG &subdiv_ccg,
181 const Span<int> grids,
182 const MutableSpan<float3> new_positions)
183{
185 faces, corner_verts, boundary_verts, subdiv_ccg, grids, {}, new_positions);
186}
187
189 const Span<int> corner_verts,
190 const BitSpan boundary_verts,
191 const SubdivCCG &subdiv_ccg,
192 const Span<int> grids,
193 const Span<float> factors,
194 const MutableSpan<float3> new_positions)
195{
197 faces, corner_verts, boundary_verts, subdiv_ccg, grids, factors, new_positions);
198}
199
200template<typename T>
201void average_data_grids(const SubdivCCG &subdiv_ccg,
202 const Span<T> src,
203 const Span<int> grids,
204 const MutableSpan<T> dst)
205{
206 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
207
208 BLI_assert(grids.size() * key.grid_area == dst.size());
209
210 for (const int i : grids.index_range()) {
211 const int grid = grids[i];
212 const int node_verts_start = i * key.grid_area;
213
214 /* TODO: This loop could be optimized in the future by skipping unnecessary logic for
215 * non-boundary grid vertices. */
216 for (const int y : IndexRange(key.grid_size)) {
217 for (const int x : IndexRange(key.grid_size)) {
218 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
219 const int node_vert_index = node_verts_start + offset;
220
221 SubdivCCGCoord coord{};
222 coord.grid_index = grid;
223 coord.x = x;
224 coord.y = y;
225
226 SubdivCCGNeighbors neighbors;
227 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
228
229 T sum{};
230 for (const SubdivCCGCoord neighbor : neighbors.coords) {
231 sum += src[neighbor.to_index(key)];
232 }
233 dst[node_vert_index] = math::safe_divide(sum, float(neighbors.coords.size()));
234 }
235 }
236 }
237}
238
239template<typename T>
241{
242 BMeshNeighborVerts neighbor_data;
243
244 int i = 0;
245 for (BMVert *vert : verts) {
246 T sum{};
247 const Span<BMVert *> neighbors = vert_neighbors_get_bmesh(*vert, neighbor_data);
248 for (const BMVert *neighbor : neighbors) {
249 sum += src[BM_elem_index_get(neighbor)];
250 }
251 dst[i] = math::safe_divide(sum, float(neighbors.size()));
252 i++;
253 }
254}
255
258 Span<int>,
262 Span<int>,
265 const Set<BMVert *, 0> &,
268 const Set<BMVert *, 0> &,
270
272{
273 const float factor = math::safe_rcp(float(verts.size()));
274 float3 result(0);
275 for (const BMVert *vert : verts) {
276 result += float3(vert->co) * factor;
277 }
278 return result;
279}
280
282 const MutableSpan<float3> new_positions)
283{
284 BLI_assert(verts.size() == new_positions.size());
285 BMeshNeighborVerts neighbor_data;
286
287 int i = 0;
288 for (BMVert *vert : verts) {
289 const Span<BMVert *> neighbors = vert_neighbors_get_bmesh(*vert, neighbor_data);
290 new_positions[i] = average_positions(neighbors);
291 i++;
292 }
293}
294
295template<bool use_factors>
297 const Span<float> factors,
298 const MutableSpan<float3> new_positions)
299{
300 BLI_assert(verts.size() == new_positions.size());
301 if constexpr (use_factors) {
302 BLI_assert(new_positions.size() == factors.size());
303 }
304 BMeshNeighborVerts neighbor_data;
305
306 int i = 0;
307 for (BMVert *vert : verts) {
308 if constexpr (use_factors) {
309 if (factors[i] == 0.0f) {
310 new_positions[i] = float3(vert->co);
311 i++;
312 continue;
313 }
314 }
315
316 const Span<BMVert *> neighbors = vert_neighbors_get_interior_bmesh(*vert, neighbor_data);
317 if (neighbors.is_empty()) {
318 new_positions[i] = float3(vert->co);
319 }
320 else {
321 new_positions[i] = average_positions(neighbors);
322 }
323 i++;
324 }
325}
327 const Span<float> factors,
328 const MutableSpan<float3> new_positions)
329{
331}
332
338
339void bmesh_four_neighbor_average(float avg[3], const float3 &direction, const BMVert *v)
340{
341 float avg_co[3] = {0.0f, 0.0f, 0.0f};
342 float tot_co = 0.0f;
343
344 BMIter eiter;
345 BMEdge *e;
346
347 BM_ITER_ELEM (e, &eiter, const_cast<BMVert *>(v), BM_EDGES_OF_VERT) {
348 if (BM_edge_is_boundary(e)) {
349 copy_v3_v3(avg, v->co);
350 return;
351 }
352 BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
353 float vec[3];
354 sub_v3_v3v3(vec, v_other->co, v->co);
355 madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
356 normalize_v3(vec);
357
358 /* fac is a measure of how orthogonal or parallel the edge is
359 * relative to the direction. */
360 float fac = dot_v3v3(vec, direction);
361 fac = fac * fac - 0.5f;
362 fac *= fac;
363 madd_v3_v3fl(avg_co, v_other->co, fac);
364 tot_co += fac;
365 }
366
367 /* In case vert has no Edge s. */
368 if (tot_co > 0.0f) {
369 mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
370
371 /* Preserve volume. */
372 float vec[3];
373 sub_v3_v3(avg, v->co);
374 mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
375 sub_v3_v3(avg, vec);
376 add_v3_v3(avg, v->co);
377 }
378 else {
379 zero_v3(avg);
380 }
381}
382
384 const Span<int> corner_verts,
385 const GroupedSpan<int> vert_to_face_map,
386 const GSpan color_attribute,
387 const bke::AttrDomain color_domain,
388 const GroupedSpan<int> vert_neighbors,
389 const MutableSpan<float4> smooth_colors)
390{
391 BLI_assert(vert_neighbors.size() == smooth_colors.size());
392
393 for (const int i : vert_neighbors.index_range()) {
394 float4 sum(0);
395 const Span<int> neighbors = vert_neighbors[i];
396 for (const int vert : neighbors) {
398 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, vert);
399 }
400 smooth_colors[i] = math::safe_divide(sum, float(neighbors.size()));
401 }
402}
403
404/* HC Smooth Algorithm. */
405/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
406
408 const Span<float3> orig_positions,
410 const float alpha,
411 MutableSpan<float3> laplacian_disp,
412 MutableSpan<float3> translations)
413{
414 BLI_assert(positions.size() == orig_positions.size());
415 BLI_assert(positions.size() == average_positions.size());
416 BLI_assert(positions.size() == laplacian_disp.size());
417 BLI_assert(positions.size() == translations.size());
418
419 for (const int i : average_positions.index_range()) {
420 const float3 weighted_o = orig_positions[i] * alpha;
421 const float3 weighted_q = positions[i] * (1.0f - alpha);
422 const float3 d = weighted_o + weighted_q;
423 laplacian_disp[i] = average_positions[i] - d;
424 translations[i] = average_positions[i] - positions[i];
425 }
426}
427
429 const Span<float3> average_laplacian_disp,
430 const float beta,
431 const MutableSpan<float3> translations)
432{
433 BLI_assert(laplacian_disp.size() == average_laplacian_disp.size());
434 BLI_assert(laplacian_disp.size() == translations.size());
435
436 for (const int i : laplacian_disp.index_range()) {
437 float3 b_current_vert = average_laplacian_disp[i] * (1.0f - beta);
438 b_current_vert += laplacian_disp[i] * beta;
439 translations[i] = -b_current_vert;
440 }
441}
442
443static float3 translation_to_plane(const float3 &current_position,
444 const float3 &normal,
445 const float3 &smoothed_position)
446{
447 float4 plane;
448 plane_from_point_normal_v3(plane, current_position, normal);
449
450 float3 smooth_closest_plane;
451 closest_to_plane_v3(smooth_closest_plane, plane, smoothed_position);
452
453 return smooth_closest_plane - current_position;
454}
455
456static float3 calc_boundary_normal_corner(const float3 &current_position,
457 const Span<float3> vert_positions,
458 const Span<int> neighbors)
459{
460 float3 normal(0);
461 for (const int vert : neighbors) {
462 const float3 to_neighbor = vert_positions[vert] - current_position;
463 normal += math::normalize(to_neighbor);
464 }
465 return math::normalize(normal);
466}
467
469 const Span<float3> positions,
470 const float3 &current_position,
471 const Span<SubdivCCGCoord> neighbors)
472{
473 float3 normal(0);
474 for (const SubdivCCGCoord &coord : neighbors) {
475 const float3 to_neighbor = positions[coord.to_index(key)] - current_position;
476 normal += math::normalize(to_neighbor);
477 }
478 return math::normalize(normal);
479}
480
481static float3 calc_boundary_normal_corner(const float3 &current_position,
482 const Span<BMVert *> neighbors)
483{
484 float3 normal(0);
485 for (BMVert *vert : neighbors) {
486 const float3 neighbor_pos = vert->co;
487 const float3 to_neighbor = neighbor_pos - current_position;
488 normal += math::normalize(to_neighbor);
489 }
490 return math::normalize(normal);
491}
492
494 const Span<float3> vert_normals,
496 const Span<int> corner_verts,
497 const GroupedSpan<int> vert_to_face_map,
498 const BitSpan boundary_verts,
499 const Span<int> face_sets,
500 const Span<bool> hide_poly,
501 const bool filter_boundary_face_sets,
502 const Span<int> verts,
503 const Span<float> factors,
504 const MutableSpan<float3> translations)
505{
506 BLI_assert(verts.size() == factors.size());
507 BLI_assert(verts.size() == translations.size());
508
509 Vector<int> neighbors;
510
511 for (const int i : verts.index_range()) {
512 if (factors[i] == 0.0f) {
513 translations[i] = float3(0);
514 continue;
515 }
516
517 vert_neighbors_get_mesh(faces, corner_verts, vert_to_face_map, hide_poly, verts[i], neighbors);
518
519 /* Don't modify corner vertices */
520 if (neighbors.size() <= 2) {
521 translations[i] = float3(0);
522 continue;
523 }
524
525 const bool is_boundary = boundary_verts[verts[i]];
526 if (is_boundary) {
527 neighbors.remove_if([&](const int vert) { return !boundary_verts[vert]; });
528 }
529
530 if (filter_boundary_face_sets) {
531 neighbors.remove_if([&](const int vert) {
532 return face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, vert);
533 });
534 }
535
536 if (neighbors.is_empty()) {
537 translations[i] = float3(0);
538 continue;
539 }
540
541 const float3 smoothed_position = calc_average(vert_positions, neighbors);
542
543 /* Normal Calculation */
544 float3 normal;
545 if (is_boundary && neighbors.size() == 2) {
546 normal = calc_boundary_normal_corner(vert_positions[verts[i]], vert_positions, neighbors);
547 if (math::is_zero(normal)) {
548 translations[i] = float3(0);
549 continue;
550 }
551 }
552 else {
553 normal = vert_normals[verts[i]];
554 }
555
556 const float3 translation = translation_to_plane(
557 vert_positions[verts[i]], normal, smoothed_position);
558
559 translations[i] = translation * factors[i];
560 }
561}
562
565 const Span<int> corner_verts,
566 const Span<int> face_sets,
567 const GroupedSpan<int> vert_to_face_map,
568 const BitSpan boundary_verts,
569 const Span<int> grids,
570 const bool filter_boundary_face_sets,
571 const Span<float> factors,
572 const MutableSpan<float3> translations)
573{
574 const Span<float3> positions = subdiv_ccg.positions;
575 const Span<float3> normals = subdiv_ccg.normals;
576 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
577
578 for (const int i : grids.index_range()) {
579 const IndexRange grid_range = bke::ccg::grid_range(key, grids[i]);
580 const int node_start = i * key.grid_area;
581 for (const int y : IndexRange(key.grid_size)) {
582 for (const int x : IndexRange(key.grid_size)) {
583 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
584 const int node_vert = node_start + offset;
585 const int vert = grid_range[offset];
586 if (factors[node_vert] == 0.0f) {
587 translations[node_vert] = float3(0);
588 continue;
589 }
590
591 SubdivCCGCoord coord{};
592 coord.grid_index = grids[i];
593 coord.x = x;
594 coord.y = y;
595
596 SubdivCCGNeighbors neighbor_storage;
597 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbor_storage);
598 SubdivCCGNeighborCoords &neighbors = neighbor_storage.coords;
599
600 /* Don't modify corner vertices */
601 if (neighbors.size() <= 2) {
602 translations[node_vert] = float3(0);
603 continue;
604 }
605
606 const bool is_boundary = BKE_subdiv_ccg_coord_is_mesh_boundary(
607 faces, corner_verts, boundary_verts, subdiv_ccg, coord);
608
609 if (is_boundary) {
610 neighbors.remove_if([&](const SubdivCCGCoord neighbor) {
612 faces, corner_verts, boundary_verts, subdiv_ccg, neighbor);
613 });
614 }
615
616 if (filter_boundary_face_sets) {
617 neighbors.remove_if([&](const SubdivCCGCoord neighbor) {
619 faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, neighbor);
620 });
621 }
622
623 if (neighbors.is_empty()) {
624 translations[node_vert] = float3(0);
625 continue;
626 }
627
628 const float3 smoothed_position = average_positions(key, positions, neighbors);
629
630 /* Normal Calculation */
631 float3 normal;
632 if (is_boundary && neighbors.size() == 2) {
633 normal = calc_boundary_normal_corner(key, positions, positions[vert], neighbors);
634 if (math::is_zero(normal)) {
635 translations[node_vert] = float3(0);
636 continue;
637 }
638 }
639 else {
640 normal = normals[vert];
641 }
642
643 const float3 translation = translation_to_plane(
644 positions[vert], normal, smoothed_position);
645
646 translations[node_vert] = translation * factors[node_vert];
647 }
648 }
649 }
650}
651
653 const Span<float3> positions,
654 const int face_set_offset,
655 const bool filter_boundary_face_sets,
656 const Span<float> factors,
657 const MutableSpan<float3> translations)
658{
659 BLI_assert(verts.size() == factors.size());
660 BLI_assert(verts.size() == translations.size());
661
662 BMeshNeighborVerts neighbors;
663
664 int i = 0;
665 for (BMVert *vert : verts) {
666 if (factors[i] == 0.0f) {
667 translations[i] = float3(0);
668 i++;
669 continue;
670 }
671
672 vert_neighbors_get_bmesh(*vert, neighbors);
673
674 /* Don't modify corner vertices */
675 if (neighbors.size() <= 2) {
676 translations[i] = float3(0);
677 i++;
678 continue;
679 }
680
681 const bool is_boundary = BM_vert_is_boundary(vert);
682 if (is_boundary) {
683 neighbors.remove_if([&](const BMVert *vert) { return !BM_vert_is_boundary(vert); });
684 }
685
686 if (filter_boundary_face_sets) {
687 neighbors.remove_if([&](const BMVert *vert) {
688 return face_set::vert_has_unique_face_set(face_set_offset, *vert);
689 });
690 }
691
692 if (neighbors.is_empty()) {
693 translations[i] = float3(0);
694 i++;
695 continue;
696 }
697
698 const float3 smoothed_position = average_positions(neighbors);
699
700 /* Normal Calculation */
701 float3 normal;
702 if (is_boundary && neighbors.size() == 2) {
703 normal = calc_boundary_normal_corner(positions[i], neighbors);
704 if (math::is_zero(normal)) {
705 translations[i] = float3(0);
706 i++;
707 continue;
708 }
709 }
710 else {
711 normal = vert->no;
712 }
713
714 const float3 translation = translation_to_plane(positions[i], normal, smoothed_position);
715
716 translations[i] = translation * factors[i];
717 i++;
718 }
719}
720
722 const int iterations,
724{
725 struct LocalData {
726 Vector<int> vert_indices;
727 Vector<int> neighbor_offsets;
728 Vector<int> neighbor_data;
729 Vector<float> new_factors;
730 };
731 const SculptSession &ss = *object.sculpt;
732 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
733 IndexMaskMemory memory;
734 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
735
737 switch (pbvh.type()) {
740
741 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
742 const OffsetIndices faces = mesh.faces();
743 const Span<int> corner_verts = mesh.corner_verts();
744 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
745 const bke::AttributeAccessor attributes = mesh.attributes();
746 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
748 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
750 for ([[maybe_unused]] const int _ : IndexRange(iterations)) {
751 node_mask.foreach_index(GrainSize(1), [&](const int i) {
752 LocalData &tls = all_tls.local();
753 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, tls.vert_indices);
754
756 corner_verts,
757 vert_to_face_map,
758 hide_poly,
759 verts,
760 tls.neighbor_offsets,
761 tls.neighbor_data);
762
763 tls.new_factors.resize(verts.size());
764 const MutableSpan<float> new_factors = tls.new_factors;
765 smooth::neighbor_data_average_mesh(data.as_span(), neighbors, new_factors);
766
767 scatter_data_mesh(new_factors.as_span(), verts, data);
768 });
769 }
770 break;
771 }
774 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
775 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
776 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
777 for ([[maybe_unused]] const int _ : IndexRange(iterations)) {
778 node_mask.foreach_index(GrainSize(1), [&](const int node_index) {
779 LocalData &tls = all_tls.local();
780 const Span<int> grids = nodes[node_index].grids();
781 const int grid_verts_num = key.grid_area * grids.size();
782
783 tls.new_factors.resize(grid_verts_num);
784 const MutableSpan<float> new_factors = tls.new_factors;
785 smooth::average_data_grids(subdiv_ccg, data.as_span(), grids, new_factors);
786
787 if (grid_hidden.is_empty()) {
788 scatter_data_grids(subdiv_ccg, new_factors.as_span(), grids, data);
789 }
790 else {
791 for (const int i : grids.index_range()) {
792 const int node_start = i * key.grid_area;
794 key, grid_hidden, grids[i], [&](const int offset) {
795 data[i] = new_factors[node_start + offset];
796 });
797 }
798 }
799 });
800 }
801 break;
802 }
805 for ([[maybe_unused]] const int _ : IndexRange(iterations)) {
806 node_mask.foreach_index(GrainSize(1), [&](const int node_index) {
807 LocalData &tls = all_tls.local();
809 const_cast<bke::pbvh::BMeshNode *>(&nodes[node_index]));
810
811 tls.new_factors.resize(verts.size());
812 const MutableSpan<float> new_factors = tls.new_factors;
813 smooth::average_data_bmesh(data.as_span(), verts, new_factors);
814
815 int i = 0;
816 for (const BMVert *vert : verts) {
818 i++;
819 continue;
820 }
821 data[BM_elem_index_get(vert)] = new_factors[i];
822 i++;
823 }
824 });
825 }
826 break;
827 }
828 }
829}
830
831} // namespace blender::ed::sculpt_paint::smooth
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:73
A BVH for high poly meshes.
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
bool BKE_subdiv_ccg_coord_is_mesh_boundary(blender::OffsetIndices< int > faces, blender::Span< int > corner_verts, blender::BitSpan boundary_verts, const SubdivCCG &subdiv_ccg, SubdivCCGCoord coord)
blender::Vector< SubdivCCGCoord, 256 > SubdivCCGNeighborCoords
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_foreach_visible_grid_vert(const CCGKey &key, const blender::BitGroupVector<> &grid_hidden, const int grid, const Fn &fn)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
#define BLI_assert(a)
Definition BLI_assert.h:46
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:435
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_EDGES_OF_VERT
BMesh const char void * data
bool BM_vert_is_boundary(const BMVert *v)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static T sum(const btAlignedObjectArray< T > &items)
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
int64_t size() const
int64_t remove_if(Predicate &&predicate)
bool is_empty() const
GAttributeReader lookup(const StringRef attribute_id) const
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
static ushort indices[]
static float verts[][3]
static float normals[][3]
ccl_device_inline float beta(const float x, const float y)
Definition math_base.h:661
#define T
static char faces[256]
IndexRange grid_range(const int grid_area, const int grid)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2628
float4 color_vert_get(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, int vert)
bool vert_has_unique_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, int vert)
Definition sculpt.cc:292
Span< int > node_visible_verts(const bke::pbvh::MeshNode &node, const Span< bool > hide_vert, Vector< int > &indices)
static void neighbor_position_average_interior_bmesh_impl(const Set< BMVert *, 0 > &verts, const Span< float > factors, const MutableSpan< float3 > new_positions)
void average_data_bmesh(const Span< T > src, const Set< BMVert *, 0 > &verts, const MutableSpan< T > dst)
void neighbor_position_average_interior_grids(const OffsetIndices< int > faces, const Span< int > corner_verts, const BitSpan boundary_verts, const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< float3 > new_positions)
static float3 translation_to_plane(const float3 &current_position, const float3 &normal, const float3 &smoothed_position)
static float3 calc_boundary_normal_corner(const float3 &current_position, const Span< float3 > vert_positions, const Span< int > neighbors)
void neighbor_data_average_mesh(const Span< T > src, const GroupedSpan< int > vert_neighbors, const MutableSpan< T > dst)
void neighbor_color_average(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const GSpan color_attribute, const bke::AttrDomain color_domain, const GroupedSpan< int > vert_neighbors, const MutableSpan< float4 > smooth_colors)
template void neighbor_data_average_mesh< float >(Span< float >, GroupedSpan< int >, MutableSpan< float >)
void neighbor_data_average_mesh_check_loose(const Span< T > src, const Span< int > verts, const GroupedSpan< int > vert_neighbors, const MutableSpan< T > dst)
void neighbor_position_average_interior_bmesh(const Set< BMVert *, 0 > &verts, const Span< float > factors, const MutableSpan< float3 > new_positions)
static float3 average_positions(const CCGKey &key, const Span< float3 > positions, const Span< SubdivCCGCoord > coords)
void surface_smooth_laplacian_step(const Span< float3 > positions, const Span< float3 > orig_positions, const Span< float3 > average_positions, const float alpha, MutableSpan< float3 > laplacian_disp, MutableSpan< float3 > translations)
template void neighbor_data_average_mesh_check_loose< float >(Span< float >, Span< int >, GroupedSpan< int >, MutableSpan< float >)
template void average_data_grids< float3 >(const SubdivCCG &, Span< float3 >, Span< int >, MutableSpan< float3 >)
template void neighbor_data_average_mesh< float3 >(Span< float3 >, GroupedSpan< int >, MutableSpan< float3 >)
template void neighbor_data_average_mesh_check_loose< float3 >(Span< float3 >, Span< int >, GroupedSpan< int >, MutableSpan< float3 >)
void surface_smooth_displace_step(const Span< float3 > laplacian_disp, const Span< float3 > average_laplacian_disp, const float beta, const MutableSpan< float3 > translations)
T calc_average(const Span< T > values, const Span< int > indices)
void bmesh_four_neighbor_average(float avg[3], const float3 &direction, const BMVert *v)
static void neighbor_position_average_interior_grids_impl(const OffsetIndices< int > faces, const Span< int > corner_verts, const BitSpan boundary_verts, const SubdivCCG &subdiv_ccg, const Span< int > grids, const Span< float > factors, const MutableSpan< float3 > new_positions)
void average_data_grids(const SubdivCCG &subdiv_ccg, const Span< T > src, const Span< int > grids, const MutableSpan< T > dst)
template void average_data_grids< float >(const SubdivCCG &, Span< float >, Span< int >, MutableSpan< float >)
void blur_geometry_data_array(const Object &object, const int iterations, const MutableSpan< float > data)
template void average_data_bmesh< float3 >(Span< float3 > src, const Set< BMVert *, 0 > &, MutableSpan< float3 >)
void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg, const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > face_sets, const GroupedSpan< int > vert_to_face_map, const BitSpan boundary_verts, const Span< int > grids, const bool filter_boundary_face_sets, const Span< float > factors, const MutableSpan< float3 > translations)
template void average_data_bmesh< float >(Span< float > src, const Set< BMVert *, 0 > &, MutableSpan< float >)
void calc_relaxed_translations_bmesh(const Set< BMVert *, 0 > &verts, const Span< float3 > positions, const int face_set_offset, const bool filter_boundary_face_sets, const Span< float > factors, const MutableSpan< float3 > translations)
void calc_relaxed_translations_faces(const Span< float3 > vert_positions, const Span< float3 > vert_normals, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const BitSpan boundary_verts, const Span< int > face_sets, const Span< bool > hide_poly, const bool filter_boundary_face_sets, const Span< int > verts, const Span< float > factors, const MutableSpan< float3 > translations)
template void neighbor_data_average_mesh< float4 >(Span< float4 >, GroupedSpan< int >, MutableSpan< float4 >)
void neighbor_position_average_bmesh(const Set< BMVert *, 0 > &verts, const MutableSpan< float3 > new_positions)
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7597
Vector< BMVert *, 64 > BMeshNeighborVerts
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6435
Span< BMVert * > vert_neighbors_get_interior_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:402
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:429
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6445
T safe_rcp(const T &a)
T safe_divide(const T &a, const T &b)
bool is_zero(const T &a)
T rcp(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
float co[3]
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
int to_index(const CCGKey &key) const
SubdivCCGNeighborCoords coords
blender::Array< blender::float3 > normals
blender::Array< blender::float3 > positions
i
Definition text_draw.cc:230