Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_remesh_voxel.cc
| Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | static Mesh *remesh_quadriflow(const Mesh *input_mesh, | ||||
| int seed, | int seed, | ||||
| bool preserve_sharp, | bool preserve_sharp, | ||||
| bool preserve_boundary, | bool preserve_boundary, | ||||
| bool adaptive_scale, | bool adaptive_scale, | ||||
| void (*update_cb)(void *, float progress, int *cancel), | void (*update_cb)(void *, float progress, int *cancel), | ||||
| void *update_cb_data) | void *update_cb_data) | ||||
| { | { | ||||
| const Span<float3> input_positions = input_mesh->vert_positions(); | const Span<float3> input_positions = input_mesh->vert_positions(); | ||||
| const Span<MLoop> input_loops = input_mesh->loops(); | const Span<int> src_corner_verts = input_mesh->corner_verts(); | ||||
| const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh); | const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh); | ||||
| /* Gather the required data for export to the internal quadriflow mesh format. */ | /* Gather the required data for export to the internal quadriflow mesh format. */ | ||||
| MVertTri *verttri = (MVertTri *)MEM_callocN( | MVertTri *verttri = (MVertTri *)MEM_callocN( | ||||
| sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh), "remesh_looptri"); | sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh), "remesh_looptri"); | ||||
| BKE_mesh_runtime_verttri_from_looptri( | BKE_mesh_runtime_verttri_from_looptri( | ||||
| verttri, input_loops.data(), looptri, BKE_mesh_runtime_looptri_len(input_mesh)); | verttri, src_corner_verts.data(), looptri, BKE_mesh_runtime_looptri_len(input_mesh)); | ||||
| const int totfaces = BKE_mesh_runtime_looptri_len(input_mesh); | const int totfaces = BKE_mesh_runtime_looptri_len(input_mesh); | ||||
| const int totverts = input_mesh->totvert; | const int totverts = input_mesh->totvert; | ||||
| Array<int> faces(totfaces * 3); | Array<int> faces(totfaces * 3); | ||||
| for (const int i : IndexRange(totfaces)) { | for (const int i : IndexRange(totfaces)) { | ||||
| MVertTri &vt = verttri[i]; | MVertTri &vt = verttri[i]; | ||||
| faces[i * 3] = vt.tri[0]; | faces[i * 3] = vt.tri[0]; | ||||
| Show All 35 Lines | if (qrd.out_totfaces == 0) { | ||||
| MEM_freeN(qrd.out_verts); | MEM_freeN(qrd.out_verts); | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| /* Construct the new output mesh */ | /* Construct the new output mesh */ | ||||
| Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, 0, qrd.out_totfaces * 4, qrd.out_totfaces); | Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, 0, qrd.out_totfaces * 4, qrd.out_totfaces); | ||||
| BKE_mesh_copy_parameters(mesh, input_mesh); | BKE_mesh_copy_parameters(mesh, input_mesh); | ||||
| MutableSpan<MPoly> polys = mesh->polys_for_write(); | MutableSpan<MPoly> polys = mesh->polys_for_write(); | ||||
| MutableSpan<MLoop> loops = mesh->loops_for_write(); | MutableSpan<int> corner_verts = mesh->corner_verts_for_write(); | ||||
| mesh->vert_positions_for_write().copy_from( | mesh->vert_positions_for_write().copy_from( | ||||
| Span(reinterpret_cast<float3 *>(qrd.out_verts), qrd.out_totverts)); | Span(reinterpret_cast<float3 *>(qrd.out_verts), qrd.out_totverts)); | ||||
| for (const int i : IndexRange(qrd.out_totfaces)) { | for (const int i : IndexRange(qrd.out_totfaces)) { | ||||
| MPoly &poly = polys[i]; | MPoly &poly = polys[i]; | ||||
| const int loopstart = i * 4; | const int loopstart = i * 4; | ||||
| poly.loopstart = loopstart; | poly.loopstart = loopstart; | ||||
| poly.totloop = 4; | poly.totloop = 4; | ||||
| loops[loopstart].v = qrd.out_faces[loopstart]; | corner_verts[loopstart] = qrd.out_faces[loopstart]; | ||||
| loops[loopstart + 1].v = qrd.out_faces[loopstart + 1]; | corner_verts[loopstart + 1] = qrd.out_faces[loopstart + 1]; | ||||
| loops[loopstart + 2].v = qrd.out_faces[loopstart + 2]; | corner_verts[loopstart + 2] = qrd.out_faces[loopstart + 2]; | ||||
| loops[loopstart + 3].v = qrd.out_faces[loopstart + 3]; | corner_verts[loopstart + 3] = qrd.out_faces[loopstart + 3]; | ||||
| } | } | ||||
| BKE_mesh_calc_edges(mesh, false, false); | BKE_mesh_calc_edges(mesh, false, false); | ||||
| MEM_freeN(qrd.out_faces); | MEM_freeN(qrd.out_faces); | ||||
| MEM_freeN(qrd.out_verts); | MEM_freeN(qrd.out_verts); | ||||
| return mesh; | return mesh; | ||||
| Show All 34 Lines | |||||
| #endif | #endif | ||||
| } | } | ||||
| #ifdef WITH_OPENVDB | #ifdef WITH_OPENVDB | ||||
| static openvdb::FloatGrid::Ptr remesh_voxel_level_set_create(const Mesh *mesh, | static openvdb::FloatGrid::Ptr remesh_voxel_level_set_create(const Mesh *mesh, | ||||
| const float voxel_size) | const float voxel_size) | ||||
| { | { | ||||
| const Span<float3> positions = mesh->vert_positions(); | const Span<float3> positions = mesh->vert_positions(); | ||||
| const Span<MLoop> loops = mesh->loops(); | const Span<int> corner_verts = mesh->corner_verts(); | ||||
| const Span<MLoopTri> looptris = mesh->looptris(); | const Span<MLoopTri> looptris = mesh->looptris(); | ||||
| std::vector<openvdb::Vec3s> points(mesh->totvert); | std::vector<openvdb::Vec3s> points(mesh->totvert); | ||||
| std::vector<openvdb::Vec3I> triangles(looptris.size()); | std::vector<openvdb::Vec3I> triangles(looptris.size()); | ||||
| for (const int i : IndexRange(mesh->totvert)) { | for (const int i : IndexRange(mesh->totvert)) { | ||||
| const float3 &co = positions[i]; | const float3 &co = positions[i]; | ||||
| points[i] = openvdb::Vec3s(co.x, co.y, co.z); | points[i] = openvdb::Vec3s(co.x, co.y, co.z); | ||||
| } | } | ||||
| for (const int i : IndexRange(looptris.size())) { | for (const int i : IndexRange(looptris.size())) { | ||||
| const MLoopTri &loop_tri = looptris[i]; | const MLoopTri &loop_tri = looptris[i]; | ||||
| triangles[i] = openvdb::Vec3I( | triangles[i] = openvdb::Vec3I(corner_verts[loop_tri.tri[0]], | ||||
| loops[loop_tri.tri[0]].v, loops[loop_tri.tri[1]].v, loops[loop_tri.tri[2]].v); | corner_verts[loop_tri.tri[1]], | ||||
| corner_verts[loop_tri.tri[2]]); | |||||
| } | } | ||||
| openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform( | openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform( | ||||
| voxel_size); | voxel_size); | ||||
| openvdb::FloatGrid::Ptr grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>( | openvdb::FloatGrid::Ptr grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>( | ||||
| *transform, points, triangles, 1.0f); | *transform, points, triangles, 1.0f); | ||||
| return grid; | return grid; | ||||
| Show All 9 Lines | static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set_grid, | ||||
| std::vector<openvdb::Vec3I> tris; | std::vector<openvdb::Vec3I> tris; | ||||
| openvdb::tools::volumeToMesh<openvdb::FloatGrid>( | openvdb::tools::volumeToMesh<openvdb::FloatGrid>( | ||||
| *level_set_grid, vertices, tris, quads, isovalue, adaptivity, relax_disoriented_triangles); | *level_set_grid, vertices, tris, quads, isovalue, adaptivity, relax_disoriented_triangles); | ||||
| Mesh *mesh = BKE_mesh_new_nomain( | Mesh *mesh = BKE_mesh_new_nomain( | ||||
| vertices.size(), 0, 0, quads.size() * 4 + tris.size() * 3, quads.size() + tris.size()); | vertices.size(), 0, 0, quads.size() * 4 + tris.size() * 3, quads.size() + tris.size()); | ||||
| MutableSpan<float3> vert_positions = mesh->vert_positions_for_write(); | MutableSpan<float3> vert_positions = mesh->vert_positions_for_write(); | ||||
| MutableSpan<MPoly> mesh_polys = mesh->polys_for_write(); | MutableSpan<MPoly> mesh_polys = mesh->polys_for_write(); | ||||
| MutableSpan<MLoop> mesh_loops = mesh->loops_for_write(); | MutableSpan<int> mesh_corner_verts = mesh->corner_verts_for_write(); | ||||
| for (const int i : vert_positions.index_range()) { | for (const int i : vert_positions.index_range()) { | ||||
| vert_positions[i] = float3(vertices[i].x(), vertices[i].y(), vertices[i].z()); | vert_positions[i] = float3(vertices[i].x(), vertices[i].y(), vertices[i].z()); | ||||
| } | } | ||||
| for (const int i : IndexRange(quads.size())) { | for (const int i : IndexRange(quads.size())) { | ||||
| MPoly &poly = mesh_polys[i]; | MPoly &poly = mesh_polys[i]; | ||||
| const int loopstart = i * 4; | const int loopstart = i * 4; | ||||
| poly.loopstart = loopstart; | poly.loopstart = loopstart; | ||||
| poly.totloop = 4; | poly.totloop = 4; | ||||
| mesh_loops[loopstart].v = quads[i][0]; | mesh_corner_verts[loopstart] = quads[i][0]; | ||||
| mesh_loops[loopstart + 1].v = quads[i][3]; | mesh_corner_verts[loopstart + 1] = quads[i][3]; | ||||
| mesh_loops[loopstart + 2].v = quads[i][2]; | mesh_corner_verts[loopstart + 2] = quads[i][2]; | ||||
| mesh_loops[loopstart + 3].v = quads[i][1]; | mesh_corner_verts[loopstart + 3] = quads[i][1]; | ||||
| } | } | ||||
| const int triangle_loop_start = quads.size() * 4; | const int triangle_loop_start = quads.size() * 4; | ||||
| for (const int i : IndexRange(tris.size())) { | for (const int i : IndexRange(tris.size())) { | ||||
| MPoly &poly = mesh_polys[quads.size() + i]; | MPoly &poly = mesh_polys[quads.size() + i]; | ||||
| const int loopstart = triangle_loop_start + i * 3; | const int loopstart = triangle_loop_start + i * 3; | ||||
| poly.loopstart = loopstart; | poly.loopstart = loopstart; | ||||
| poly.totloop = 3; | poly.totloop = 3; | ||||
| mesh_loops[loopstart].v = tris[i][2]; | mesh_corner_verts[loopstart] = tris[i][2]; | ||||
| mesh_loops[loopstart + 1].v = tris[i][1]; | mesh_corner_verts[loopstart + 1] = tris[i][1]; | ||||
| mesh_loops[loopstart + 2].v = tris[i][0]; | mesh_corner_verts[loopstart + 2] = tris[i][0]; | ||||
| } | } | ||||
| BKE_mesh_calc_edges(mesh, false, false); | BKE_mesh_calc_edges(mesh, false, false); | ||||
| return mesh; | return mesh; | ||||
| } | } | ||||
| #endif | #endif | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | |||||
| void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) | void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) | ||||
| { | { | ||||
| using namespace blender; | using namespace blender; | ||||
| using namespace blender::bke; | using namespace blender::bke; | ||||
| const AttributeAccessor src_attributes = source->attributes(); | const AttributeAccessor src_attributes = source->attributes(); | ||||
| MutableAttributeAccessor dst_attributes = target->attributes_for_write(); | MutableAttributeAccessor dst_attributes = target->attributes_for_write(); | ||||
| const Span<float3> target_positions = target->vert_positions(); | const Span<float3> target_positions = target->vert_positions(); | ||||
| const Span<MPoly> target_polys = target->polys(); | const Span<MPoly> target_polys = target->polys(); | ||||
| const Span<MLoop> target_loops = target->loops(); | const Span<int> target_corner_verts = target->corner_verts(); | ||||
| const VArray<int> src_face_sets = src_attributes.lookup<int>(".sculpt_face_set", | const VArray<int> src_face_sets = src_attributes.lookup<int>(".sculpt_face_set", | ||||
| ATTR_DOMAIN_FACE); | ATTR_DOMAIN_FACE); | ||||
| if (!src_face_sets) { | if (!src_face_sets) { | ||||
| return; | return; | ||||
| } | } | ||||
| SpanAttributeWriter<int> dst_face_sets = dst_attributes.lookup_or_add_for_write_only_span<int>( | SpanAttributeWriter<int> dst_face_sets = dst_attributes.lookup_or_add_for_write_only_span<int>( | ||||
| ".sculpt_face_set", ATTR_DOMAIN_FACE); | ".sculpt_face_set", ATTR_DOMAIN_FACE); | ||||
| Show All 11 Lines | void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) | ||||
| blender::threading::parallel_for(IndexRange(target->totpoly), 2048, [&](const IndexRange range) { | blender::threading::parallel_for(IndexRange(target->totpoly), 2048, [&](const IndexRange range) { | ||||
| for (const int i : range) { | for (const int i : range) { | ||||
| float from_co[3]; | float from_co[3]; | ||||
| BVHTreeNearest nearest; | BVHTreeNearest nearest; | ||||
| nearest.index = -1; | nearest.index = -1; | ||||
| nearest.dist_sq = FLT_MAX; | nearest.dist_sq = FLT_MAX; | ||||
| const MPoly *mpoly = &target_polys[i]; | const MPoly *mpoly = &target_polys[i]; | ||||
| BKE_mesh_calc_poly_center(mpoly, | BKE_mesh_calc_poly_center(mpoly, | ||||
| &target_loops[mpoly->loopstart], | &target_corner_verts[mpoly->loopstart], | ||||
| reinterpret_cast<const float(*)[3]>(target_positions.data()), | reinterpret_cast<const float(*)[3]>(target_positions.data()), | ||||
| from_co); | from_co); | ||||
| BLI_bvhtree_find_nearest( | BLI_bvhtree_find_nearest( | ||||
| bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); | bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); | ||||
| if (nearest.index != -1) { | if (nearest.index != -1) { | ||||
| dst[i] = src[looptri[nearest.index].poly]; | dst[i] = src[looptri[nearest.index].poly]; | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (domain == ATTR_DOMAIN_POINT) { | ||||
| }); | }); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Lazily init vertex -> loop maps. */ | /* Lazily init vertex -> loop maps. */ | ||||
| if (!source_lmap) { | if (!source_lmap) { | ||||
| BKE_mesh_vert_loop_map_create(&source_lmap, | BKE_mesh_vert_loop_map_create(&source_lmap, | ||||
| &source_lmap_mem, | &source_lmap_mem, | ||||
| source->polys().data(), | source->polys().data(), | ||||
| source->loops().data(), | source->corner_verts().data(), | ||||
| source->totvert, | source->totvert, | ||||
| source->totpoly, | source->totpoly, | ||||
| source->totloop); | source->totloop); | ||||
| BKE_mesh_vert_loop_map_create(&target_lmap, | BKE_mesh_vert_loop_map_create(&target_lmap, | ||||
| &target_lmap_mem, | &target_lmap_mem, | ||||
| target->polys().data(), | target->polys().data(), | ||||
| target->loops().data(), | target->corner_verts().data(), | ||||
| target->totvert, | target->totvert, | ||||
| target->totpoly, | target->totpoly, | ||||
| target->totloop); | target->totloop); | ||||
| } | } | ||||
| blender::threading::parallel_for( | blender::threading::parallel_for( | ||||
| IndexRange(target->totvert), 2048, [&](const IndexRange range) { | IndexRange(target->totvert), 2048, [&](const IndexRange range) { | ||||
| for (const int i : range) { | for (const int i : range) { | ||||
| ▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines | |||||