diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_data_mesh.py | 2 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d_toolbar.py | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_mesh_remesh_voxel.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_shrinkwrap.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_remesh_voxel.c | 106 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/shrinkwrap.c | 34 | ||||
-rw-r--r-- | source/blender/editors/object/object_remesh.c | 38 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_defaults.h | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mesh.c | 13 |
10 files changed, 182 insertions, 23 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 0794c3a1039..906969e9af4 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -476,7 +476,9 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel): col = layout.column() if (mesh.remesh_mode == 'VOXEL'): col.prop(mesh, "remesh_voxel_size") + col.prop(mesh, "remesh_fix_poles") col.prop(mesh, "remesh_smooth_normals") + col.prop(mesh, "remesh_preserve_volume") col.prop(mesh, "remesh_preserve_paint_mask") col.operator("object.voxel_remesh", text="Voxel Remesh") else: diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 761b813d576..96a27ae796c 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1234,7 +1234,9 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel): col = layout.column() mesh = context.active_object.data col.prop(mesh, "remesh_voxel_size") + col.prop(mesh, "remesh_fix_poles") col.prop(mesh, "remesh_smooth_normals") + col.prop(mesh, "remesh_preserve_volume") col.prop(mesh, "remesh_preserve_paint_mask") col.operator("object.voxel_remesh", text="Remesh") diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h index a1bcd515c17..16c22baf9b0 100644 --- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h +++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h @@ -39,6 +39,8 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve double adaptivity, bool relax_disoriented_triangles); #endif + +struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh); struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size); struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh, int target_faces, diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index e3d19a3d807..e90b1429c9d 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -115,6 +115,11 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C, struct Object *ob_source, struct Object *ob_target); +/* Used in object_remesh.c to preserve the details and volume in the voxel remesher */ +void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me, + struct Mesh *target_me, + struct Object *ob_target); + /* * This function casts a ray in the given BVHTree. * but it takes into consideration the space_transform, that is: diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c index ff7ff947e1d..92e180601d7 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c @@ -38,6 +38,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_library.h" @@ -45,6 +46,8 @@ #include "BKE_bvhutils.h" #include "BKE_mesh_remesh_voxel.h" /* own include */ +#include "bmesh_tools.h" + #ifdef WITH_OPENVDB # include "openvdb_capi.h" #endif @@ -348,3 +351,106 @@ void BKE_remesh_reproject_paint_mask(Mesh *target, Mesh *source) } 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_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, 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; +} diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 992ceda7b74..797ae0f0a8a 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -1506,3 +1506,37 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C, MEM_freeN(vertexCos); } + +void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target) +{ + ShrinkwrapModifierData ssmd = {0}; + int totvert; + + ssmd.target = ob_target; + ssmd.shrinkType = MOD_SHRINKWRAP_TARGET_PROJECT; + ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE; + ssmd.keepDist = 0.0f; + + float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert); + + ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; + + calc.smd = &ssmd; + calc.numVerts = src_me->totvert; + calc.vertexCos = vertexCos; + calc.vgroup = -1; + calc.target = target_me; + calc.keepDist = ssmd.keepDist; + BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target); + + ShrinkwrapTreeData tree; + if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) { + calc.tree = &tree; + TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface); + BKE_shrinkwrap_free_tree(&tree); + } + + BKE_mesh_vert_coords_apply(src_me, vertexCos); + + MEM_freeN(vertexCos); +} diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index d4e7ee04da8..6075867b552 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -42,10 +42,13 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_library.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_shrinkwrap.h" #include "BKE_customdata.h" #include "BKE_mesh_remesh_voxel.h" @@ -112,23 +115,22 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - Mesh *obj_mesh_copy = NULL; - if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) { - obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0); - CustomData_copy( - &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - for (int i = 0; i < mesh->totvert; i++) { - copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co); - } + if (mesh->flag & ME_REMESH_FIX_POLES) { + new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh); } - BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); + if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) { + BKE_mesh_runtime_clear_geometry(mesh); + BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob); + } if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) { - BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy); - BKE_mesh_free(obj_mesh_copy); + BKE_mesh_runtime_clear_geometry(mesh); + BKE_remesh_reproject_paint_mask(new_mesh, mesh); } + BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); + if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) { BKE_mesh_smooth_flag_set(ob->data, true); } @@ -264,23 +266,13 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update ED_sculpt_undo_geometry_begin(ob); } - Mesh *obj_mesh_copy = NULL; if (qj->preserve_paint_mask) { - obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0); - CustomData_copy( - &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - for (int i = 0; i < mesh->totvert; i++) { - copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co); - } + BKE_mesh_runtime_clear_geometry(mesh); + BKE_remesh_reproject_paint_mask(new_mesh, mesh); } BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); - if (qj->preserve_paint_mask) { - BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy); - BKE_mesh_free(obj_mesh_copy); - } - if (qj->smooth_normals) { BKE_mesh_smooth_flag_set(ob->data, true); } diff --git a/source/blender/makesdna/DNA_mesh_defaults.h b/source/blender/makesdna/DNA_mesh_defaults.h index 40b8e2c9247..a4354232cf7 100644 --- a/source/blender/makesdna/DNA_mesh_defaults.h +++ b/source/blender/makesdna/DNA_mesh_defaults.h @@ -34,6 +34,7 @@ .smoothresh = DEG2RADF(30), \ .texflag = ME_AUTOSPACE, \ .remesh_voxel_size = 0.1f, \ + .flag = ME_REMESH_FIX_POLES | ME_REMESH_REPROJECT_VOLUME, \ } /** \} */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index e77a535ab7a..1e7c12e97bc 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -251,6 +251,8 @@ enum { ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10, ME_REMESH_SMOOTH_NORMALS = 1 << 11, ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12, + ME_REMESH_FIX_POLES = 1 << 13, + ME_REMESH_REPROJECT_VOLUME = 1 << 14, }; /* me->cd_flag */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 1ecaf0805a0..ce2911cbb01 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3000,6 +3000,19 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_fix_poles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES); + RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + + prop = RNA_def_property(srna, "remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VOLUME); + RNA_def_property_ui_text( + prop, + "Preserve Volume", + "Projects the mesh to preserve the volume and details of the original mesh"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_PAINT_MASK); RNA_def_property_boolean_default(prop, false); |