BMesh decimate, improve behavior with weights
authorCampbell Barton <ideasman42@gmail.com>
Thu, 4 Jun 2015 09:49:59 +0000 (19:49 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 4 Jun 2015 16:56:11 +0000 (02:56 +1000)
Add slider to adjust the influence of weights relative to geometry distortion.
This allows subtle influences to be applied - without drastic changes in behavior.

release/scripts/startup/bl_ui/properties_data_modifier.py
source/blender/blenloader/intern/versioning_270.c
source/blender/bmesh/tools/bmesh_decimate.h
source/blender/bmesh/tools/bmesh_decimate_collapse.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/modifiers/intern/MOD_decimate.c

index d6d4e03df393db6ae1d95cf5e288a75cad3e226f..381c9add34fbf25d506da9f6d331649f068ad251 100644 (file)
@@ -262,24 +262,37 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         row.prop(md, "decimate_type", expand=True)
 
         if decimate_type == 'COLLAPSE':
+            has_vgroup = bool(md.vertex_group)
             layout.prop(md, "ratio")
 
             split = layout.split()
-            row = split.row(align=True)
+
+            col = split.column()
+            row = col.row(align=True)
             row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
             row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
 
-            split.prop(md, "use_collapse_triangulate")
+            layout_info = col
+
+            col = split.column()
+            row = col.row()
+            row.active = has_vgroup
+            row.prop(md, "vertex_group_factor")
+
+            col.prop(md, "use_collapse_triangulate")
+
         elif decimate_type == 'UNSUBDIV':
             layout.prop(md, "iterations")
+            layout_info = layout
         else:  # decimate_type == 'DISSOLVE':
             layout.prop(md, "angle_limit")
             layout.prop(md, "use_dissolve_boundaries")
             layout.label("Delimit:")
             row = layout.row()
             row.prop(md, "delimit")
+            layout_info = layout
 
-        layout.label(text=iface_("Face Count: %d") % md.face_count, translate=False)
+        layout_info.label(text=iface_("Faces: %d") % md.face_count, translate=False)
 
     def DISPLACE(self, layout, ob, md):
         has_texture = (md.texture is not None)
index df985448ccd2ac4316b5f0e6e39cbb34776286ac..37c255620d98acb0f66b0883de41bd087f39a292 100644 (file)
@@ -830,5 +830,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
                                scene->r.simplify_particles_render = scene->r.simplify_particles;
                        }
                }
+
+               if (!DNA_struct_elem_find(fd->filesdna, "DecimateModifierData", "float", "defgrp_factor")) {
+                       Object *ob;
+
+                       for (ob = main->object.first; ob; ob = ob->id.next) {
+                               ModifierData *md;
+                               for (md = ob->modifiers.first; md; md = md->next) {
+                                       if (md->type == eModifierType_Decimate) {
+                                               DecimateModifierData *dmd = (DecimateModifierData *)md;
+                                               dmd->defgrp_factor = 1.0f;
+                                       }
+                               }
+                       }
+               }
        }
 }
index 17b55be52dcb556e61dff0ae9e4ff9399226e293..b0a85b09d5a9ac784c397e4728eb51187b0f096f 100644 (file)
@@ -42,8 +42,4 @@ void BM_mesh_decimate_dissolve(
         BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
         const BMO_Delimit delimit);
 
-/* these weights are accumulated so too high values may reach 'inf' too quickly */
-#define BM_MESH_DECIM_WEIGHT_MAX 100000.0f
-#define BM_MESH_DECIM_WEIGHT_EPS (1.0f / BM_MESH_DECIM_WEIGHT_MAX)
-
 #endif /* __BMESH_DECIMATE_H__ */
index 3bcf9a3cd0bd604ad312dc48cb0f1b0c2e2ef4ce..6b6219ca3213e0b99580c9bc1efab94f9da85223 100644 (file)
@@ -212,10 +212,15 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
  *
  * This avoids cases where a flat (or near flat) areas get very un-even geometry.
  */
-static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
+static float bm_decim_build_edge_cost_single_squared__topology(BMEdge *e)
 {
        return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_squared_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
 }
