Blender V4.5
mesh_remesh_voxel.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cctype>
10#include <cfloat>
11#include <cmath>
12#include <cstdlib>
13#include <cstring>
14#include <ctime>
15
16#include "BLI_array.hh"
17#include "BLI_array_utils.hh"
19#include "BLI_index_range.hh"
20#include "BLI_math_vector.h"
21#include "BLI_span.hh"
22#include "BLI_task.hh"
23
24#include "BKE_attribute.hh"
25#include "BKE_attribute_math.hh"
26#include "BKE_bvhutils.hh"
27#include "BKE_deform.hh"
28#include "BKE_mesh.hh"
29#include "BKE_mesh_remesh_voxel.hh" /* own include */
30#include "BKE_mesh_sample.hh"
31#include "BKE_modifier.hh"
32#include "BKE_report.hh"
33
34#include "bmesh.hh"
35#include "bmesh_tools.hh"
36
37#ifdef WITH_OPENVDB
38# include <openvdb/openvdb.h>
39# include <openvdb/tools/MeshToVolume.h>
40# include <openvdb/tools/VolumeToMesh.h>
41#endif
42
43#ifdef WITH_QUADRIFLOW
44# include "quadriflow_capi.hpp"
45#endif
46
47using blender::Array;
48using blender::float3;
50using blender::int3;
52using blender::Span;
53
54#ifdef WITH_QUADRIFLOW
55static Mesh *remesh_quadriflow(const Mesh *input_mesh,
56 int target_faces,
57 int seed,
58 bool preserve_sharp,
59 bool preserve_boundary,
60 bool adaptive_scale,
61 void (*update_cb)(void *, float progress, int *cancel),
62 void *update_cb_data)
63{
64 using namespace blender;
65 using namespace blender::bke;
66 const Span<float3> input_positions = input_mesh->vert_positions();
67 const Span<int> input_corner_verts = input_mesh->corner_verts();
68 const Span<int3> corner_tris = input_mesh->corner_tris();
69
70 /* Gather the required data for export to the internal quadriflow mesh format. */
71 Array<int3> vert_tris(corner_tris.size());
72 mesh::vert_tris_from_corner_tris(input_corner_verts, corner_tris, vert_tris);
73
74 /* Fill out the required input data */
76
77 qrd.totfaces = corner_tris.size();
78 qrd.totverts = input_positions.size();
79 qrd.verts = input_positions.cast<float>().data();
80 qrd.faces = vert_tris.as_span().cast<int>().data();
81 qrd.target_faces = target_faces;
82
83 qrd.preserve_sharp = preserve_sharp;
84 qrd.preserve_boundary = preserve_boundary;
85 qrd.adaptive_scale = adaptive_scale;
86 qrd.minimum_cost_flow = false;
87 qrd.aggresive_sat = false;
88 qrd.rng_seed = seed;
89
90 qrd.out_faces = nullptr;
91
92 /* Run the remesher */
93 QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data);
94
95 if (qrd.out_faces == nullptr) {
96 /* The remeshing was canceled */
97 return nullptr;
98 }
99
100 if (qrd.out_totfaces == 0) {
101 /* Meshing failed */
102 MEM_freeN(qrd.out_faces);
103 MEM_freeN(qrd.out_verts);
104 return nullptr;
105 }
106
107 /* Construct the new output mesh */
109 BKE_mesh_copy_parameters(mesh, input_mesh);
110 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
111 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
112
114
115 mesh->vert_positions_for_write().copy_from(
116 Span(reinterpret_cast<float3 *>(qrd.out_verts), qrd.out_totverts));
117
118 for (const int i : IndexRange(qrd.out_totfaces)) {
119 const int loopstart = i * 4;
120 corner_verts[loopstart] = qrd.out_faces[loopstart];
121 corner_verts[loopstart + 1] = qrd.out_faces[loopstart + 1];
122 corner_verts[loopstart + 2] = qrd.out_faces[loopstart + 2];
123 corner_verts[loopstart + 3] = qrd.out_faces[loopstart + 3];
124 }
125
126 mesh_calc_edges(*mesh, false, false);
127
128 MEM_freeN(qrd.out_faces);
129 MEM_freeN(qrd.out_verts);
130
131 return mesh;
132}
133#endif
134
136 int target_faces,
137 int seed,
138 bool preserve_sharp,
139 bool preserve_boundary,
140 bool adaptive_scale,
141 void (*update_cb)(void *, float progress, int *cancel),
142 void *update_cb_data)
143{
144#ifdef WITH_QUADRIFLOW
145 if (target_faces <= 0) {
146 target_faces = -1;
147 }
148 return remesh_quadriflow(mesh,
149 target_faces,
150 seed,
151 preserve_sharp,
152 preserve_boundary,
153 adaptive_scale,
154 update_cb,
155 update_cb_data);
156#else
158 target_faces,
159 seed,
160 preserve_sharp,
161 preserve_boundary,
162 adaptive_scale,
163 update_cb,
164 update_cb_data);
165 return nullptr;
166#endif
167}
168
169#ifdef WITH_OPENVDB
170static openvdb::FloatGrid::Ptr remesh_voxel_level_set_create(
171 const Mesh *mesh, openvdb::math::Transform::Ptr transform)
172{
173 const Span<float3> positions = mesh->vert_positions();
174 const Span<int> corner_verts = mesh->corner_verts();
175 const Span<int3> corner_tris = mesh->corner_tris();
176
177 std::vector<openvdb::Vec3s> points(mesh->verts_num);
178 std::vector<openvdb::Vec3I> triangles(corner_tris.size());
179
180 for (const int i : IndexRange(mesh->verts_num)) {
181 const float3 &co = positions[i];
182 points[i] = openvdb::Vec3s(co.x, co.y, co.z);
183 }
184
185 for (const int i : IndexRange(corner_tris.size())) {
186 const int3 &tri = corner_tris[i];
187 triangles[i] = openvdb::Vec3I(
188 corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]);
189 }
190
191 openvdb::FloatGrid::Ptr grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>(
192 *transform, points, triangles, 1.0f);
193
194 return grid;
195}
196
197static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set_grid,
198 const float isovalue,
199 const float adaptivity,
200 const bool relax_disoriented_triangles)
201{
202 using namespace blender;
203 using namespace blender::bke;
204 std::vector<openvdb::Vec3s> vertices;
205 std::vector<openvdb::Vec4I> quads;
206 std::vector<openvdb::Vec3I> tris;
207 openvdb::tools::volumeToMesh<openvdb::FloatGrid>(
208 *level_set_grid, vertices, tris, quads, isovalue, adaptivity, relax_disoriented_triangles);
209
211 vertices.size(), 0, quads.size() + tris.size(), quads.size() * 4 + tris.size() * 3);
212 MutableSpan<float3> vert_positions = mesh->vert_positions_for_write();
213 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
214 MutableSpan<int> mesh_corner_verts = mesh->corner_verts_for_write();
215
216 const int triangle_loop_start = quads.size() * 4;
217 if (!face_offsets.is_empty()) {
218 blender::offset_indices::fill_constant_group_size(4, 0, face_offsets.take_front(quads.size()));
220 3, triangle_loop_start, face_offsets.drop_front(quads.size()));
221 }
222
223 for (const int i : vert_positions.index_range()) {
224 vert_positions[i] = float3(vertices[i].x(), vertices[i].y(), vertices[i].z());
225 }
226
227 for (const int i : IndexRange(quads.size())) {
228 const int loopstart = i * 4;
229 mesh_corner_verts[loopstart] = quads[i][0];
230 mesh_corner_verts[loopstart + 1] = quads[i][3];
231 mesh_corner_verts[loopstart + 2] = quads[i][2];
232 mesh_corner_verts[loopstart + 3] = quads[i][1];
233 }
234
235 for (const int i : IndexRange(tris.size())) {
236 const int loopstart = triangle_loop_start + i * 3;
237 mesh_corner_verts[loopstart] = tris[i][2];
238 mesh_corner_verts[loopstart + 1] = tris[i][1];
239 mesh_corner_verts[loopstart + 2] = tris[i][0];
240 }
241
242 mesh_calc_edges(*mesh, false, false);
243
244 return mesh;
245}
246#endif
247
249 const float voxel_size,
250 const float adaptivity,
251 const float isovalue,
252 const Object *object,
253 ModifierData *modifier_data)
254{
255#ifdef WITH_OPENVDB
256 openvdb::math::Transform::Ptr transform;
257 try {
258 transform = openvdb::math::Transform::createLinearTransform(voxel_size);
259 }
260 catch (const openvdb::ArithmeticError & /*e*/) {
261 /* OpenVDB internally has a limit of 3e-15 for the matrix's determinant and throws
262 * ArithmeticError if the provided value is too low.
263 * See #136637 for more details. */
265 object, modifier_data, "Voxel size of %f too small to be solved", voxel_size);
266 return nullptr;
267 }
268 openvdb::FloatGrid::Ptr level_set = remesh_voxel_level_set_create(mesh, transform);
269 Mesh *result = remesh_voxel_volume_to_mesh(level_set, isovalue, adaptivity, false);
271 return result;
272#else
273 UNUSED_VARS(mesh, voxel_size, adaptivity, isovalue, object, modifier_data);
274 return nullptr;
275#endif
276}
277
279 const float voxel_size,
280 const float adaptivity,
281 const float isovalue,
283{
284#ifdef WITH_OPENVDB
285 openvdb::math::Transform::Ptr transform;
286 try {
287 transform = openvdb::math::Transform::createLinearTransform(voxel_size);
288 }
289 catch (const openvdb::ArithmeticError & /*e*/) {
290 /* OpenVDB internally has a limit of 3e-15 for the matrix's determinant and throws
291 * ArithmeticError if the provided value is too low.
292 * See #136637 for more details. */
293 BKE_reportf(reports, RPT_ERROR, "Voxel size of %f too small to be solved", voxel_size);
294 return nullptr;
295 }
296 openvdb::FloatGrid::Ptr level_set = remesh_voxel_level_set_create(mesh, transform);
297 Mesh *result = remesh_voxel_volume_to_mesh(level_set, isovalue, adaptivity, false);
299 return result;
300#else
301 UNUSED_VARS(mesh, voxel_size, adaptivity, isovalue, reports);
302 return nullptr;
303#endif
304}
305
306namespace blender::bke {
307
308static void calc_edge_centers(const Span<float3> positions,
309 const Span<int2> edges,
310 MutableSpan<float3> edge_centers)
311{
312 for (const int i : edges.index_range()) {
313 edge_centers[i] = math::midpoint(positions[edges[i][0]], positions[edges[i][1]]);
314 }
315}
316
317static void calc_face_centers(const Span<float3> positions,
319 const Span<int> corner_verts,
320 MutableSpan<float3> face_centers)
321{
322 for (const int i : faces.index_range()) {
323 face_centers[i] = mesh::face_center_calc(positions, corner_verts.slice(faces[i]));
324 }
325}
326
327static void find_nearest_tris(const Span<float3> positions,
328 BVHTreeFromMesh &bvhtree,
329 MutableSpan<int> tris)
330{
331 for (const int i : positions.index_range()) {
332 BVHTreeNearest nearest;
333 nearest.index = -1;
334 nearest.dist_sq = FLT_MAX;
336 bvhtree.tree, positions[i], &nearest, bvhtree.nearest_callback, &bvhtree);
337 tris[i] = nearest.index;
338 }
339}
340
341static void find_nearest_tris_parallel(const Span<float3> positions,
342 BVHTreeFromMesh &bvhtree,
343 MutableSpan<int> tris)
344{
345 threading::parallel_for(tris.index_range(), 512, [&](const IndexRange range) {
346 find_nearest_tris(positions.slice(range), bvhtree, tris.slice(range));
347 });
348}
349
350static void find_nearest_verts(const Span<float3> positions,
351 const Span<int> corner_verts,
352 const Span<int3> src_corner_tris,
353 const Span<float3> dst_positions,
354 const Span<int> nearest_vert_tris,
355 MutableSpan<int> nearest_verts)
356{
357 threading::parallel_for(dst_positions.index_range(), 512, [&](const IndexRange range) {
358 for (const int dst_vert : range) {
359 const float3 &dst_position = dst_positions[dst_vert];
360 const int3 &src_tri = src_corner_tris[nearest_vert_tris[dst_vert]];
361
362 std::array<float, 3> distances;
363 for (const int i : IndexRange(3)) {
364 const int src_vert = corner_verts[src_tri[i]];
365 distances[i] = math::distance_squared(positions[src_vert], dst_position);
366 }
367
368 const int min = std::min_element(distances.begin(), distances.end()) - distances.begin();
369 nearest_verts[dst_vert] = corner_verts[src_tri[min]];
370 }
371 });
372}
373
374static void find_nearest_faces(const Span<int> src_tri_faces,
375 const Span<float3> dst_positions,
376 const OffsetIndices<int> dst_faces,
377 const Span<int> dst_corner_verts,
378 BVHTreeFromMesh &bvhtree,
379 MutableSpan<int> nearest_faces)
380{
381 struct TLS {
382 Vector<float3> face_centers;
383 Vector<int> tri_indices;
384 };
386 threading::parallel_for(dst_faces.index_range(), 512, [&](const IndexRange range) {
387 threading::isolate_task([&] {
388 TLS &tls = all_tls.local();
389 Vector<float3> &face_centers = tls.face_centers;
390 face_centers.reinitialize(range.size());
391 calc_face_centers(dst_positions, dst_faces.slice(range), dst_corner_verts, face_centers);
392
393 Vector<int> &tri_indices = tls.tri_indices;
394 tri_indices.reinitialize(range.size());
395 find_nearest_tris(face_centers, bvhtree, tri_indices);
396
397 array_utils::gather(src_tri_faces, tri_indices.as_span(), nearest_faces.slice(range));
398 });
399 });
400}
401
402static void find_nearest_corners(const Span<float3> src_positions,
403 const OffsetIndices<int> src_faces,
404 const Span<int> src_corner_verts,
405 const Span<int> src_tri_faces,
406 const Span<float3> dst_positions,
407 const Span<int> dst_corner_verts,
408 const Span<int> nearest_vert_tris,
409 MutableSpan<int> nearest_corners)
410{
411 threading::parallel_for(nearest_corners.index_range(), 512, [&](const IndexRange range) {
412 Vector<float, 64> distances;
413 for (const int dst_corner : range) {
414 const int dst_vert = dst_corner_verts[dst_corner];
415 const float3 &dst_position = dst_positions[dst_vert];
416
417 const int src_tri = nearest_vert_tris[dst_vert];
418 const IndexRange src_face = src_faces[src_tri_faces[src_tri]];
419 const Span<int> src_face_verts = src_corner_verts.slice(src_face);
420
421 /* Find the corner in the face that's closest in the closest face. */
422 distances.reinitialize(src_face_verts.size());
423 for (const int i : src_face_verts.index_range()) {
424 const int src_vert = src_face_verts[i];
425 distances[i] = math::distance_squared(src_positions[src_vert], dst_position);
426 }
427
428 const int min = std::min_element(distances.begin(), distances.end()) - distances.begin();
429 nearest_corners[dst_corner] = src_face[min];
430 }
431 });
432}
433
434static void find_nearest_edges(const Span<float3> src_positions,
435 const Span<int2> src_edges,
436 const OffsetIndices<int> src_faces,
437 const Span<int> src_corner_edges,
438 const Span<int> src_tri_faces,
439 const Span<float3> dst_positions,
440 const Span<int2> dst_edges,
441 BVHTreeFromMesh &bvhtree,
442 MutableSpan<int> nearest_edges)
443{
444 struct TLS {
445 Vector<float3> edge_centers;
446 Vector<int> tri_indices;
447 Vector<int> face_indices;
448 Vector<float> distances;
449 };
451 threading::parallel_for(nearest_edges.index_range(), 512, [&](const IndexRange range) {
452 threading::isolate_task([&] {
453 TLS &tls = all_tls.local();
454 Vector<float3> &edge_centers = tls.edge_centers;
455 edge_centers.reinitialize(range.size());
456 calc_edge_centers(dst_positions, dst_edges.slice(range), edge_centers);
457
458 Vector<int> &tri_indices = tls.tri_indices;
459 tri_indices.reinitialize(range.size());
460 find_nearest_tris_parallel(edge_centers, bvhtree, tri_indices);
461
462 Vector<int> &face_indices = tls.face_indices;
463 face_indices.reinitialize(range.size());
464 array_utils::gather(src_tri_faces, tri_indices.as_span(), face_indices.as_mutable_span());
465
466 /* Find the source edge that's closest to the destination edge in the nearest face. Search
467 * through the whole face instead of just the triangle because the triangle has edges that
468 * might not be actual mesh edges. */
469 Vector<float, 64> distances;
470 for (const int i : range.index_range()) {
471 const int dst_edge = range[i];
472 const float3 &dst_position = edge_centers[i];
473
474 const int src_face = face_indices[i];
475 const Span<int> src_face_edges = src_corner_edges.slice(src_faces[src_face]);
476
477 distances.reinitialize(src_face_edges.size());
478 for (const int i : src_face_edges.index_range()) {
479 const int2 src_edge = src_edges[src_face_edges[i]];
480 const float3 src_center = math::midpoint(src_positions[src_edge[0]],
481 src_positions[src_edge[1]]);
482 distances[i] = math::distance_squared(src_center, dst_position);
483 }
484
485 const int min = std::min_element(distances.begin(), distances.end()) - distances.begin();
486 nearest_edges[dst_edge] = src_face_edges[min];
487 }
488 });
489 });
490}
491
492static void gather_attributes(const Span<StringRef> ids,
493 const AttributeAccessor src_attributes,
494 const AttrDomain domain,
495 const Span<int> index_map,
496 MutableAttributeAccessor dst_attributes)
497{
498 for (const StringRef id : ids) {
499 const GVArraySpan src = *src_attributes.lookup(id, domain);
501 GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(id, domain, type);
502 attribute_math::gather(src, index_map, dst.span);
503 dst.finish();
504 }
505}
506
508{
509 /* Gather attributes to transfer for each domain. This makes it possible to skip
510 * building index maps and even the main BVH tree if there are no attributes. */
511 const AttributeAccessor src_attributes = src.attributes();
512 Vector<StringRef> point_ids;
513 Vector<StringRef> edge_ids;
514 Vector<StringRef> face_ids;
515 Vector<StringRef> corner_ids;
516 src_attributes.foreach_attribute([&](const AttributeIter &iter) {
517 if (ELEM(iter.name, "position", ".edge_verts", ".corner_vert", ".corner_edge")) {
518 return;
519 }
520 switch (iter.domain) {
522 point_ids.append(iter.name);
523 break;
524 case AttrDomain::Edge:
525 edge_ids.append(iter.name);
526 break;
527 case AttrDomain::Face:
528 face_ids.append(iter.name);
529 break;
531 corner_ids.append(iter.name);
532 break;
533 default:
535 break;
536 }
537 });
538
539 if (point_ids.is_empty() && edge_ids.is_empty() && face_ids.is_empty() && corner_ids.is_empty())
540 {
541 return;
542 }
543
544 const Span<float3> src_positions = src.vert_positions();
545 const OffsetIndices src_faces = src.faces();
546 const Span<int> src_corner_verts = src.corner_verts();
547 const Span<int3> src_corner_tris = src.corner_tris();
548
549 /* The main idea in the following code is to trade some complexity in sampling for the benefit of
550 * only using and building a single BVH tree. Since sculpt mode doesn't generally deal with loose
551 * vertices and edges, we use the standard "triangles" BVH which won't contain them. Also, only
552 * relying on a single BVH should reduce memory usage, and work better if the BVH and #pbvh::Tree
553 * are ever merged.
554 *
555 * One key decision is separating building transfer index maps from actually transferring any
556 * attribute data. This is important to keep attribute storage independent from the specifics of
557 * the decisions made here, which mainly results in easier refactoring, more generic code, and
558 * possibly improved performance from lower cache usage in the "complex" sampling part of the
559 * algorithm and the copying itself. */
560 BVHTreeFromMesh bvhtree = src.bvh_corner_tris();
561
562 const Span<float3> dst_positions = dst.vert_positions();
563 const OffsetIndices dst_faces = dst.faces();
564 const Span<int> dst_corner_verts = dst.corner_verts();
565
566 MutableAttributeAccessor dst_attributes = dst.attributes_for_write();
567
568 if (!point_ids.is_empty() || !corner_ids.is_empty()) {
569 Array<int> vert_nearest_tris(dst_positions.size());
570 find_nearest_tris_parallel(dst_positions, bvhtree, vert_nearest_tris);
571
572 if (!point_ids.is_empty()) {
573 Array<int> map(dst.verts_num);
575 src_positions, src_corner_verts, src_corner_tris, dst_positions, vert_nearest_tris, map);
576 /* Copy vertex group names (otherwise `MeshVertexGroupsAttributeProvider` wont find them -
577 * and these would show up as regular attributes afterwards). "vertex_group_active_index" is
578 * taken care of via #BKE_mesh_copy_parameters(). */
580 gather_attributes(point_ids, src_attributes, AttrDomain::Point, map, dst_attributes);
581 }
582
583 if (!corner_ids.is_empty()) {
584 const Span<int> src_tri_faces = src.corner_tri_faces();
585 Array<int> map(dst.corners_num);
586 find_nearest_corners(src_positions,
587 src_faces,
588 src_corner_verts,
589 src_tri_faces,
590 dst_positions,
591 dst_corner_verts,
592 vert_nearest_tris,
593 map);
594 gather_attributes(corner_ids, src_attributes, AttrDomain::Corner, map, dst_attributes);
595 }
596 }
597
598 if (!edge_ids.is_empty()) {
599 const Span<int2> src_edges = src.edges();
600 const Span<int> src_corner_edges = src.corner_edges();
601 const Span<int> src_tri_faces = src.corner_tri_faces();
602 const Span<int2> dst_edges = dst.edges();
603 Array<int> map(dst.edges_num);
604 find_nearest_edges(src_positions,
605 src_edges,
606 src_faces,
607 src_corner_edges,
608 src_tri_faces,
609 dst_positions,
610 dst_edges,
611 bvhtree,
612 map);
613 gather_attributes(edge_ids, src_attributes, AttrDomain::Edge, map, dst_attributes);
614 }
615
616 if (!face_ids.is_empty()) {
617 const Span<int> src_tri_faces = src.corner_tri_faces();
618 Array<int> map(dst.faces_num);
619 find_nearest_faces(src_tri_faces, dst_positions, dst_faces, dst_corner_verts, bvhtree, map);
620 gather_attributes(face_ids, src_attributes, AttrDomain::Face, map, dst_attributes);
621 }
622
623 if (src.active_color_attribute) {
625 }
626 if (src.default_color_attribute) {
628 }
629}
630
631} // namespace blender::bke
632
634{
636
637 BMeshCreateParams bmesh_create_params{};
638 bmesh_create_params.use_toolflags = true;
639 BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
640
641 BMeshFromMeshParams bmesh_from_mesh_params{};
642 bmesh_from_mesh_params.calc_face_normal = true;
643 bmesh_from_mesh_params.calc_vert_normal = true;
644 BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
645
646 BMVert *v;
647 BMEdge *ed, *ed_next;
648 BMFace *f, *f_next;
649 BMIter iter_a, iter_b;
650
651 /* Merge 3 edge poles vertices that exist in the same face */
653 BM_ITER_MESH_MUTABLE (f, f_next, &iter_a, bm, BM_FACES_OF_MESH) {
654 BMVert *v1, *v2;
655 v1 = nullptr;
656 v2 = nullptr;
657 BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
658 if (BM_vert_edge_count(v) == 3) {
659 if (v1) {
660 v2 = v;
661 }
662 else {
663 v1 = v;
664 }
665 }
666 }
667 if (v1 && v2 && (v1 != v2) && !BM_edge_exists(v1, v2)) {
668 BM_face_kill(bm, f);
669 BMEdge *e = BM_edge_create(bm, v1, v2, nullptr, BM_CREATE_NOP);
671 }
672 }
673
674 BM_ITER_MESH_MUTABLE (ed, ed_next, &iter_a, bm, BM_EDGES_OF_MESH) {
676 float co[3];
677 mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
678 BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true);
679 copy_v3_v3(vc->co, co);
680 }
681 }
682
683 /* Delete faces with a 3 edge pole in all their vertices */
685 BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
686 bool dissolve = true;
687 BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
688 if (BM_vert_edge_count(v) != 3) {
689 dissolve = false;
690 }
691 }
692 if (dissolve) {
693 BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
695 }
696 }
697 }
699
700 BM_ITER_MESH (ed, &iter_a, bm, BM_EDGES_OF_MESH) {
701 if (BM_edge_face_count(ed) != 2) {
703 }
704 }
705 BM_mesh_edgenet(bm, false, true);
706
707 /* Smooth the result */
708 for (int i = 0; i < 4; i++) {
709 BM_ITER_MESH (v, &iter_a, bm, BM_VERTS_OF_MESH) {
710 float co[3];
711 zero_v3(co);
712 BM_ITER_ELEM (ed, &iter_b, v, BM_EDGES_OF_VERT) {
713 BMVert *vert = BM_edge_other_vert(ed, v);
714 add_v3_v3(co, vert->co);
715 }
716 mul_v3_fl(co, 1.0f / float(BM_vert_edge_count(v)));
717 mid_v3_v3v3(v->co, v->co, co);
718 }
719 }
720
722
727 "recalc_face_normals faces=%hf",
730
731 BMeshToMeshParams bmesh_to_mesh_params{};
732 bmesh_to_mesh_params.calc_object_remap = false;
733 Mesh *result = BKE_mesh_from_bmesh_nomain(bm, &bmesh_to_mesh_params, mesh);
734
736 return result;
737}
void BKE_id_attributes_default_color_set(struct ID *id, std::optional< blender::StringRef > name)
void BKE_id_attributes_active_color_set(struct ID *id, std::optional< blender::StringRef > name)
Definition attribute.cc:986
support for deformation groups and hooks.
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:71
Mesh * BKE_mesh_from_bmesh_nomain(BMesh *bm, const BMeshToMeshParams *params, const Mesh *me_settings)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS(...)
#define ELEM(...)
ReportList * reports
Definition WM_types.hh:1025
float progress
Definition WM_types.hh:1019
@ BM_ELEM_SELECT
@ BM_ELEM_TAG
void BM_face_kill(BMesh *bm, BMFace *f)
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_VERT
#define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype)
BMesh const char void * data
BMesh * bm
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BMALLOC_TEMPLATE_FROM_ME(...)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_normals_update(BMesh *bm)
BMVert * BM_edge_collapse(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
@ BMO_FLAG_RESPECT_HIDE
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
int BM_edge_face_count(const BMEdge *e)
int BM_vert_edge_count(const BMVert *v)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
static unsigned long seed
Definition btSoftBody.h:39
AttributeSet attributes
const CPPType & type() const
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:607
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void append(const T &value)
bool is_empty() const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
Mesh * BKE_mesh_remesh_voxel(const Mesh *mesh, const float voxel_size, const float adaptivity, const float isovalue, const Object *object, ModifierData *modifier_data)
Mesh * BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
Mesh * BKE_mesh_remesh_quadriflow(const Mesh *mesh, int target_faces, int seed, bool preserve_sharp, bool preserve_boundary, bool adaptive_scale, void(*update_cb)(void *, float progress, int *cancel), void *update_cb_data)
void gather(GSpan src, Span< int > map, GMutableSpan dst)
void vert_tris_from_corner_tris(Span< int > corner_verts, Span< int3 > corner_tris, MutableSpan< int3 > vert_tris)
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
static void find_nearest_tris_parallel(const Span< float3 > positions, BVHTreeFromMesh &bvhtree, MutableSpan< int > tris)
static void find_nearest_faces(const Span< int > src_tri_faces, const Span< float3 > dst_positions, const OffsetIndices< int > dst_faces, const Span< int > dst_corner_verts, BVHTreeFromMesh &bvhtree, MutableSpan< int > nearest_faces)
static void calc_edge_centers(const Span< float3 > positions, const Span< int2 > edges, MutableSpan< float3 > edge_centers)
void mesh_remesh_reproject_attributes(const Mesh &src, Mesh &dst)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
static void find_nearest_verts(const Span< float3 > positions, const Span< int > corner_verts, const Span< int3 > src_corner_tris, const Span< float3 > dst_positions, const Span< int > nearest_vert_tris, MutableSpan< int > nearest_verts)
void gather_attributes(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
static void find_nearest_edges(const Span< float3 > src_positions, const Span< int2 > src_edges, const OffsetIndices< int > src_faces, const Span< int > src_corner_edges, const Span< int > src_tri_faces, const Span< float3 > dst_positions, const Span< int2 > dst_edges, BVHTreeFromMesh &bvhtree, MutableSpan< int > nearest_edges)
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges)
static void find_nearest_corners(const Span< float3 > src_positions, const OffsetIndices< int > src_faces, const Span< int > src_corner_verts, const Span< int > src_tri_faces, const Span< float3 > dst_positions, const Span< int > dst_corner_verts, const Span< int > nearest_vert_tris, MutableSpan< int > nearest_corners)
static void calc_face_centers(const Span< float3 > positions, const OffsetIndices< int > faces, const Span< int > corner_verts, MutableSpan< float3 > face_centers)
static void find_nearest_tris(const Span< float3 > positions, BVHTreeFromMesh &bvhtree, MutableSpan< int > tris)
T midpoint(const T &a, const T &b)
void fill_constant_group_size(int size, int start_offset, MutableSpan< int > offsets)
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:93
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd, void(*update_cb)(void *, float progress, int *cancel), void *update_cb_data)
#define FLT_MAX
Definition stdcycles.h:14
float co[3]
int corners_num
int edges_num
char * default_color_attribute
ListBase vertex_group_names
int faces_num
int verts_num
char * active_color_attribute
BVHTree_NearestPointCallback nearest_callback
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
i
Definition text_draw.cc:230