Blender V4.5
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 const int index = neighbor.grid_index * key.grid_area +
232 CCG_grid_xy_to_index(key.grid_size, neighbor.x, neighbor.y);
233 sum += src[index];
234 }
235 dst[node_vert_index] = math::safe_divide(sum, float(neighbors.coords.size()));
236 }
237 }
238 }
239}
240
241template<typename T>
243{
244 BMeshNeighborVerts neighbor_data;
245
246 int i = 0;
247 for (BMVert *vert : verts) {
248 T sum{};
249 const Span<BMVert *> neighbors = vert_neighbors_get_bmesh(*vert, neighbor_data);
250 for (const BMVert *neighbor : neighbors) {
251 sum += src[BM_elem_index_get(neighbor)];
252 }
253 dst[i] = math::safe_divide(sum, float(neighbors.size()));
254 i++;
255 }
256}
257
260 Span<int>,
264 Span<int>,
267 const Set<BMVert *, 0> &,
270 const Set<BMVert *, 0> &,
272
274{
275 const float factor = math::safe_rcp(float(verts.size()));
276 float3 result(0);
277 for (const BMVert *vert : verts) {
278 result += float3(vert->co) * factor;
279 }
280 return result;
281}
282
284 const MutableSpan<float3> new_positions)
285{
286 BLI_assert(verts.size() == new_positions.size());
287 BMeshNeighborVerts neighbor_data;
288
289 int i = 0;
290 for (BMVert *vert : verts) {
291 const Span<BMVert *> neighbors = vert_neighbors_get_bmesh(*vert, neighbor_data);
292 new_positions[i] = average_positions(neighbors);
293 i++;
294 }
295}
296
297template<bool use_factors>
299 const Span<float> factors,
300 const MutableSpan<float3> new_positions)
301{
302 BLI_assert(verts.size() == new_positions.size());
303 if constexpr (use_factors) {
304 BLI_assert(new_positions.size() == factors.size());
305 }
306 BMeshNeighborVerts neighbor_data;
307
308 int i = 0;
309 for (BMVert *vert : verts) {
310 if constexpr (use_factors) {
311 if (factors[i] == 0.0f) {
312 new_positions[i] = float3(vert->co);
313 i++;
314 continue;
315 }
316 }
317
318 const Span<BMVert *> neighbors = vert_neighbors_get_interior_bmesh(*vert, neighbor_data);
319 if (neighbors.is_empty()) {
320 new_positions[i] = float3(vert->co);
321 }
322 else {
323 new_positions[i] = average_positions(neighbors);
324 }
325 i++;
326 }
327}
329 const Span<float> factors,
330 const MutableSpan<float3> new_positions)
331{
333}
334
340
341void bmesh_four_neighbor_average(float avg[3], const float3 &direction, const BMVert *v)
342{
343 float avg_co[3] = {0.0f, 0.0f, 0.0f};
344 float tot_co = 0.0f;
345
346 BMIter eiter;
347 BMEdge *e;
348
349 BM_ITER_ELEM (e, &eiter, const_cast<BMVert *>(v), BM_EDGES_OF_VERT) {
350 if (BM_edge_is_boundary(e)) {
351 copy_v3_v3(avg, v->co);
352 return;
353 }
354 BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
355 float vec[3];
356 sub_v3_v3v3(vec, v_other->co, v->co);
357 madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
358 normalize_v3(vec);
359
360 /* fac is a measure of how orthogonal or parallel the edge is
361 * relative to the direction. */
362 float fac = dot_v3v3(vec, direction);
363 fac = fac * fac - 0.5f;
364 fac *= fac;
365 madd_v3_v3fl(avg_co, v_other->co, fac);
366 tot_co += fac;
367 }
368
369 /* In case vert has no Edge s. */
370 if (tot_co > 0.0f) {
371 mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
372
373 /* Preserve volume. */
374 float vec[3];
375 sub_v3_v3(avg, v->co);
376 mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
377 sub_v3_v3(avg, vec);
378 add_v3_v3(avg, v->co);
379 }
380 else {
381 zero_v3(avg);
382 }
383}
384
386 const Span<int> corner_verts,
387 const GroupedSpan<int> vert_to_face_map,
388 const GSpan color_attribute,
389 const bke::AttrDomain color_domain,
390 const GroupedSpan<int> vert_neighbors,
391 const MutableSpan<float4> smooth_colors)
392{
393 BLI_assert(vert_neighbors.size() == smooth_colors.size());
394
395 for (const int i : vert_neighbors.index_range()) {
396 float4 sum(0);
397 const Span<int> neighbors = vert_neighbors[i];
398 for (const int vert : neighbors) {
400 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, vert);
401 }
402 smooth_colors[i] = math::safe_divide(sum, float(neighbors.size()));
403 }
404}
405
406/* HC Smooth Algorithm. */
407/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
408
410 const Span<float3> orig_positions,
412 const float alpha,
413 MutableSpan<float3> laplacian_disp,
414 MutableSpan<float3> translations)
415{
416 BLI_assert(positions.size() == orig_positions.size());
417 BLI_assert(positions.size() == average_positions.size());
418 BLI_assert(positions.size() == laplacian_disp.size());
419 BLI_assert(positions.size() == translations.size());
420
421 for (const int i : average_positions.index_range()) {
422 const float3 weighted_o = orig_positions[i] * alpha;
423 const float3 weighted_q = positions[i] * (1.0f - alpha);
424 const float3 d = weighted_o + weighted_q;
425 laplacian_disp[i] = average_positions[i] - d;
426 translations[i] = average_positions[i] - positions[i];
427 }
428}
429
431 const Span<float3> average_laplacian_disp,
432 const float beta,
433 const MutableSpan<float3> translations)
434{
435 BLI_assert(laplacian_disp.size() == average_laplacian_disp.size());
436 BLI_assert(laplacian_disp.size() == translations.size());
437
438 for (const int i : laplacian_disp.index_range()) {
439 float3 b_current_vert = average_laplacian_disp[i] * (1.0f - beta);
440 b_current_vert += laplacian_disp[i] * beta;
441 translations[i] = -b_current_vert;
442 }
443}
444
445static float3 translation_to_plane(const float3 &current_position,
446 const float3 &normal,
447 const float3 &smoothed_position)
448{
449 float4 plane;
450 plane_from_point_normal_v3(plane, current_position, normal);
451
452 float3 smooth_closest_plane;
453 closest_to_plane_v3(smooth_closest_plane, plane, smoothed_position);
454
455 return smooth_closest_plane - current_position;
456}
457
458static float3 calc_boundary_normal_corner(const float3 &current_position,
459 const Span<float3> vert_positions,
460 const Span<int> neighbors)
461{
462 float3 normal(0);
463 for (const int vert : neighbors) {
464 const float3 to_neighbor = vert_positions[vert] - current_position;
465 normal += math::normalize(to_neighbor);
466 }
467 return math::normalize(normal);
468}
469
471 const Span<float3> positions,
472 const float3 &current_position,
473 const Span<SubdivCCGCoord> neighbors)
474{
475 float3 normal(0);
476 for (const SubdivCCGCoord &coord : neighbors) {
477 const float3 to_neighbor = positions[coord.to_index(key)] - current_position;
478 normal += math::normalize(to_neighbor);
479 }
480 return math::normalize(normal);
481}
482
483static float3 calc_boundary_normal_corner(const float3 &current_position,
484 const Span<BMVert *> neighbors)
485{
486 float3 normal(0);
487 for (BMVert *vert : neighbors) {
488 const float3 neighbor_pos = vert->co;
489 const float3 to_neighbor = neighbor_pos - current_position;
490 normal += math::normalize(to_neighbor);
491 }
492 return math::normalize(normal);
493}
494
496 const Span<float3> vert_normals,
498 const Span<int> corner_verts,
499 const GroupedSpan<int> vert_to_face_map,
500 const BitSpan boundary_verts,
501 const Span<int> face_sets,
502 const Span<bool> hide_poly,
503 const bool filter_boundary_face_sets,
504 const Span<int> verts,
505 const Span<float> factors,
506 const MutableSpan<float3> translations)
507{
508 BLI_assert(verts.size() == factors.size());
509 BLI_assert(verts.size() == translations.size());
510
511 Vector<int> neighbors;
512
513 for (const int i : verts.index_range()) {
514 if (factors[i] == 0.0f) {
515 translations[i] = float3(0);
516 continue;
517 }
518
519 vert_neighbors_get_mesh(faces, corner_verts, vert_to_face_map, hide_poly, verts[i], neighbors);
520
521 /* Don't modify corner vertices */
522 if (neighbors.size() <= 2) {
523 translations[i] = float3(0);
524 continue;
525 }
526
527 const bool is_boundary = boundary_verts[verts[i]];
528 if (is_boundary) {
529 neighbors.remove_if([&](const int vert) { return !boundary_verts[vert]; });
530 }
531
532 if (filter_boundary_face_sets) {
533 neighbors.remove_if([&](const int vert) {
534 return face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, vert);
535 });
536 }
537
538 if (neighbors.is_empty()) {
539 translations[i] = float3(0);
540 continue;
541 }
542
543 const float3 smoothed_position = calc_average(vert_positions, neighbors);
544
545 /* Normal Calculation */
546 float3 normal;
547 if (is_boundary && neighbors.size() == 2) {
548 normal = calc_boundary_normal_corner(vert_positions[verts[i]], vert_positions, neighbors);
549 if (math::is_zero(normal)) {
550 translations[i] = float3(0);
551 continue;
552 }
553 }
554 else {
555 normal = vert_normals[verts[i]];
556 }
557
558 const float3 translation = translation_to_plane(
559 vert_positions[verts[i]], normal, smoothed_position);
560
561 translations[i] = translation * factors[i];
562 }
563}
564
567 const Span<int> corner_verts,
568 const Span<int> face_sets,
569 const GroupedSpan<int> vert_to_face_map,
570 const BitSpan boundary_verts,
571 const Span<int> grids,
572 const bool filter_boundary_face_sets,
573 const Span<float> factors,
574 const MutableSpan<float3> translations)
575{
576 const Span<float3> positions = subdiv_ccg.positions;
577 const Span<float3> normals = subdiv_ccg.normals;
578 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
579
580 for (const int i : grids.index_range()) {
581 const IndexRange grid_range = bke::ccg::grid_range(key, grids[i]);
582 const int node_start = i * key.grid_area;
583 for (const int y : IndexRange(key.grid_size)) {
584 for (const int x : IndexRange(key.grid_size)) {
585 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
586 const int node_vert = node_start + offset;
587 const int vert = grid_range[offset];
588 if (factors[node_vert] == 0.0f) {
589 translations[node_vert] = float3(0);
590 continue;
591 }
592
593 SubdivCCGCoord coord{};
594 coord.grid_index = grids[i];
595 coord.x = x;
596 coord.y = y;
597
598 SubdivCCGNeighbors neighbor_storage;
599 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbor_storage);
600 SubdivCCGNeighborCoords &neighbors = neighbor_storage.coords;
601
602 /* Don't modify corner vertices */
603 if (neighbors.size() <= 2) {
604 translations[node_vert] = float3(0);
605 continue;
606 }
607
608 const bool is_boundary = BKE_subdiv_ccg_coord_is_mesh_boundary(
609 faces, corner_verts, boundary_verts, subdiv_ccg, coord);
610
611 if (is_boundary) {
612 neighbors.remove_if([&](const SubdivCCGCoord neighbor) {
614 faces, corner_verts, boundary_verts, subdiv_ccg, neighbor);
615 });
616 }
617
618 if (filter_boundary_face_sets) {
619 neighbors.remove_if([&](const SubdivCCGCoord neighbor) {
621 faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, neighbor);
622 });
623 }
624
625 if (neighbors.is_empty()) {
626 translations[node_vert] = float3(0);
627 continue;
628 }
629
630 const float3 smoothed_position = average_positions(key, positions, neighbors);
631
632 /* Normal Calculation */
633 float3 normal;
634 if (is_boundary && neighbors.size() == 2) {
635 normal = calc_boundary_normal_corner(key, positions, positions[vert], neighbors);
636 if (math::is_zero(normal)) {
637 translations[node_vert] = float3(0);
638 continue;
639 }
640 }
641 else {
642 normal = normals[vert];
643 }
644
645 const float3 translation = translation_to_plane(
646 positions[vert], normal, smoothed_position);
647
648 translations[node_vert] = translation * factors[node_vert];
649 }
650 }
651 }
652}
653
655 const Span<float3> positions,
656 const int face_set_offset,
657 const bool filter_boundary_face_sets,
658 const Span<float> factors,
659 const MutableSpan<float3> translations)
660{
661 BLI_assert(verts.size() == factors.size());
662 BLI_assert(verts.size() == translations.size());
663
664 BMeshNeighborVerts neighbors;
665
666 int i = 0;
667 for (BMVert *vert : verts) {
668 if (factors[i] == 0.0f) {
669 translations[i] = float3(0);
670 i++;
671 continue;
672 }
673
674 vert_neighbors_get_bmesh(*vert, neighbors);
675
676 /* Don't modify corner vertices */
677 if (neighbors.size() <= 2) {
678 translations[i] = float3(0);
679 i++;
680 continue;
681 }
682
683 const bool is_boundary = BM_vert_is_boundary(vert);
684 if (is_boundary) {
685 neighbors.remove_if([&](const BMVert *vert) { return !BM_vert_is_boundary(vert); });
686 }
687
688 if (filter_boundary_face_sets) {
689 neighbors.remove_if([&](const BMVert *vert) {
690 return face_set::vert_has_unique_face_set(face_set_offset, *vert);
691 });
692 }
693
694 if (neighbors.is_empty()) {
695 translations[i] = float3(0);
696 i++;
697 continue;
698 }
699
700 const float3 smoothed_position = average_positions(neighbors);
701
702 /* Normal Calculation */
703 float3 normal;
704 if (is_boundary && neighbors.size() == 2) {
705 normal = calc_boundary_normal_corner(positions[i], neighbors);
706 if (math::is_zero(normal)) {
707 translations[i] = float3(0);
708 i++;
709 continue;
710 }
711 }
712 else {
713 normal = vert->no;
714 }
715
716 const float3 translation = translation_to_plane(positions[i], normal, smoothed_position);
717
718 translations[i] = translation * factors[i];
719 i++;
720 }
721}
722
724 const int iterations,
726{
727 struct LocalData {
728 Vector<int> vert_indices;
729 Vector<int> neighbor_offsets;
730 Vector<int> neighbor_data;
731 Vector<float> new_factors;
732 };
733 const SculptSession &ss = *object.sculpt;
734 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
735 IndexMaskMemory memory;
736 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
737
739 switch (pbvh.type()) {
742
743 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
744 const OffsetIndices faces = mesh.faces();
745 const Span<int> corner_verts = mesh.corner_verts();
746 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
747 const bke::AttributeAccessor attributes = mesh.attributes();
748 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
750 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
752 for ([[maybe_unused]] const int _ : IndexRange(iterations)) {
753 node_mask.foreach_index(GrainSize(1), [&](const int i) {
754 LocalData &tls = all_tls.local();
755 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, tls.vert_indices);
756
758 corner_verts,
759 vert_to_face_map,
760 hide_poly,
761 verts,
762 tls.neighbor_offsets,
763 tls.neighbor_data);
764
765 tls.new_factors.resize(verts.size());
766 const MutableSpan<float> new_factors = tls.new_factors;
767 smooth::neighbor_data_average_mesh(data.as_span(), neighbors, new_factors);
768
769 scatter_data_mesh(new_factors.as_span(), verts, data);
770 });
771 }
772 break;
773 }
776 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
777 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
778 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
779 for ([[maybe_unused]] const int _ : IndexRange(iterations)) {
780 node_mask.foreach_index(GrainSize(1), [&](const int node_index) {
781 LocalData &tls = all_tls.local();
782 const Span<int> grids = nodes[node_index].grids();
783 const int grid_verts_num = key.grid_area * grids.size();
784
785 tls.new_factors.resize(grid_verts_num);
786 const MutableSpan<float> new_factors = tls.new_factors;
787 smooth::average_data_grids(subdiv_ccg, data.as_span(), grids, new_factors);
788
789 if (grid_hidden.is_empty()) {
790 scatter_data_grids(subdiv_ccg, new_factors.as_span(), grids, data);
791 }
792 else {
793 for (const int i : grids.index_range()) {
794 const int node_start = i * key.grid_area;
796 key, grid_hidden, grids[i], [&](const int offset) {
797 data[i] = new_factors[node_start + offset];
798 });
799 }
800 }
801 });
802 }
803 break;
804 }
807 for ([[maybe_unused]] const int _ : IndexRange(iterations)) {
808 node_mask.foreach_index(GrainSize(1), [&](const int node_index) {
809 LocalData &tls = all_tls.local();
811 const_cast<bke::pbvh::BMeshNode *>(&nodes[node_index]));
812
813 tls.new_factors.resize(verts.size());
814 const MutableSpan<float> new_factors = tls.new_factors;
815 smooth::average_data_bmesh(data.as_span(), verts, new_factors);
816
817 int i = 0;
818 for (const BMVert *vert : verts) {
820 i++;
821 continue;
822 }
823 data[BM_elem_index_get(vert)] = new_factors[i];
824 i++;
825 }
826 });
827 }
828 break;
829 }
830 }
831}
832
833} // 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:77
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:651
#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:2912
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
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:293
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:7596
Vector< BMVert *, 64 > BMeshNeighborVerts
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6419
Span< BMVert * > vert_neighbors_get_interior_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:403
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:388
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:430
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6429
T safe_rcp(const T &a)
T 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:415
SubdivCCGNeighborCoords coords
blender::Array< blender::float3 > normals
blender::Array< blender::float3 > positions
i
Definition text_draw.cc:230