+static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
+{
+       return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+}
+
 #endif  /* USE_TOPOLOGY_FALLBACK */
 
 static void bm_decim_build_edge_cost_single(
@@ -253,15 +258,6 @@ static void bm_decim_build_edge_cost_single(
        else {
                goto clear;
        }
-
-       if (vweights) {
-               if ((vweights[BM_elem_index_get(e->v1)] >= BM_MESH_DECIM_WEIGHT_MAX) &&
-                   (vweights[BM_elem_index_get(e->v2)] >= BM_MESH_DECIM_WEIGHT_MAX))
-               {
-                       /* skip collapsing this edge */
-                       goto clear;
-               }
-       }
        /* end sanity check */
 
 
@@ -270,21 +266,21 @@ static void bm_decim_build_edge_cost_single(
        q1 = &vquadrics[BM_elem_index_get(e->v1)];
        q2 = &vquadrics[BM_elem_index_get(e->v2)];
 
-       if (vweights == NULL) {
-               cost = (BLI_quadric_evaluate(q1, optimize_co) +
-                       BLI_quadric_evaluate(q2, optimize_co));
-       }
-       else {
-               /* add 1.0 so planar edges are still weighted against */
-               cost = (((BLI_quadric_evaluate(q1, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v1)]) +
-                       ((BLI_quadric_evaluate(q2, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v2)]));
-       }
+       cost = (BLI_quadric_evaluate(q1, optimize_co) +
+               BLI_quadric_evaluate(q2, optimize_co));
+
+
        // print("COST %.12f\n");
 
        /* note, 'cost' shouldn't be negative but happens sometimes with small values.
         * this can cause faces that make up a flat surface to over-collapse, see [#37121] */
        cost = fabsf(cost);
 
+       /* edge weights can be 2 max, ((2 * 2) ^ 2) == 16x max,
+        * a high weight means being inserted into the heap ahead of 16x better edges.
+        * but thats fine since its the purpose of weighting. */
+#define VWEIGHT_SCALE 2
+
 #ifdef USE_TOPOLOGY_FALLBACK
        if (UNLIKELY(cost < TOPOLOGY_FALLBACK_EPS)) {
                /* subtract existing cost to further differentiate edges from one another
@@ -292,10 +288,35 @@ static void bm_decim_build_edge_cost_single(
                 * keep topology cost below 0.0 so their values don't interfere with quadric cost,
                 * (and they get handled first).
                 * */
-               cost = bm_decim_build_edge_cost_single__topology(e) - cost;
-               BLI_assert(cost <= 0.0f);
+               if (vweights == NULL) {
+                       cost = bm_decim_build_edge_cost_single_squared__topology(e) - cost;
+               }
+               else {
+                       /* with weights we need to use the real length so we can scale them properly */
+                       float e_weight = (vweights[BM_elem_index_get(e->v1)] +
+                                         vweights[BM_elem_index_get(e->v2)]);
+                       cost = bm_decim_build_edge_cost_single__topology(e) - cost;
+                       /* note, this is rather arbitrary max weight is 2 here,
+                        * allow for skipping edges 4x the length, based on weights */
+                       if (e_weight) {
+                               e_weight *= VWEIGHT_SCALE;
+                               cost *= 1.0f + SQUARE(e_weight);
+                       }
+
+                       BLI_assert(cost <= 0.0f);
+               }
        }
+       else
 #endif
+       if (vweights) {
+               float e_weight = 2.0f - (vweights[BM_elem_index_get(e->v1)] +
+                                        vweights[BM_elem_index_get(e->v2)]);
+               if (e_weight) {
+                       e_weight *= VWEIGHT_SCALE;
+                       cost += (BM_edge_calc_length(e) * SQUARE(e_weight));
+               }
+       }
+#undef VWEIGHT_SCALE
 
        eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e);
        return;
@@ -950,7 +971,9 @@ static void bm_decim_edge_collapse(
                int i;
 
                if (vweights) {
-                       vweights[v_other_index] += vweights[v_clear_index];
+                       float v_other_weight = interpf(vweights[v_other_index], vweights[v_clear_index], customdata_fac);
+                       CLAMP(v_other_weight, 0.0f, 1.0f);
+                       vweights[v_other_index] = v_other_weight;
                }
 
                e = NULL;  /* paranoid safety check */
index f3c61f0ab6c1764ca1aa183bec345ee9c62e191d..1fc66b9b016ea3cb42b036103af42e98ec4fd11b 100644 (file)
@@ -431,10 +431,11 @@ typedef struct DecimateModifierData {
        float angle;    /* (mode == MOD_DECIM_MODE_DISSOLVE) */
 
        char defgrp_name[64];  /* MAX_VGROUP_NAME */
+       float defgrp_factor;
        short flag, mode;
 
        /* runtime only */
-       int face_count, pad2;
+       int face_count;
 } DecimateModifierData;
 
 enum {
index 1c719b1376b9b8c59f73f3b0023ecaa34b902a65..6f1f6f97a15226ea3409bcd87dd6c66f70e4e2dd 100644 (file)
@@ -1506,6 +1506,13 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
        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 (collapse only)");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+       prop = RNA_def_property(srna, "vertex_group_factor", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "defgrp_factor");
+       RNA_def_property_range(prop, 0, 1.0f);
+       RNA_def_property_ui_range(prop, 0, 1, 1, 4);
+       RNA_def_property_ui_text(prop, "Factor", "Vertex group strength");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
        /* end collapse-only option */
 
        /* (mode == MOD_DECIM_MODE_DISSOLVE) */
index 7c13774ee9981d686b71a6f17466b14aadfe8801..878015c7a7b08f8b46cd8a1d08fc9bdd7b586227 100644 (file)
@@ -61,6 +61,7 @@ static void initData(ModifierData *md)
 
        dmd->percent = 1.0;
        dmd->angle   = DEG2RADF(5.0f);
+       dmd->defgrp_factor = 1.0;
 }
 
 static void copyData(ModifierData *md, ModifierData *target)
@@ -78,7 +79,9 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
        CustomDataMask dataMask = 0;
 
        /* ask for vertexgroups if we need them */
-       if (dmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
+       if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
+               dataMask |= CD_MASK_MDEFORMVERT;
+       }
 
        return dataMask;
 }
@@ -130,7 +133,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
        }
 
        if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
-               if (dmd->defgrp_name[0]) {
+               if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
                        MDeformVert *dvert;
                        int defgrp_index;
 
@@ -144,14 +147,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
 
                                if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
                                        for (i = 0; i < vert_tot; i++) {
-                                               const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
-                                               vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
+                                               vweights[i] = (1.0f - defvert_find_weight(&dvert[i], defgrp_index)) * dmd->defgrp_factor;
                                        }
                                }
                                else {
                                        for (i = 0; i < vert_tot; i++) {
-                                               const float f = defvert_find_weight(&dvert[i], defgrp_index);
-                                               vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
+                                               vweights[i] = (defvert_find_weight(&dvert[i], defgrp_index)) * dmd->defgrp_factor;
                                        }
                                }
                        }