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