From a82af0d220835970f83c63ade5e1b2309a993ec5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 23 Oct 2012 06:13:56 +0000 Subject: add option to planar decimator to collapse all verts that define face boundries (verts that 2 faces share and have 2 edge users). avoids ugly stepping between faces when applying on curves surfaces. (but less useful for architectural style models) --- .../startup/bl_ui/properties_data_modifier.py | 3 +- source/blender/bmesh/intern/bmesh_decimate.h | 4 +- .../blender/bmesh/intern/bmesh_decimate_dissolve.c | 74 +++++++++++++--------- source/blender/bmesh/intern/bmesh_opdefines.c | 1 + source/blender/bmesh/operators/bmo_dissolve.c | 3 +- source/blender/editors/mesh/editmesh_tools.c | 9 ++- source/blender/makesdna/DNA_modifier_types.h | 5 +- source/blender/makesrna/intern/rna_modifier.c | 11 +++- source/blender/modifiers/intern/MOD_decimate.c | 12 +++- 9 files changed, 80 insertions(+), 42 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 445178e4e42..c205edc0c3c 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -220,11 +220,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): row = layout.row() row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") row.prop(md, "invert_vertex_group") - layout.prop(md, "use_triangulate") + layout.prop(md, "use_collapse_triangulate") elif decimate_type == 'UNSUBDIV': layout.prop(md, "iterations") else: # decimate_type == 'DISSOLVE': layout.prop(md, "angle_limit") + layout.prop(md, "use_dissolve_boundaries") layout.label(text="Face Count" + ": %d" % md.face_count) diff --git a/source/blender/bmesh/intern/bmesh_decimate.h b/source/blender/bmesh/intern/bmesh_decimate.h index a5f4acc5f37..04dc0cfd2ea 100644 --- a/source/blender/bmesh/intern/bmesh_decimate.h +++ b/source/blender/bmesh/intern/bmesh_decimate.h @@ -32,10 +32,10 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int tag_only); void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations); -void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, +void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const int do_dissolve_boundaries, BMVert **vinput_arr, const int vinput_len, BMEdge **einput_arr, const int einput_len); -void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit); +void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const int do_dissolve_boundaries); #endif /* __BMESH_DECIMATE_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_decimate_dissolve.c b/source/blender/bmesh/intern/bmesh_decimate_dissolve.c index 97cad114121..26cf174dd15 100644 --- a/source/blender/bmesh/intern/bmesh_decimate_dissolve.c +++ b/source/blender/bmesh/intern/bmesh_decimate_dissolve.c @@ -69,7 +69,10 @@ static int dissolve_elem_cmp(const void *a1, const void *a2) return 0; } -void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, +/** + * \param do_all_verts Collapse all verts between 2 faces - don't check their edge angle. + */ +void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const int do_dissolve_boundaries, BMVert **vinput_arr, const int vinput_len, BMEdge **einput_arr, const int einput_len) { @@ -172,35 +175,48 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, /* --- second verts --- */ - for (i = 0, tot_found = 0; i < vinput_len; i++) { - BMVert *v = vinput_arr[i]; - const float angle = v ? bm_vert_edge_face_angle(v) : angle_limit; - - if (angle < angle_limit) { - weight_elems[i].ele = (BMHeader *)v; - weight_elems[i].weight = angle; - tot_found++; - } - else { - weight_elems[i].ele = NULL; - weight_elems[i].weight = angle_max; + if (do_dissolve_boundaries) { + /* simple version of the branch below, sincve we will dissolve _all_ verts that use 2 edges */ + for (i = 0; i < vinput_len; i++) { + BMVert *v = vinput_arr[i]; + if (v) { + if (BM_vert_edge_count(v) == 2) { + BM_vert_collapse_edge(bm, v->e, v, TRUE); /* join edges */ + } + } } } + else { + for (i = 0, tot_found = 0; i < vinput_len; i++) { + BMVert *v = vinput_arr[i]; + const float angle = v ? bm_vert_edge_face_angle(v) : angle_limit; + + if (angle < angle_limit) { + weight_elems[i].ele = (BMHeader *)v; + weight_elems[i].weight = angle; + tot_found++; + } + else { + weight_elems[i].ele = NULL; + weight_elems[i].weight = angle_max; + } + } - if (tot_found != 0) { - qsort(weight_elems, vinput_len, sizeof(DissolveElemWeight), dissolve_elem_cmp); - - for (i = 0; i < tot_found; i++) { - BMVert *v = (BMVert *)weight_elems[i].ele; - if (/* topology changes may cause this to be un-collapsable */ - (BM_vert_edge_count(v) == 2) && - /* check twice because cumulative effect could dissolve over angle limit */ - bm_vert_edge_face_angle(v) < angle_limit) - { - BMEdge *ne = BM_vert_collapse_edge(bm, v->e, v, TRUE); /* join edges */ - - if (ne && ne->l) { - BM_edge_normals_update(ne); + if (tot_found != 0) { + qsort(weight_elems, vinput_len, sizeof(DissolveElemWeight), dissolve_elem_cmp); + + for (i = 0; i < tot_found; i++) { + BMVert *v = (BMVert *)weight_elems[i].ele; + if (/* topology changes may cause this to be un-collapsable */ + (BM_vert_edge_count(v) == 2) && + /* check twice because cumulative effect could dissolve over angle limit */ + bm_vert_edge_face_angle(v) < angle_limit) + { + BMEdge *ne = BM_vert_collapse_edge(bm, v->e, v, TRUE); /* join edges */ + + if (ne && ne->l) { + BM_edge_normals_update(ne); + } } } } @@ -209,7 +225,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, MEM_freeN(weight_elems); } -void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit) +void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const int do_dissolve_boundaries) { int vinput_len; int einput_len; @@ -217,7 +233,7 @@ void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit) BMVert **vinput_arr = BM_iter_as_arrayN(bm, BM_VERTS_OF_MESH, NULL, &vinput_len); BMEdge **einput_arr = BM_iter_as_arrayN(bm, BM_EDGES_OF_MESH, NULL, &einput_len); - BM_mesh_decimate_dissolve_ex(bm, angle_limit, + BM_mesh_decimate_dissolve_ex(bm, angle_limit, do_dissolve_boundaries, vinput_arr, vinput_len, einput_arr, einput_len); diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 407e7caae0f..9f47892c15b 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -679,6 +679,7 @@ static BMOpDefine bmo_dissolve_faces_def = { static BMOpDefine bmo_dissolve_limit_def = { "dissolve_limit", {{BMO_OP_SLOT_FLT, "angle_limit"}, /* total rotation angle (degrees) */ + {BMO_OP_SLOT_BOOL, "use_dissolve_boundaries"}, {BMO_OP_SLOT_ELEMENT_BUF, "verts"}, {BMO_OP_SLOT_ELEMENT_BUF, "edges"}, {0} /* null-terminating sentinel */}, diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 41fe6b4dfec..ce6ecfc7b6f 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -483,8 +483,9 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op) BMOpSlot *vinput = BMO_slot_get(op, "verts"); const float angle_max = (float)M_PI / 2.0f; const float angle_limit = minf(angle_max, BMO_slot_float_get(op, "angle_limit")); + const int do_dissolve_boundaries = BMO_slot_bool_get(op, "use_dissolve_boundaries"); - BM_mesh_decimate_dissolve_ex(bm, angle_limit, + BM_mesh_decimate_dissolve_ex(bm, angle_limit, do_dissolve_boundaries, vinput->data.p, vinput->len, einput->data.p, einput->len); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 484faf0d1e5..0bbd9c7fbaf 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3412,7 +3412,8 @@ static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BMEdit_FromObject(obedit); BMesh *bm = em->bm; - float angle_limit = RNA_float_get(op->ptr, "angle_limit"); + const float angle_limit = RNA_float_get(op->ptr, "angle_limit"); + const int use_dissolve_boundaries = RNA_boolean_get(op->ptr, "use_dissolve_boundaries"); char dissolve_flag; @@ -3448,8 +3449,8 @@ static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) } if (!EDBM_op_callf(em, op, - "dissolve_limit edges=%he verts=%hv angle_limit=%f", - dissolve_flag, dissolve_flag, angle_limit)) + "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b", + dissolve_flag, dissolve_flag, angle_limit, use_dissolve_boundaries)) { return OPERATOR_CANCELLED; } @@ -3478,6 +3479,8 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot) prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), "Max Angle", "Angle Limit in Degrees", 0.0f, DEG2RADF(180.0f)); RNA_def_property_float_default(prop, DEG2RADF(15.0f)); + RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundries", + "Dissolve all vertices inbetween face boundaries"); } static int edbm_split_exec(bContext *C, wmOperator *op) diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 477d2c28f7c..a6f3cd5bda9 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -374,8 +374,9 @@ typedef struct DecimateModifierData { } DecimateModifierData; enum { - MOD_DECIM_FLAG_INVERT_VGROUP = (1 << 0), - MOD_DECIM_FLAG_TRIANGULATE = (1 << 1) /* for collapse only. dont convert tri pairs back to quads */ + MOD_DECIM_FLAG_INVERT_VGROUP = (1 << 0), + MOD_DECIM_FLAG_TRIANGULATE = (1 << 1), /* for collapse only. dont convert tri pairs back to quads */ + MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS = (1 << 2) /* for dissolve only. collapse all verts between 2 faces */ }; enum { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 12254a62f71..23d9a9065d5 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1167,12 +1167,21 @@ static void rna_def_modifier_decimate(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "use_triangulate", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_collapse_triangulate", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_TRIANGULATE); RNA_def_property_ui_text(prop, "Triangulate", "Keep triangulated faces resulting from decimation"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); /* end collapse-only option */ + /* (mode == MOD_DECIM_MODE_DISSOLVE) */ + prop = RNA_def_property(srna, "use_dissolve_boundaries", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS); + RNA_def_property_ui_text(prop, "All Boundaries", "Dissolve all vertices inbetween face boundaries"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* end dissolve-only option */ + + + /* all modes use this */ prop = RNA_def_property(srna, "face_count", PROP_INT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index cb6eb127172..a9bc9cbf83a 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -100,8 +100,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, BMEditMesh *em; BMesh *bm; - const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; - float *vweights = NULL; #ifdef USE_TIMEIT @@ -148,14 +146,22 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: + { + const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate); break; + } case MOD_DECIM_MODE_UNSUBDIV: + { BM_mesh_decimate_unsubdivide(bm, dmd->iter); break; + } case MOD_DECIM_MODE_DISSOLVE: - BM_mesh_decimate_dissolve(bm, dmd->angle); + { + const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0; + BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries); break; + } } if (vweights) { -- cgit v1.2.3