forked from bartvdbraak/blender
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)
This commit is contained in:
parent
c297605665
commit
a82af0d220
@ -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)
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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 (tot_found != 0) {
|
||||
qsort(weight_elems, vinput_len, sizeof(DissolveElemWeight), dissolve_elem_cmp);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (tot_found != 0) {
|
||||
qsort(weight_elems, vinput_len, sizeof(DissolveElemWeight), dissolve_elem_cmp);
|
||||
|
||||
if (ne && ne->l) {
|
||||
BM_edge_normals_update(ne);
|
||||
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);
|
||||
|
||||
|
@ -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 */},
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user