BMesh decimate, improve behavior with weights
Add slider to adjust the influence of weights relative to geometry distortion. This allows subtle influences to be applied - without drastic changes in behavior.
This commit is contained in:
parent
c64f491f9f
commit
455ca1b28f
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue