From 3526ae98055d28ac27f1e9b5d8b76d7597905e99 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 22 Oct 2012 15:39:06 +0000 Subject: [PATCH] add vertex group option to decimate modifier, handy if you want to pin some parts of the geometry. --- .../startup/bl_ui/properties_data_modifier.py | 3 + source/blender/bmesh/intern/bmesh_decimate.c | 61 ++++++++++++++----- source/blender/bmesh/intern/bmesh_decimate.h | 2 +- source/blender/makesdna/DNA_modifier_types.h | 9 ++- source/blender/makesrna/intern/rna_modifier.c | 17 ++++++ .../blender/modifiers/intern/MOD_decimate.c | 55 +++++++++++++++-- source/blender/modifiers/intern/MOD_util.h | 12 ++-- 7 files changed, 134 insertions(+), 25 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 0398cb36b18..5d8144631b0 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -212,6 +212,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): def DECIMATE(self, layout, ob, md): layout.prop(md, "ratio") + row = layout.row() + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex_group") layout.label(text="Face Count" + ": %d" % md.face_count) def DISPLACE(self, layout, ob, md): diff --git a/source/blender/bmesh/intern/bmesh_decimate.c b/source/blender/bmesh/intern/bmesh_decimate.c index dd836c7c4fc..978a1674121 100644 --- a/source/blender/bmesh/intern/bmesh_decimate.c +++ b/source/blender/bmesh/intern/bmesh_decimate.c @@ -144,7 +144,7 @@ static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3], } static void bm_decim_build_edge_cost_single(BMEdge *e, - const Quadric *vquadrics, + const Quadric *vquadrics, const float *vweights, Heap *eheap, HeapNode **eheap_table) { const Quadric *q1, *q2; @@ -180,6 +180,16 @@ static void bm_decim_build_edge_cost_single(BMEdge *e, eheap_table[BM_elem_index_get(e)] = NULL; return; } + + if (vweights) { + if ((vweights[BM_elem_index_get(e->v1)] < FLT_EPSILON) && + (vweights[BM_elem_index_get(e->v2)] < FLT_EPSILON)) + { + /* skip collapsing this edge */ + eheap_table[BM_elem_index_get(e)] = NULL; + return; + } + } /* end sanity check */ @@ -188,14 +198,21 @@ static void bm_decim_build_edge_cost_single(BMEdge *e, q1 = &vquadrics[BM_elem_index_get(e->v1)]; q2 = &vquadrics[BM_elem_index_get(e->v2)]; - cost = (BLI_quadric_evaluate(q1, optimize_co) + BLI_quadric_evaluate(q2, optimize_co)); + if (vweights == NULL) { + cost = (BLI_quadric_evaluate(q1, optimize_co) + + BLI_quadric_evaluate(q2, optimize_co)); + } + else { + cost = ((BLI_quadric_evaluate(q1, optimize_co) * vweights[BM_elem_index_get(e->v1)]) + + (BLI_quadric_evaluate(q2, optimize_co) * vweights[BM_elem_index_get(e->v2)])); + } // print("COST %.12f\n"); eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e); } static void bm_decim_build_edge_cost(BMesh *bm, - const Quadric *vquadrics, + const Quadric *vquadrics, const float *vweights, Heap *eheap, HeapNode **eheap_table) { BMIter iter; @@ -204,7 +221,7 @@ static void bm_decim_build_edge_cost(BMesh *bm, BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { eheap_table[i] = NULL; /* keep sanity check happy */ - bm_decim_build_edge_cost_single(e, vquadrics, eheap, eheap_table); + bm_decim_build_edge_cost_single(e, vquadrics, vweights, eheap, eheap_table); #ifdef USE_PRESERVE_BOUNDARY /* init: runs second! */ @@ -268,15 +285,16 @@ static int bm_decim_triangulate_begin(BMesh *bm) BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { if (f->len == 4) { BMLoop *f_l[4]; - BMLoop *l_iter; BMLoop *l_a, *l_b; - l_iter = BM_FACE_FIRST_LOOP(f); + { + BMLoop *l_iter = BM_FACE_FIRST_LOOP(f); - f_l[0] = l_iter; l_iter = l_iter->next; - f_l[1] = l_iter; l_iter = l_iter->next; - f_l[2] = l_iter; l_iter = l_iter->next; - f_l[3] = l_iter; l_iter = l_iter->next; + f_l[0] = l_iter; l_iter = l_iter->next; + f_l[1] = l_iter; l_iter = l_iter->next; + f_l[2] = l_iter; l_iter = l_iter->next; + f_l[3] = l_iter; + } if (len_squared_v3v3(f_l[0]->v->co, f_l[2]->v->co) < len_squared_v3v3(f_l[1]->v->co, f_l[3]->v->co)) @@ -764,7 +782,7 @@ static int bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e /* collapse e the edge, removing e->v2 */ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, - Quadric *vquadrics, + Quadric *vquadrics, float *vweights, Heap *eheap, HeapNode **eheap_table, const CD_UseFlag customdata_flag) { @@ -796,6 +814,12 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, /* update collapse info */ int i; + if (vweights) { + const int fac = CLAMPIS(customdata_fac, 0.0f, 1.0f); + vweights[BM_elem_index_get(v_other)] = (vweights[v_clear_index] * (1.0f - fac)) + + (vweights[BM_elem_index_get(v_other)] * fac); + } + e = NULL; /* paranoid safety check */ copy_v3_v3(v_other->co, optimize_co); @@ -825,7 +849,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, e_iter = e_first = v_other->e; do { BLI_assert(BM_edge_find_double(e_iter) == NULL); - bm_decim_build_edge_cost_single(e_iter, vquadrics, eheap, eheap_table); + bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, eheap, eheap_table); } while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first); } @@ -857,7 +881,14 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, /* Main Decimate Function * ********************** */ -void BM_mesh_decimate(BMesh *bm, const float factor) +/** + * \brief BM_mesh_decimate + * \param bm The mesh + * \param factor face count multiplier [0 - 1] + * \param vertex_weights Optional array of vertex aligned weights [0 - 1], + * a vertex group is the usual source for this. + */ +void BM_mesh_decimate(BMesh *bm, const float factor, float *vweights) { Heap *eheap; /* edge heap */ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */ @@ -885,7 +916,7 @@ void BM_mesh_decimate(BMesh *bm, const float factor) /* build initial edge collapse cost data */ bm_decim_build_quadrics(bm, vquadrics); - bm_decim_build_edge_cost(bm, vquadrics, eheap, eheap_table); + bm_decim_build_edge_cost(bm, vquadrics, vweights, eheap, eheap_table); face_tot_target = bm->totface * factor; bm->elem_index_dirty |= BM_FACE | BM_EDGE | BM_VERT; @@ -910,7 +941,7 @@ void BM_mesh_decimate(BMesh *bm, const float factor) * but NULL just incase so we don't use freed node */ eheap_table[BM_elem_index_get(e)] = NULL; - bm_decim_edge_collapse(bm, e, vquadrics, eheap, eheap_table, customdata_flag); + bm_decim_edge_collapse(bm, e, vquadrics, vweights, eheap, eheap_table, customdata_flag); } diff --git a/source/blender/bmesh/intern/bmesh_decimate.h b/source/blender/bmesh/intern/bmesh_decimate.h index e44aa576bda..1724bbd16bb 100644 --- a/source/blender/bmesh/intern/bmesh_decimate.h +++ b/source/blender/bmesh/intern/bmesh_decimate.h @@ -27,6 +27,6 @@ * \ingroup bmesh */ -void BM_mesh_decimate(BMesh *bm, const float factor); +void BM_mesh_decimate(BMesh *bm, const float factor, float *vweights); #endif /* __BMESH_DECIMATE_H__ */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index fe82d27cfa8..05c1871ae41 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -362,9 +362,16 @@ typedef struct DecimateModifierData { ModifierData modifier; float percent; - int faceCount; + int faceCount; /* runtime only */ + + char defgrp_name[64]; /* MAX_VGROUP_NAME */ + int flag, pad; } DecimateModifierData; +enum { + MOD_DECIM_INVERT_VGROUP = (1 << 0) +}; + /* Smooth modifier flags */ #define MOD_SMOOTH_X (1<<1) #define MOD_SMOOTH_Y (1<<2) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 1fcf4107682..67ab1469318 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -377,6 +377,12 @@ static void rna_SolidifyModifier_vgroup_set(PointerRNA *ptr, const char *value) rna_object_vgroup_name_set(ptr, value, smd->defgrp_name, sizeof(smd->defgrp_name)); } +static void rna_DecimateModifier_vgroup_set(PointerRNA *ptr, const char *value) +{ + DecimateModifierData *dmd = (DecimateModifierData *)ptr->data; + rna_object_vgroup_name_set(ptr, value, dmd->defgrp_name, sizeof(dmd->defgrp_name)); +} + static void rna_WeightVGModifier_vgroup_set(PointerRNA *ptr, const char *value) { ModifierData *md = (ModifierData *)ptr->data; @@ -1119,6 +1125,17 @@ static void rna_def_modifier_decimate(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Ratio", "Ratio of triangles to reduce to"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_DecimateModifier_vgroup_set"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_INVERT_VGROUP); + 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, "face_count", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "faceCount"); 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 d55bc7ab9b1..a882e4f5854 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -32,9 +32,10 @@ * \ingroup modifiers */ -#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "BLI_math.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BLF_translation.h" @@ -43,6 +44,7 @@ #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_deform.h" #include "BKE_particle.h" #include "BKE_cdderivedmesh.h" @@ -70,9 +72,22 @@ static void copyData(ModifierData *md, ModifierData *target) DecimateModifierData *tdmd = (DecimateModifierData *) target; tdmd->percent = dmd->percent; + BLI_strncpy(tdmd->defgrp_name, dmd->defgrp_name, sizeof(tdmd->defgrp_name)); + tdmd->flag = dmd->flag; } -static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob), +static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) +{ + DecimateModifierData *dmd = (DecimateModifierData *) md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if (dmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT; + + return dataMask; +} + +static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { @@ -81,6 +96,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob), BMEditMesh *em; BMesh *bm; + float *vweights = NULL; + #ifdef USE_TIMEIT TIMEIT_START(decim); #endif @@ -93,10 +110,40 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob), return dm; } + if (dmd->defgrp_name[0]) { + MDeformVert *dvert; + int defgrp_index; + + modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); + + if (dvert) { + const unsigned int vert_tot = dm->getNumVerts(dm); + unsigned int i; + + vweights = MEM_mallocN(vert_tot * sizeof(float), __func__); + + if (dmd->flag & MOD_DECIM_INVERT_VGROUP) { + for (i = 0; i < vert_tot; i++) { + vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index); + } + } + else { + for (i = 0; i < vert_tot; i++) { + vweights[i] = defvert_find_weight(&dvert[i], defgrp_index); + } + } + } + } + + em = DM_to_editbmesh(dm, NULL, FALSE); bm = em->bm; - BM_mesh_decimate(bm, dmd->percent); + BM_mesh_decimate(bm, dmd->percent, vweights); + + if (vweights) { + MEM_freeN(vweights); + } dmd->faceCount = bm->totface; @@ -126,7 +173,7 @@ ModifierTypeInfo modifierType_Decimate = { /* applyModifier */ applyModifier, /* applyModifierEM */ NULL, /* initData */ initData, - /* requiredDataMask */ NULL, + /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, /* updateDepgraph */ NULL, diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h index eadf7af553b..6f05c9a957a 100644 --- a/source/blender/modifiers/intern/MOD_util.h +++ b/source/blender/modifiers/intern/MOD_util.h @@ -42,10 +42,14 @@ struct TexResult; void modifier_init_texture(struct Scene *scene, struct Tex *texture); void get_texture_value(struct Tex *texture, float *tex_co, struct TexResult *texres); -void get_texture_coords(struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts); +void get_texture_coords(struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm, + float (*co)[3], float (*texco)[3], int numVerts); void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]); -struct DerivedMesh *get_cddm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]); -struct DerivedMesh *get_dm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], int orco); -void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index); +struct DerivedMesh *get_cddm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, + float (*vertexCos)[3]); +struct DerivedMesh *get_dm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, + float (*vertexCos)[3], int orco); +void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm, + const char *name, struct MDeformVert **dvert, int *defgrp_index); #endif /* __MOD_UTIL_H__ */