/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2019 by Blender Foundation * All rights reserved. */ /** \file * \ingroup bke */ #include #include #include #include #include #include #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "BKE_bvhutils.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_remesh_voxel.h" /* own include */ #include "BKE_mesh_runtime.h" #include "bmesh_tools.h" #ifdef WITH_OPENVDB # include "openvdb_capi.h" #endif #ifdef WITH_QUADRIFLOW # include "quadriflow_capi.hpp" #endif #ifdef WITH_OPENVDB struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create( Mesh *mesh, struct OpenVDBTransform *transform) { BKE_mesh_runtime_looptri_recalc(mesh); const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh); MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(mesh), "remesh_looptri"); BKE_mesh_runtime_verttri_from_looptri( verttri, mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(mesh)); unsigned int totfaces = BKE_mesh_runtime_looptri_len(mesh); unsigned int totverts = mesh->totvert; float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts"); unsigned int *faces = (unsigned int *)MEM_malloc_arrayN( totfaces * 3, sizeof(unsigned int), "remesh_intput_faces"); for (unsigned int i = 0; i < totverts; i++) { MVert *mvert = &mesh->mvert[i]; verts[i * 3] = mvert->co[0]; verts[i * 3 + 1] = mvert->co[1]; verts[i * 3 + 2] = mvert->co[2]; } for (unsigned int i = 0; i < totfaces; i++) { MVertTri *vt = &verttri[i]; faces[i * 3] = vt->tri[0]; faces[i * 3 + 1] = vt->tri[1]; faces[i * 3 + 2] = vt->tri[2]; } struct OpenVDBLevelSet *level_set = OpenVDBLevelSet_create(false, NULL); OpenVDBLevelSet_mesh_to_level_set(level_set, verts, faces, totverts, totfaces, transform); MEM_freeN(verts); MEM_freeN(faces); MEM_freeN(verttri); return level_set; } Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *level_set, double isovalue, double adaptivity, bool relax_disoriented_triangles) { # ifdef WITH_OPENVDB struct OpenVDBVolumeToMeshData output_mesh; OpenVDBLevelSet_volume_to_mesh( level_set, &output_mesh, isovalue, adaptivity, relax_disoriented_triangles); # endif Mesh *mesh = BKE_mesh_new_nomain(output_mesh.totvertices, 0, 0, (output_mesh.totquads * 4) + (output_mesh.tottriangles * 3), output_mesh.totquads + output_mesh.tottriangles); for (int i = 0; i < output_mesh.totvertices; i++) { copy_v3_v3(mesh->mvert[i].co, &output_mesh.vertices[i * 3]); } MPoly *mp = mesh->mpoly; MLoop *ml = mesh->mloop; for (int i = 0; i < output_mesh.totquads; i++, mp++, ml += 4) { mp->loopstart = (int)(ml - mesh->mloop); mp->totloop = 4; ml[0].v = output_mesh.quads[i * 4 + 3]; ml[1].v = output_mesh.quads[i * 4 + 2]; ml[2].v = output_mesh.quads[i * 4 + 1]; ml[3].v = output_mesh.quads[i * 4]; } for (int i = 0; i < output_mesh.tottriangles; i++, mp++, ml += 3) { mp->loopstart = (int)(ml - mesh->mloop); mp->totloop = 3; ml[0].v = output_mesh.triangles[i * 3 + 2]; ml[1].v = output_mesh.triangles[i * 3 + 1]; ml[2].v = output_mesh.triangles[i * 3]; } BKE_mesh_calc_edges(mesh, false, false); BKE_mesh_calc_normals(mesh); MEM_freeN(output_mesh.quads); MEM_freeN(output_mesh.vertices); if (output_mesh.tottriangles > 0) { MEM_freeN(output_mesh.triangles); } return mesh; } #endif #ifdef WITH_QUADRIFLOW static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh, int target_faces, int seed, bool preserve_sharp, bool preserve_boundary, bool adaptive_scale, void *update_cb, void *update_cb_data) { /* Ensure that the triangulated mesh data is up to data */ BKE_mesh_runtime_looptri_recalc(input_mesh); const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh); /* Gather the required data for export to the internal quadiflow mesh format */ MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh), "remesh_looptri"); BKE_mesh_runtime_verttri_from_looptri( verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh)); unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh); unsigned int totverts = input_mesh->totvert; float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts"); unsigned int *faces = (unsigned int *)MEM_malloc_arrayN( totfaces * 3, sizeof(unsigned int), "remesh_intput_faces"); for (unsigned int i = 0; i < totverts; i++) { MVert *mvert = &input_mesh->mvert[i]; verts[i * 3] = mvert->co[0]; verts[i * 3 + 1] = mvert->co[1]; verts[i * 3 + 2] = mvert->co[2]; } for (unsigned int i = 0; i < totfaces; i++) { MVertTri *vt = &verttri[i]; faces[i * 3] = vt->tri[0]; faces[i * 3 + 1] = vt->tri[1]; faces[i * 3 + 2] = vt->tri[2]; } /* Fill out the required input data */ QuadriflowRemeshData qrd; qrd.totfaces = totfaces; qrd.totverts = totverts; qrd.verts = verts; qrd.faces = faces; qrd.target_faces = target_faces; qrd.preserve_sharp = preserve_sharp; qrd.preserve_boundary = preserve_boundary; qrd.adaptive_scale = adaptive_scale; qrd.minimum_cost_flow = 0; qrd.aggresive_sat = 0; qrd.rng_seed = seed; qrd.out_faces = NULL; /* Run the remesher */ QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data); MEM_freeN(verts); MEM_freeN(faces); MEM_freeN(verttri); if (qrd.out_faces == NULL) { /* The remeshing was canceled */ return NULL; } if (qrd.out_totfaces == 0) { /* Meshing failed */ MEM_freeN(qrd.out_faces); MEM_freeN(qrd.out_verts); return NULL; } /* Construct the new output mesh */ Mesh *mesh = BKE_mesh_new_nomain( qrd.out_totverts, 0, 0, (qrd.out_totfaces * 4), qrd.out_totfaces); for (int i = 0; i < qrd.out_totverts; i++) { copy_v3_v3(mesh->mvert[i].co, &qrd.out_verts[i * 3]); } MPoly *mp = mesh->mpoly; MLoop *ml = mesh->mloop; for (int i = 0; i < qrd.out_totfaces; i++, mp++, ml += 4) { mp->loopstart = (int)(ml - mesh->mloop); mp->totloop = 4; ml[0].v = qrd.out_faces[i * 4]; ml[1].v = qrd.out_faces[i * 4 + 1]; ml[2].v = qrd.out_faces[i * 4 + 2]; ml[3].v = qrd.out_faces[i * 4 + 3]; } BKE_mesh_calc_edges(mesh, false, false); BKE_mesh_calc_normals(mesh); MEM_freeN(qrd.out_faces); MEM_freeN(qrd.out_verts); return mesh; } #endif Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh, int target_faces, int seed, bool preserve_sharp, bool preserve_boundary, bool adaptive_scale, void *update_cb, void *update_cb_data) { Mesh *new_mesh = NULL; #ifdef WITH_QUADRIFLOW if (target_faces <= 0) { target_faces = -1; } new_mesh = BKE_mesh_remesh_quadriflow(mesh, target_faces, seed, preserve_sharp, preserve_boundary, adaptive_scale, update_cb, update_cb_data); #else UNUSED_VARS(mesh, target_faces, seed, preserve_sharp, preserve_boundary, adaptive_scale, update_cb, update_cb_data); #endif return new_mesh; } Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size, float adaptivity, float isovalue) { Mesh *new_mesh = NULL; #ifdef WITH_OPENVDB struct OpenVDBLevelSet *level_set; struct OpenVDBTransform *xform = OpenVDBTransform_create(); OpenVDBTransform_create_linear_transform(xform, (double)voxel_size); level_set = BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform); new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain( level_set, (double)isovalue, (double)adaptivity, false); OpenVDBLevelSet_free(level_set); OpenVDBTransform_free(xform); #else UNUSED_VARS(mesh, voxel_size, adaptivity, isovalue); #endif return new_mesh; } void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source) { BVHTreeFromMesh bvhtree = { .nearest_callback = NULL, }; BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2); MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT); float *target_mask; if (CustomData_has_layer(&target->vdata, CD_PAINT_MASK)) { target_mask = CustomData_get_layer(&target->vdata, CD_PAINT_MASK); } else { target_mask = CustomData_add_layer( &target->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, target->totvert); } float *source_mask; if (CustomData_has_layer(&source->vdata, CD_PAINT_MASK)) { source_mask = CustomData_get_layer(&source->vdata, CD_PAINT_MASK); } else { source_mask = CustomData_add_layer( &source->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, source->totvert); } for (int i = 0; i < target->totvert; i++) { float from_co[3]; BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = FLT_MAX; copy_v3_v3(from_co, target_verts[i].co); BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index != -1) { target_mask[i] = source_mask[nearest.index]; } } free_bvhtree_from_mesh(&bvhtree); } void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source) { BVHTreeFromMesh bvhtree = { .nearest_callback = NULL, }; const MPoly *target_polys = CustomData_get_layer(&target->pdata, CD_MPOLY); const MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT); const MLoop *target_loops = CustomData_get_layer(&target->ldata, CD_MLOOP); int *target_face_sets; if (CustomData_has_layer(&target->pdata, CD_SCULPT_FACE_SETS)) { target_face_sets = CustomData_get_layer(&target->pdata, CD_SCULPT_FACE_SETS); } else { target_face_sets = CustomData_add_layer( &target->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, target->totpoly); } int *source_face_sets; if (CustomData_has_layer(&source->pdata, CD_SCULPT_FACE_SETS)) { source_face_sets = CustomData_get_layer(&source->pdata, CD_SCULPT_FACE_SETS); } else { source_face_sets = CustomData_add_layer( &source->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, source->totpoly); } const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source); BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_LOOPTRI, 2); for (int i = 0; i < target->totpoly; i++) { float from_co[3]; BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = FLT_MAX; const MPoly *mpoly = &target_polys[i]; BKE_mesh_calc_poly_center(mpoly, &target_loops[mpoly->loopstart], target_verts, from_co); BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index != -1) { target_face_sets[i] = source_face_sets[looptri[nearest.index].poly]; } else { target_face_sets[i] = 1; } } free_bvhtree_from_mesh(&bvhtree); } struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh) { const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); BMesh *bm; bm = BM_mesh_create(&allocsize, &((struct BMeshCreateParams){ .use_toolflags = true, })); BM_mesh_bm_from_me(bm, mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, })); BMVert *v; BMEdge *ed, *ed_next; BMFace *f, *f_next; BMIter iter_a, iter_b; /* Merge 3 edge poles vertices that exist in the same face */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); BM_ITER_MESH_MUTABLE (f, f_next, &iter_a, bm, BM_FACES_OF_MESH) { BMVert *v1, *v2; v1 = NULL; v2 = NULL; BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { if (BM_vert_edge_count(v) == 3) { if (v1) { v2 = v; } else { v1 = v; } } } if (v1 && v2 && (v1 != v2) && !BM_edge_exists(v1, v2)) { BM_face_kill(bm, f); BMEdge *e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NOP); BM_elem_flag_set(e, BM_ELEM_TAG, true); } } BM_ITER_MESH_MUTABLE (ed, ed_next, &iter_a, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(ed, BM_ELEM_TAG)) { float co[3]; mid_v3_v3v3(co, ed->v1->co, ed->v2->co); BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true); copy_v3_v3(vc->co, co); } } /* Delete faces with a 3 edge pole in all their vertices */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) { bool dissolve = true; BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { if (BM_vert_edge_count(v) != 3) { dissolve = false; } } if (dissolve) { BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { BM_elem_flag_set(v, BM_ELEM_TAG, true); } } } BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS); BM_ITER_MESH (ed, &iter_a, bm, BM_EDGES_OF_MESH) { if (BM_edge_face_count(ed) != 2) { BM_elem_flag_set(ed, BM_ELEM_TAG, true); } } BM_mesh_edgenet(bm, false, true); /* Smooth the result */ for (int i = 0; i < 4; i++) { BM_ITER_MESH (v, &iter_a, bm, BM_VERTS_OF_MESH) { float co[3]; zero_v3(co); BM_ITER_ELEM (ed, &iter_b, v, BM_EDGES_OF_VERT) { BMVert *vert = BM_edge_other_vert(ed, v); add_v3_v3(co, vert->co); } mul_v3_fl(co, 1.0f / (float)BM_vert_edge_count(v)); mid_v3_v3v3(v->co, v->co, co); } } BM_mesh_normals_update(bm); BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false); BMO_op_callf(bm, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "recalc_face_normals faces=%hf", BM_ELEM_TAG); BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); Mesh *result = BKE_mesh_from_bmesh_nomain(bm, (&(struct BMeshToMeshParams){ .calc_object_remap = false, }), mesh); BKE_id_free(NULL, mesh); BM_mesh_free(bm); return result; }