Blender V4.3
mesh_evaluate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <climits>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_mesh_types.h"
16#include "DNA_meshdata_types.h"
17
18#include "BLI_array_utils.hh"
19#include "BLI_index_range.hh"
20#include "BLI_math_geom.h"
21#include "BLI_span.hh"
22#include "BLI_utildefines.h"
23#include "BLI_virtual_array.hh"
24
25#include "BKE_attribute.hh"
26#include "BKE_mesh.hh"
27
28using blender::float3;
29using blender::int2;
32using blender::Span;
33using blender::VArray;
34
35/* -------------------------------------------------------------------- */
39namespace blender::bke::mesh {
40
41static float3 face_center_calc_ngon(const Span<float3> vert_positions, const Span<int> face_verts)
42{
43 const float w = 1.0f / float(face_verts.size());
44
45 float3 center(0);
46 for (const int i : face_verts.index_range()) {
47 center += vert_positions[face_verts[i]] * w;
48 }
49 return center;
50}
51
52float3 face_center_calc(const Span<float3> vert_positions, const Span<int> face_verts)
53{
54 if (face_verts.size() == 3) {
55 float3 center;
56 mid_v3_v3v3v3(center,
57 vert_positions[face_verts[0]],
58 vert_positions[face_verts[1]],
59 vert_positions[face_verts[2]]);
60 return center;
61 }
62 if (face_verts.size() == 4) {
63 float3 center;
64 mid_v3_v3v3v3v3(center,
65 vert_positions[face_verts[0]],
66 vert_positions[face_verts[1]],
67 vert_positions[face_verts[2]],
68 vert_positions[face_verts[3]]);
69 return center;
70 }
71 return face_center_calc_ngon(vert_positions, face_verts);
72}
73
74float face_area_calc(const Span<float3> vert_positions, const Span<int> face_verts)
75{
76 if (face_verts.size() == 3) {
77 return area_tri_v3(vert_positions[face_verts[0]],
78 vert_positions[face_verts[1]],
79 vert_positions[face_verts[2]]);
80 }
81 Array<float3, 32> coords(face_verts.size());
82 for (const int i : face_verts.index_range()) {
83 coords[i] = vert_positions[face_verts[i]];
84 }
85 return area_poly_v3((const float(*)[3])coords.data(), face_verts.size());
86}
87
88} // namespace blender::bke::mesh
89
90float BKE_mesh_calc_area(const Mesh *mesh)
91{
92 const Span<float3> positions = mesh->vert_positions();
93 const blender::OffsetIndices faces = mesh->faces();
94 const Span<int> corner_verts = mesh->corner_verts();
95
96 float total_area = 0.0f;
97 for (const int i : faces.index_range()) {
98 total_area += blender::bke::mesh::face_area_calc(positions, corner_verts.slice(faces[i]));
99 }
100 return total_area;
101}
102
103static float UNUSED_FUNCTION(mesh_calc_face_volume_centroid)(const int *face_verts,
104 const int face_size,
105 const float (*positions)[3],
106 float r_cent[3])
107{
108 const float *v_pivot, *v_step1;
109 float total_volume = 0.0f;
110
111 zero_v3(r_cent);
112
113 v_pivot = positions[face_verts[0]];
114 v_step1 = positions[face_verts[1]];
115
116 for (int i = 2; i < face_size; i++) {
117 const float *v_step2 = positions[face_verts[i]];
118
119 /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
120 * of the triangle and the origin as the fourth vertex */
121 const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
122 total_volume += tetra_volume;
123
124 /* Calculate the centroid of the tetrahedron formed by the 3 vertices
125 * of the triangle and the origin as the fourth vertex.
126 * The centroid is simply the average of the 4 vertices.
127 *
128 * Note that the vector is 4x the actual centroid
129 * so the division can be done once at the end. */
130 for (uint j = 0; j < 3; j++) {
131 r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
132 }
133
134 v_step1 = v_step2;
135 }
136
137 return total_volume;
138}
139
140namespace blender::bke::mesh {
141
148 const Span<int> face_verts,
149 const float3 &reference_center,
150 float r_cent[3])
151{
152 /* See: mesh_calc_face_volume_centroid for comments. */
153 float v_pivot[3], v_step1[3];
154 float total_volume = 0.0f;
155 zero_v3(r_cent);
156 sub_v3_v3v3(v_pivot, positions[face_verts[0]], reference_center);
157 sub_v3_v3v3(v_step1, positions[face_verts[1]], reference_center);
158 for (int i = 2; i < face_verts.size(); i++) {
159 float v_step2[3];
160 sub_v3_v3v3(v_step2, positions[face_verts[i]], reference_center);
161 const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2);
162 total_volume += tetra_volume;
163 for (uint j = 0; j < 3; j++) {
164 r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
165 }
166 copy_v3_v3(v_step1, v_step2);
167 }
168 return total_volume;
169}
170
177static float face_area_centroid_calc(const Span<float3> positions,
178 const Span<int> face_verts,
179 float r_cent[3])
180{
181 float total_area = 0.0f;
182 float v1[3], v2[3], v3[3], tri_cent[3];
183
184 const float3 normal = blender::bke::mesh::face_normal_calc(positions, face_verts);
185
186 copy_v3_v3(v1, positions[face_verts[0]]);
187 copy_v3_v3(v2, positions[face_verts[1]]);
188
189 zero_v3(r_cent);
190
191 for (int i = 2; i < face_verts.size(); i++) {
192 copy_v3_v3(v3, positions[face_verts[i]]);
193
194 float tri_area = area_tri_signed_v3(v1, v2, v3, normal);
195 total_area += tri_area;
196
197 mid_v3_v3v3v3(tri_cent, v1, v2, v3);
198 madd_v3_v3fl(r_cent, tri_cent, tri_area);
199
200 copy_v3_v3(v2, v3);
201 }
202
203 mul_v3_fl(r_cent, 1.0f / total_area);
204
205 return total_area;
206}
207
208void face_angles_calc(const Span<float3> vert_positions,
209 const Span<int> face_verts,
210 MutableSpan<float> angles)
211{
212 float nor_prev[3];
213 float nor_next[3];
214
215 int i_this = face_verts.size() - 1;
216 int i_next = 0;
217
219 nor_prev, vert_positions[face_verts[i_this - 1]], vert_positions[face_verts[i_this]]);
220 normalize_v3(nor_prev);
221
222 while (i_next < face_verts.size()) {
223 sub_v3_v3v3(nor_next, vert_positions[face_verts[i_this]], vert_positions[face_verts[i_next]]);
224 normalize_v3(nor_next);
225 angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next);
226
227 /* step */
228 copy_v3_v3(nor_prev, nor_next);
229 i_this = i_next;
230 i_next++;
231 }
232}
233
234} // namespace blender::bke::mesh
235
238/* -------------------------------------------------------------------- */
242bool BKE_mesh_center_median(const Mesh *mesh, float r_cent[3])
243{
244 const Span<float3> positions = mesh->vert_positions();
245 zero_v3(r_cent);
246 for (const int i : positions.index_range()) {
247 add_v3_v3(r_cent, positions[i]);
248 }
249 /* otherwise we get NAN for 0 verts */
250 if (mesh->verts_num) {
251 mul_v3_fl(r_cent, 1.0f / float(mesh->verts_num));
252 }
253 return (mesh->verts_num != 0);
254}
255
256bool BKE_mesh_center_median_from_faces(const Mesh *mesh, float r_cent[3])
257{
258 int tot = 0;
259 const Span<float3> positions = mesh->vert_positions();
260 const blender::OffsetIndices faces = mesh->faces();
261 const Span<int> corner_verts = mesh->corner_verts();
262 zero_v3(r_cent);
263 for (const int i : faces.index_range()) {
264 for (const int vert : corner_verts.slice(faces[i])) {
265 add_v3_v3(r_cent, positions[vert]);
266 }
267 tot += faces[i].size();
268 }
269 /* otherwise we get NAN for 0 verts */
270 if (mesh->faces_num) {
271 mul_v3_fl(r_cent, 1.0f / float(tot));
272 }
273 return (mesh->faces_num != 0);
274}
275
276bool BKE_mesh_center_of_surface(const Mesh *mesh, float r_cent[3])
277{
278 float face_area;
279 float total_area = 0.0f;
280 float face_cent[3];
281 const Span<float3> positions = mesh->vert_positions();
282 const blender::OffsetIndices faces = mesh->faces();
283 const Span<int> corner_verts = mesh->corner_verts();
284
285 zero_v3(r_cent);
286
287 /* calculate a weighted average of face centroids */
288 for (const int i : faces.index_range()) {
290 positions, corner_verts.slice(faces[i]), face_cent);
291
292 madd_v3_v3fl(r_cent, face_cent, face_area);
293 total_area += face_area;
294 }
295 /* otherwise we get NAN for 0 faces */
296 if (mesh->faces_num) {
297 mul_v3_fl(r_cent, 1.0f / total_area);
298 }
299
300 /* zero area faces cause this, fallback to median */
301 if (UNLIKELY(!is_finite_v3(r_cent))) {
302 return BKE_mesh_center_median(mesh, r_cent);
303 }
304
305 return (mesh->faces_num != 0);
306}
307
308bool BKE_mesh_center_of_volume(const Mesh *mesh, float r_cent[3])
309{
310 float face_volume;
311 float total_volume = 0.0f;
312 float face_cent[3];
313 const Span<float3> positions = mesh->vert_positions();
314 const blender::OffsetIndices faces = mesh->faces();
315 const Span<int> corner_verts = mesh->corner_verts();
316
317 /* Use an initial center to avoid numeric instability of geometry far away from the center. */
318 float init_cent[3];
319 const bool init_cent_result = BKE_mesh_center_median_from_faces(mesh, init_cent);
320
321 zero_v3(r_cent);
322
323 /* calculate a weighted average of polyhedron centroids */
324 for (const int i : faces.index_range()) {
326 positions, corner_verts.slice(faces[i]), init_cent, face_cent);
327
328 /* face_cent is already volume-weighted, so no need to multiply by the volume */
329 add_v3_v3(r_cent, face_cent);
330 total_volume += face_volume;
331 }
332 /* otherwise we get NAN for 0 faces */
333 if (total_volume != 0.0f) {
334 /* multiply by 0.25 to get the correct centroid */
335 /* no need to divide volume by 6 as the centroid is weighted by 6x the volume,
336 * so it all cancels out. */
337 mul_v3_fl(r_cent, 0.25f / total_volume);
338 }
339
340 /* this can happen for non-manifold objects, fallback to median */
341 if (UNLIKELY(!is_finite_v3(r_cent))) {
342 copy_v3_v3(r_cent, init_cent);
343 return init_cent_result;
344 }
345 add_v3_v3(r_cent, init_cent);
346 return (mesh->faces_num != 0);
347}
348
351/* -------------------------------------------------------------------- */
355static bool mesh_calc_center_centroid_ex(const float (*positions)[3],
356 int /*mverts_num*/,
357 const blender::int3 *corner_tris,
358 int corner_tris_num,
359 const int *corner_verts,
360 float r_center[3])
361{
362
363 zero_v3(r_center);
364
365 if (corner_tris_num == 0) {
366 return false;
367 }
368
369 float totweight = 0.0f;
370 int i;
371 for (i = 0; i < corner_tris_num; i++) {
372 const float *v1 = positions[corner_verts[corner_tris[i][0]]];
373 const float *v2 = positions[corner_verts[corner_tris[i][1]]];
374 const float *v3 = positions[corner_verts[corner_tris[i][2]]];
375 float area;
376
377 area = area_tri_v3(v1, v2, v3);
378 madd_v3_v3fl(r_center, v1, area);
379 madd_v3_v3fl(r_center, v2, area);
380 madd_v3_v3fl(r_center, v3, area);
381 totweight += area;
382 }
383 if (totweight == 0.0f) {
384 return false;
385 }
386
387 mul_v3_fl(r_center, 1.0f / (3.0f * totweight));
388
389 return true;
390}
391
392void BKE_mesh_calc_volume(const float (*vert_positions)[3],
393 const int mverts_num,
394 const blender::int3 *corner_tris,
395 const int corner_tris_num,
396 const int *corner_verts,
397 float *r_volume,
398 float r_center[3])
399{
400 float center[3];
401 float totvol;
402 int i;
403
404 if (r_volume) {
405 *r_volume = 0.0f;
406 }
407 if (r_center) {
408 zero_v3(r_center);
409 }
410
411 if (corner_tris_num == 0) {
412 return;
413 }
414
416 vert_positions, mverts_num, corner_tris, corner_tris_num, corner_verts, center))
417 {
418 return;
419 }
420
421 totvol = 0.0f;
422
423 for (i = 0; i < corner_tris_num; i++) {
424 const float *v1 = vert_positions[corner_verts[corner_tris[i][0]]];
425 const float *v2 = vert_positions[corner_verts[corner_tris[i][1]]];
426 const float *v3 = vert_positions[corner_verts[corner_tris[i][2]]];
427 float vol;
428
429 vol = volume_tetrahedron_signed_v3(center, v1, v2, v3);
430 if (r_volume) {
431 totvol += vol;
432 }
433 if (r_center) {
434 /* averaging factor 1/3 is applied in the end */
435 madd_v3_v3fl(r_center, v1, vol);
436 madd_v3_v3fl(r_center, v2, vol);
437 madd_v3_v3fl(r_center, v3, vol);
438 }
439 }
440
441 /* NOTE: Depending on arbitrary centroid position,
442 * totvol can become negative even for a valid mesh.
443 * The true value is always the positive value.
444 */
445 if (r_volume) {
446 *r_volume = fabsf(totvol);
447 }
448 if (r_center) {
449 /* NOTE: Factor 1/3 is applied once for all vertices here.
450 * This also automatically negates the vector if totvol is negative.
451 */
452 if (totvol != 0.0f) {
453 mul_v3_fl(r_center, (1.0f / 3.0f) / totvol);
454 }
455 }
456}
457
460/* -------------------------------------------------------------------- */
464void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
465{
466 if (UNLIKELY(!md->totdisp || !md->disps)) {
467 return;
468 }
469
470 const int sides = int(sqrt(md->totdisp));
471 float(*co)[3] = md->disps;
472
473 for (int x = 0; x < sides; x++) {
474 float *co_a, *co_b;
475
476 for (int y = 0; y < x; y++) {
477 co_a = co[y * sides + x];
478 co_b = co[x * sides + y];
479
480 swap_v3_v3(co_a, co_b);
481 std::swap(co_a[0], co_a[1]);
482 std::swap(co_b[0], co_b[1]);
483
484 if (use_loop_mdisp_flip) {
485 co_a[2] *= -1.0f;
486 co_b[2] *= -1.0f;
487 }
488 }
489
490 co_a = co[x * sides + x];
491
492 std::swap(co_a[0], co_a[1]);
493
494 if (use_loop_mdisp_flip) {
495 co_a[2] *= -1.0f;
496 }
497 }
498}
499
502/* -------------------------------------------------------------------- */
506namespace blender::bke {
507
509 const Span<bool> hide_vert,
510 MutableSpan<bool> hide_edge)
511{
512 using namespace blender;
513 threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
514 for (const int i : range) {
515 hide_edge[i] = hide_vert[edges[i][0]] || hide_vert[edges[i][1]];
516 }
517 });
518}
519
521 const Span<int> corner_verts,
522 const Span<bool> hide_vert,
523 MutableSpan<bool> hide_poly)
524{
525 using namespace blender;
526 threading::parallel_for(faces.index_range(), 4096, [&](const IndexRange range) {
527 for (const int i : range) {
528 const Span<int> face_verts = corner_verts.slice(faces[i]);
529 hide_poly[i] = std::any_of(
530 face_verts.begin(), face_verts.end(), [&](const int vert) { return hide_vert[vert]; });
531 }
532 });
533}
534
536{
537 MutableAttributeAccessor attributes = mesh.attributes_for_write();
538
539 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
540 ".hide_vert", AttrDomain::Point, false);
541 if (hide_vert.is_single() && !hide_vert.get_internal_single()) {
542 attributes.remove(".hide_edge");
543 attributes.remove(".hide_poly");
544 return;
545 }
546 const VArraySpan<bool> hide_vert_span{hide_vert};
547
548 SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>(
549 ".hide_edge", AttrDomain::Edge);
550 SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>(
551 ".hide_poly", AttrDomain::Face);
552
553 mesh_edge_hide_from_vert(mesh.edges(), hide_vert_span, hide_edge.span);
554 mesh_face_hide_from_vert(mesh.faces(), mesh.corner_verts(), hide_vert_span, hide_poly.span);
555
556 hide_edge.finish();
557 hide_poly.finish();
558}
559
561{
562 MutableAttributeAccessor attributes = mesh.attributes_for_write();
563
564 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
565 ".hide_poly", AttrDomain::Face, false);
566 if (hide_poly.is_single() && !hide_poly.get_internal_single()) {
567 attributes.remove(".hide_vert");
568 attributes.remove(".hide_edge");
569 return;
570 }
571 const VArraySpan<bool> hide_poly_span{hide_poly};
572 const OffsetIndices faces = mesh.faces();
573 const Span<int> corner_verts = mesh.corner_verts();
574 const Span<int> corner_edges = mesh.corner_edges();
575 SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>(
576 ".hide_vert", AttrDomain::Point);
577 SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>(
578 ".hide_edge", AttrDomain::Edge);
579
580 /* Hide all edges or vertices connected to hidden polygons. */
581 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
582 for (const int i : range) {
583 if (hide_poly_span[i]) {
584 hide_vert.span.fill_indices(corner_verts.slice(faces[i]), true);
585 hide_edge.span.fill_indices(corner_edges.slice(faces[i]), true);
586 }
587 }
588 });
589 /* Unhide vertices and edges connected to visible polygons. */
590 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
591 for (const int i : range) {
592 if (!hide_poly_span[i]) {
593 hide_vert.span.fill_indices(corner_verts.slice(faces[i]), false);
594 hide_edge.span.fill_indices(corner_edges.slice(faces[i]), false);
595 }
596 }
597 });
598
599 hide_vert.finish();
600 hide_edge.finish();
601}
602
605/* -------------------------------------------------------------------- */
610{
611 MutableAttributeAccessor attributes = mesh.attributes_for_write();
612 const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
613 ".select_poly", AttrDomain::Face, false);
614 if (select_poly.is_single() && !select_poly.get_internal_single()) {
615 attributes.remove(".select_vert");
616 attributes.remove(".select_edge");
617 return;
618 }
619 SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_only_span<bool>(
620 ".select_vert", AttrDomain::Point);
621 SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>(
622 ".select_edge", AttrDomain::Edge);
623
624 /* Use generic domain interpolation to read the face attribute on the other domains.
625 * Assume selected faces are not hidden and none of their vertices/edges are hidden. */
626 array_utils::copy(*attributes.lookup_or_default<bool>(".select_poly", AttrDomain::Point, false),
627 select_vert.span);
628 array_utils::copy(*attributes.lookup_or_default<bool>(".select_poly", AttrDomain::Edge, false),
629 select_edge.span);
630
631 select_vert.finish();
632 select_edge.finish();
633}
634
636{
637 MutableAttributeAccessor attributes = mesh.attributes_for_write();
638 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
639 ".select_vert", AttrDomain::Point, false);
640 if (select_vert.is_single() && !select_vert.get_internal_single()) {
641 attributes.remove(".select_edge");
642 attributes.remove(".select_poly");
643 return;
644 }
645 SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>(
646 ".select_edge", AttrDomain::Edge);
647 SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>(
648 ".select_poly", AttrDomain::Face);
649 {
650 IndexMaskMemory memory;
651 const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
652 ".hide_edge", AttrDomain::Edge, false);
653 array_utils::copy(
654 *attributes.lookup_or_default<bool>(".select_vert", AttrDomain::Edge, false),
655 IndexMask::from_bools(hide_edge, memory).complement(hide_edge.index_range(), memory),
656 select_edge.span);
657 }
658 {
659 IndexMaskMemory memory;
660 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
661 ".hide_poly", AttrDomain::Face, false);
662 array_utils::copy(
663 *attributes.lookup_or_default<bool>(".select_vert", AttrDomain::Face, false),
664 IndexMask::from_bools(hide_poly, memory).complement(hide_poly.index_range(), memory),
665 select_poly.span);
666 }
667 select_edge.finish();
668 select_poly.finish();
669}
670
672{
673 MutableAttributeAccessor attributes = mesh.attributes_for_write();
674 const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
675 ".select_edge", AttrDomain::Point, false);
676 if (select_edge.is_single() && !select_edge.get_internal_single()) {
677 attributes.remove(".select_vert");
678 attributes.remove(".select_poly");
679 return;
680 }
681 SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_only_span<bool>(
682 ".select_vert", AttrDomain::Point);
683 SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>(
684 ".select_poly", AttrDomain::Face);
685 {
686 IndexMaskMemory memory;
687 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
688 ".hide_vert", AttrDomain::Point, false);
689 array_utils::copy(
690 *attributes.lookup_or_default<bool>(".select_edge", AttrDomain::Point, false),
691 IndexMask::from_bools(hide_vert, memory).complement(hide_vert.index_range(), memory),
692 select_vert.span);
693 }
694 {
695 IndexMaskMemory memory;
696 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
697 ".hide_poly", AttrDomain::Face, false);
698 array_utils::copy(
699 *attributes.lookup_or_default<bool>(".select_edge", AttrDomain::Face, false),
700 IndexMask::from_bools(hide_poly, memory).complement(hide_poly.index_range(), memory),
701 select_poly.span);
702 }
703 select_vert.finish();
704 select_poly.finish();
705}
706
707} // namespace blender::bke
708
711/* -------------------------------------------------------------------- */
715void BKE_mesh_calc_relative_deform(const int *face_offsets,
716 const int faces_num,
717 const int *corner_verts,
718 const int totvert,
719
720 const float (*vert_cos_src)[3],
721 const float (*vert_cos_dst)[3],
722
723 const float (*vert_cos_org)[3],
724 float (*vert_cos_new)[3])
725{
726 const blender::OffsetIndices<int> faces({face_offsets, faces_num + 1});
727
728 int *vert_accum = (int *)MEM_calloc_arrayN(size_t(totvert), sizeof(*vert_accum), __func__);
729
730 memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * size_t(totvert));
731
732 for (const int i : faces.index_range()) {
733 const blender::IndexRange face = faces[i];
734 const int *face_verts = &corner_verts[face.start()];
735
736 for (int j = 0; j < face.size(); j++) {
737 const int v_prev = face_verts[(face.size() + (j - 1)) % face.size()];
738 const int v_curr = face_verts[j];
739 const int v_next = face_verts[(j + 1) % face.size()];
740
741 float tvec[3];
742
744 vert_cos_dst[v_curr],
745 vert_cos_org[v_prev],
746 vert_cos_org[v_curr],
747 vert_cos_org[v_next],
748 vert_cos_src[v_prev],
749 vert_cos_src[v_curr],
750 vert_cos_src[v_next]);
751
752 add_v3_v3(vert_cos_new[v_curr], tvec);
753 vert_accum[v_curr] += 1;
754 }
755 }
756
757 for (int i = 0; i < totvert; i++) {
758 if (vert_accum[i]) {
759 mul_v3_fl(vert_cos_new[i], 1.0f / float(vert_accum[i]));
760 }
761 else {
762 copy_v3_v3(vert_cos_new[i], vert_cos_org[i]);
763 }
764 }
765
766 MEM_freeN(vert_accum);
767}
768
sqrt(x)+1/max(0
float area_poly_v3(const float verts[][3], unsigned int nr)
Definition math_geom.cc:131
void transform_point_by_tri_v3(float pt_tar[3], float const pt_src[3], const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
float area_tri_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float normal[3])
Definition math_geom.cc:113
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:261
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:98
float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:249
void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
bool is_finite_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE void zero_v3(float r[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3])
unsigned int uint
#define UNUSED_FUNCTION(x)
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
const T * data() const
Definition BLI_array.hh:301
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
IndexRange index_range() const
#define fabsf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static char faces[256]
void BKE_mesh_calc_relative_deform(const int *face_offsets, const int faces_num, const int *corner_verts, const int totvert, const float(*vert_cos_src)[3], const float(*vert_cos_dst)[3], const float(*vert_cos_org)[3], float(*vert_cos_new)[3])
bool BKE_mesh_center_of_surface(const Mesh *mesh, float r_cent[3])
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
void BKE_mesh_calc_volume(const float(*vert_positions)[3], const int mverts_num, const blender::int3 *corner_tris, const int corner_tris_num, const int *corner_verts, float *r_volume, float r_center[3])
static float UNUSED_FUNCTION mesh_calc_face_volume_centroid(const int *face_verts, const int face_size, const float(*positions)[3], float r_cent[3])
float BKE_mesh_calc_area(const Mesh *mesh)
static bool mesh_calc_center_centroid_ex(const float(*positions)[3], int, const blender::int3 *corner_tris, int corner_tris_num, const int *corner_verts, float r_center[3])
bool BKE_mesh_center_median(const Mesh *mesh, float r_cent[3])
bool BKE_mesh_center_median_from_faces(const Mesh *mesh, float r_cent[3])
bool BKE_mesh_center_of_volume(const Mesh *mesh, float r_cent[3])
void face_angles_calc(Span< float3 > vert_positions, Span< int > face_verts, MutableSpan< float > angles)
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
static float3 face_center_calc_ngon(const Span< float3 > vert_positions, const Span< int > face_verts)
float face_area_calc(Span< float3 > vert_positions, Span< int > face_verts)
static float face_area_centroid_calc(const Span< float3 > positions, const Span< int > face_verts, float r_cent[3])
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
static float mesh_calc_face_volume_centroid_with_reference_center(const Span< float3 > positions, const Span< int > face_verts, const float3 &reference_center, float r_cent[3])
void mesh_select_vert_flush(Mesh &mesh)
void mesh_face_hide_from_vert(OffsetIndices< int > faces, Span< int > corner_verts, Span< bool > hide_vert, MutableSpan< bool > hide_poly)
void mesh_hide_vert_flush(Mesh &mesh)
void mesh_hide_face_flush(Mesh &mesh)
void mesh_select_edge_flush(Mesh &mesh)
void mesh_edge_hide_from_vert(Span< int2 > edges, Span< bool > hide_vert, MutableSpan< bool > hide_edge)
void mesh_select_face_flush(Mesh &mesh)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
float(* disps)[3]