forked from bartvdbraak/blender
add limited dissolve as a decimation type to the decimate modifier.
This commit is contained in:
parent
0636886715
commit
bbe0deb8af
@ -213,14 +213,17 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|||||||
def DECIMATE(self, layout, ob, md):
|
def DECIMATE(self, layout, ob, md):
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(md, "decimate_type", expand=True)
|
row.prop(md, "decimate_type", expand=True)
|
||||||
|
decimate_type = md.decimate_type
|
||||||
|
|
||||||
if md.decimate_type == 'COLLAPSE':
|
if decimate_type == 'COLLAPSE':
|
||||||
layout.prop(md, "ratio")
|
layout.prop(md, "ratio")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
|
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
|
||||||
row.prop(md, "invert_vertex_group")
|
row.prop(md, "invert_vertex_group")
|
||||||
else: # assume UNSUBDIV
|
elif decimate_type == 'UNSUBDIV':
|
||||||
layout.prop(md, "iterations")
|
layout.prop(md, "iterations")
|
||||||
|
else: # decimate_type == 'DISSOLVE':
|
||||||
|
layout.prop(md, "angle_limit")
|
||||||
|
|
||||||
layout.label(text="Face Count" + ": %d" % md.face_count)
|
layout.label(text="Face Count" + ": %d" % md.face_count)
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ set(SRC
|
|||||||
intern/bmesh_core.c
|
intern/bmesh_core.c
|
||||||
intern/bmesh_core.h
|
intern/bmesh_core.h
|
||||||
intern/bmesh_decimate_collapse.c
|
intern/bmesh_decimate_collapse.c
|
||||||
|
intern/bmesh_decimate_dissolve.c
|
||||||
intern/bmesh_decimate_unsubdivide.c
|
intern/bmesh_decimate_unsubdivide.c
|
||||||
intern/bmesh_decimate.h
|
intern/bmesh_decimate.h
|
||||||
intern/bmesh_inline.h
|
intern/bmesh_inline.h
|
||||||
|
@ -32,4 +32,10 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights);
|
|||||||
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int tag_only);
|
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_unsubdivide(BMesh *bm, const int iterations);
|
||||||
|
|
||||||
|
void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit,
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __BMESH_DECIMATE_H__ */
|
#endif /* __BMESH_DECIMATE_H__ */
|
||||||
|
226
source/blender/bmesh/intern/bmesh_decimate_dissolve.c
Normal file
226
source/blender/bmesh/intern/bmesh_decimate_dissolve.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributor(s): Campbell Barton
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file blender/bmesh/intern/bmesh_decimate_dissolve.c
|
||||||
|
* \ingroup bmesh
|
||||||
|
*
|
||||||
|
* BMesh decimator that dissolves flat areas into polygons (ngons).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BLI_math.h"
|
||||||
|
|
||||||
|
#include "bmesh.h"
|
||||||
|
#include "bmesh_decimate.h" /* own include */
|
||||||
|
|
||||||
|
#define UNIT_TO_ANGLE DEG2RADF(90.0f)
|
||||||
|
#define ANGLE_TO_UNIT (1.0f / UNIT_TO_ANGLE)
|
||||||
|
|
||||||
|
/* multiply vertex edge angle by face angle
|
||||||
|
* this means we are not left with sharp corners between _almost_ planer faces
|
||||||
|
* convert angles [0-PI/2] -> [0-1], multiply together, then convert back to radians. */
|
||||||
|
static float bm_vert_edge_face_angle(BMVert *v)
|
||||||
|
{
|
||||||
|
const float angle = BM_vert_calc_edge_angle(v);
|
||||||
|
/* note: could be either edge, it doesn't matter */
|
||||||
|
if (v->e && BM_edge_is_manifold(v->e)) {
|
||||||
|
return ((angle * ANGLE_TO_UNIT) * (BM_edge_calc_face_angle(v->e) * ANGLE_TO_UNIT)) * UNIT_TO_ANGLE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef UNIT_TO_ANGLE
|
||||||
|
#undef ANGLE_TO_UNIT
|
||||||
|
|
||||||
|
typedef struct DissolveElemWeight {
|
||||||
|
BMHeader *ele;
|
||||||
|
float weight;
|
||||||
|
} DissolveElemWeight;
|
||||||
|
|
||||||
|
static int dissolve_elem_cmp(const void *a1, const void *a2)
|
||||||
|
{
|
||||||
|
const struct DissolveElemWeight *d1 = a1, *d2 = a2;
|
||||||
|
|
||||||
|
if (d1->weight > d2->weight) return 1;
|
||||||
|
else if (d1->weight < d2->weight) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit,
|
||||||
|
BMVert **vinput_arr, const int vinput_len,
|
||||||
|
BMEdge **einput_arr, const int einput_len)
|
||||||
|
{
|
||||||
|
const float angle_max = (float)M_PI / 2.0f;
|
||||||
|
DissolveElemWeight *weight_elems = MEM_mallocN(maxi(einput_len, vinput_len) *
|
||||||
|
sizeof(DissolveElemWeight), __func__);
|
||||||
|
int i, tot_found;
|
||||||
|
|
||||||
|
BMIter iter;
|
||||||
|
BMEdge *e_iter;
|
||||||
|
BMEdge **earray;
|
||||||
|
|
||||||
|
int *vert_reverse_lookup;
|
||||||
|
|
||||||
|
/* --- first edges --- */
|
||||||
|
|
||||||
|
/* wire -> tag */
|
||||||
|
BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
|
||||||
|
BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* go through and split edge */
|
||||||
|
for (i = 0, tot_found = 0; i < einput_len; i++) {
|
||||||
|
BMEdge *e = einput_arr[i];
|
||||||
|
const float angle = BM_edge_calc_face_angle(e);
|
||||||
|
|
||||||
|
if (angle < angle_limit) {
|
||||||
|
tot_found++;
|
||||||
|
}
|
||||||
|
weight_elems[i].ele = (BMHeader *)e;
|
||||||
|
weight_elems[i].weight = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tot_found != 0) {
|
||||||
|
qsort(weight_elems, einput_len, sizeof(DissolveElemWeight), dissolve_elem_cmp);
|
||||||
|
|
||||||
|
for (i = 0; i < tot_found; i++) {
|
||||||
|
BMEdge *e = (BMEdge *)weight_elems[i].ele;
|
||||||
|
|
||||||
|
if (/* may have become non-manifold */
|
||||||
|
BM_edge_is_manifold(e) &&
|
||||||
|
/* check twice because cumulative effect could dissolve over angle limit */
|
||||||
|
(BM_edge_calc_face_angle(e) < angle_limit))
|
||||||
|
{
|
||||||
|
BMFace *nf = BM_faces_join_pair(bm, e->l->f,
|
||||||
|
e->l->radial_next->f,
|
||||||
|
e,
|
||||||
|
FALSE); /* join faces */
|
||||||
|
|
||||||
|
/* there may be some errors, we don't mind, just move on */
|
||||||
|
if (nf) {
|
||||||
|
BM_face_normal_update(nf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BMO_error_clear(bm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare for cleanup */
|
||||||
|
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
||||||
|
vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
|
||||||
|
fill_vn_i(vert_reverse_lookup, bm->totvert, -1);
|
||||||
|
for (i = 0, tot_found = 0; i < vinput_len; i++) {
|
||||||
|
BMVert *v = vinput_arr[i];
|
||||||
|
vert_reverse_lookup[BM_elem_index_get(v)] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- cleanup --- */
|
||||||
|
earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__);
|
||||||
|
BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) {
|
||||||
|
earray[i] = e_iter;
|
||||||
|
}
|
||||||
|
/* remove all edges/verts left behind from dissolving, NULL'ing the vertex array so we dont re-use */
|
||||||
|
for (i = bm->totedge - 1; i != -1; i--) {
|
||||||
|
e_iter = earray[i];
|
||||||
|
|
||||||
|
if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == FALSE)) {
|
||||||
|
/* edge has become wire */
|
||||||
|
int vidx_reverse;
|
||||||
|
BMVert *v1 = e_iter->v1;
|
||||||
|
BMVert *v2 = e_iter->v2;
|
||||||
|
BM_edge_kill(bm, e_iter);
|
||||||
|
if (v1->e == NULL) {
|
||||||
|
vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)];
|
||||||
|
if (vidx_reverse != -1) vinput_arr[vidx_reverse] = NULL;
|
||||||
|
BM_vert_kill(bm, v1);
|
||||||
|
}
|
||||||
|
if (v2->e == NULL) {
|
||||||
|
vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)];
|
||||||
|
if (vidx_reverse != -1) vinput_arr[vidx_reverse] = NULL;
|
||||||
|
BM_vert_kill(bm, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_freeN(vert_reverse_lookup);
|
||||||
|
|
||||||
|
MEM_freeN(earray);
|
||||||
|
|
||||||
|
|
||||||
|
/* --- 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 (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(weight_elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit)
|
||||||
|
{
|
||||||
|
int vinput_len;
|
||||||
|
int einput_len;
|
||||||
|
|
||||||
|
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,
|
||||||
|
vinput_arr, vinput_len,
|
||||||
|
einput_arr, einput_len);
|
||||||
|
|
||||||
|
MEM_freeN(vinput_arr);
|
||||||
|
MEM_freeN(einput_arr);
|
||||||
|
}
|
@ -477,182 +477,14 @@ void dummy_exec(BMesh *bm, BMOperator *op)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Limited Dissolve */
|
/* Limited Dissolve */
|
||||||
|
|
||||||
#define UNIT_TO_ANGLE DEG2RADF(90.0f)
|
|
||||||
#define ANGLE_TO_UNIT (1.0f / UNIT_TO_ANGLE)
|
|
||||||
|
|
||||||
/* multiply vertex edge angle by face angle
|
|
||||||
* this means we are not left with sharp corners between _almost_ planer faces
|
|
||||||
* convert angles [0-PI/2] -> [0-1], multiply together, then convert back to radians. */
|
|
||||||
static float bm_vert_edge_face_angle(BMVert *v)
|
|
||||||
{
|
|
||||||
const float angle = BM_vert_calc_edge_angle(v);
|
|
||||||
/* note: could be either edge, it doesn't matter */
|
|
||||||
if (v->e && BM_edge_is_manifold(v->e)) {
|
|
||||||
return ((angle * ANGLE_TO_UNIT) * (BM_edge_calc_face_angle(v->e) * ANGLE_TO_UNIT)) * UNIT_TO_ANGLE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return angle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef UNIT_TO_ANGLE
|
|
||||||
#undef ANGLE_TO_UNIT
|
|
||||||
|
|
||||||
typedef struct DissolveElemWeight {
|
|
||||||
BMHeader *ele;
|
|
||||||
float weight;
|
|
||||||
} DissolveElemWeight;
|
|
||||||
|
|
||||||
static int dissolve_elem_cmp(const void *a1, const void *a2)
|
|
||||||
{
|
|
||||||
const struct DissolveElemWeight *d1 = a1, *d2 = a2;
|
|
||||||
|
|
||||||
if (d1->weight > d2->weight) return 1;
|
|
||||||
else if (d1->weight < d2->weight) return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
|
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
|
||||||
{
|
{
|
||||||
BMOpSlot *einput = BMO_slot_get(op, "edges");
|
BMOpSlot *einput = BMO_slot_get(op, "edges");
|
||||||
BMOpSlot *vinput = BMO_slot_get(op, "verts");
|
BMOpSlot *vinput = BMO_slot_get(op, "verts");
|
||||||
const float angle_max = (float)M_PI / 2.0f;
|
const float angle_max = (float)M_PI / 2.0f;
|
||||||
const float angle_limit = minf(angle_max, BMO_slot_float_get(op, "angle_limit"));
|
const float angle_limit = minf(angle_max, BMO_slot_float_get(op, "angle_limit"));
|
||||||
DissolveElemWeight *weight_elems = MEM_mallocN(MAX2(einput->len, vinput->len) *
|
|
||||||
sizeof(DissolveElemWeight), __func__);
|
|
||||||
int i, tot_found;
|
|
||||||
|
|
||||||
BMIter iter;
|
BM_mesh_decimate_dissolve_ex(bm, angle_limit,
|
||||||
BMEdge *e_iter;
|
vinput->data.p, vinput->len,
|
||||||
BMEdge **earray;
|
einput->data.p, einput->len);
|
||||||
|
|
||||||
int *vert_reverse_lookup;
|
|
||||||
|
|
||||||
BMEdge **einput_arr = (BMEdge **)einput->data.p;
|
|
||||||
BMVert **vinput_arr = (BMVert **)vinput->data.p;
|
|
||||||
|
|
||||||
/* --- first edges --- */
|
|
||||||
|
|
||||||
/* wire -> tag */
|
|
||||||
BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
|
|
||||||
BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* go through and split edge */
|
|
||||||
for (i = 0, tot_found = 0; i < einput->len; i++) {
|
|
||||||
BMEdge *e = einput_arr[i];
|
|
||||||
const float angle = BM_edge_calc_face_angle(e);
|
|
||||||
|
|
||||||
if (angle < angle_limit) {
|
|
||||||
tot_found++;
|
|
||||||
}
|
|
||||||
weight_elems[i].ele = (BMHeader *)e;
|
|
||||||
weight_elems[i].weight = angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tot_found != 0) {
|
|
||||||
qsort(weight_elems, einput->len, sizeof(DissolveElemWeight), dissolve_elem_cmp);
|
|
||||||
|
|
||||||
for (i = 0; i < tot_found; i++) {
|
|
||||||
BMEdge *e = (BMEdge *)weight_elems[i].ele;
|
|
||||||
|
|
||||||
if (/* may have become non-manifold */
|
|
||||||
BM_edge_is_manifold(e) &&
|
|
||||||
/* check twice because cumulative effect could dissolve over angle limit */
|
|
||||||
(BM_edge_calc_face_angle(e) < angle_limit))
|
|
||||||
{
|
|
||||||
BMFace *nf = BM_faces_join_pair(bm, e->l->f,
|
|
||||||
e->l->radial_next->f,
|
|
||||||
e,
|
|
||||||
FALSE); /* join faces */
|
|
||||||
|
|
||||||
/* there may be some errors, we don't mind, just move on */
|
|
||||||
if (nf) {
|
|
||||||
BM_face_normal_update(nf);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BMO_error_clear(bm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare for cleanup */
|
|
||||||
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
|
||||||
vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
|
|
||||||
fill_vn_i(vert_reverse_lookup, bm->totvert, -1);
|
|
||||||
for (i = 0, tot_found = 0; i < vinput->len; i++) {
|
|
||||||
BMVert *v = vinput_arr[i];
|
|
||||||
vert_reverse_lookup[BM_elem_index_get(v)] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- cleanup --- */
|
|
||||||
earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__);
|
|
||||||
BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) {
|
|
||||||
earray[i] = e_iter;
|
|
||||||
}
|
|
||||||
/* remove all edges/verts left behind from dissolving, NULL'ing the vertex array so we dont re-use */
|
|
||||||
for (i = bm->totedge - 1; i != -1; i--) {
|
|
||||||
e_iter = earray[i];
|
|
||||||
|
|
||||||
if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == FALSE)) {
|
|
||||||
/* edge has become wire */
|
|
||||||
int vidx_reverse;
|
|
||||||
BMVert *v1 = e_iter->v1;
|
|
||||||
BMVert *v2 = e_iter->v2;
|
|
||||||
BM_edge_kill(bm, e_iter);
|
|
||||||
if (v1->e == NULL) {
|
|
||||||
vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)];
|
|
||||||
if (vidx_reverse != -1) vinput_arr[vidx_reverse] = NULL;
|
|
||||||
BM_vert_kill(bm, v1);
|
|
||||||
}
|
|
||||||
if (v2->e == NULL) {
|
|
||||||
vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)];
|
|
||||||
if (vidx_reverse != -1) vinput_arr[vidx_reverse] = NULL;
|
|
||||||
BM_vert_kill(bm, v2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MEM_freeN(vert_reverse_lookup);
|
|
||||||
|
|
||||||
MEM_freeN(earray);
|
|
||||||
|
|
||||||
|
|
||||||
/* --- 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 (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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MEM_freeN(weight_elems);
|
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,9 @@ typedef struct DecimateModifierData {
|
|||||||
ModifierData modifier;
|
ModifierData modifier;
|
||||||
|
|
||||||
float percent; /* (mode == MOD_DECIM_MODE_COLLAPSE) */
|
float percent; /* (mode == MOD_DECIM_MODE_COLLAPSE) */
|
||||||
int iter; /* (mode == MOD_DECIM_MODE_UNSUBDIV) */
|
short iter; /* (mode == MOD_DECIM_MODE_UNSUBDIV) */
|
||||||
|
short pad;
|
||||||
|
float angle; /* (mode == MOD_DECIM_MODE_DISSOLVE) */
|
||||||
|
|
||||||
char defgrp_name[64]; /* MAX_VGROUP_NAME */
|
char defgrp_name[64]; /* MAX_VGROUP_NAME */
|
||||||
short flag, mode;
|
short flag, mode;
|
||||||
@ -377,7 +379,8 @@ enum {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
MOD_DECIM_MODE_COLLAPSE,
|
MOD_DECIM_MODE_COLLAPSE,
|
||||||
MOD_DECIM_MODE_UNSUBDIV
|
MOD_DECIM_MODE_UNSUBDIV,
|
||||||
|
MOD_DECIM_MODE_DISSOLVE /* called planar in the UI */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Smooth modifier flags */
|
/* Smooth modifier flags */
|
||||||
|
@ -1113,6 +1113,7 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
|
|||||||
static EnumPropertyItem modifier_decim_mode_items[] = {
|
static EnumPropertyItem modifier_decim_mode_items[] = {
|
||||||
{MOD_DECIM_MODE_COLLAPSE, "COLLAPSE", 0, "Collapse", "Use edge collapsing"},
|
{MOD_DECIM_MODE_COLLAPSE, "COLLAPSE", 0, "Collapse", "Use edge collapsing"},
|
||||||
{MOD_DECIM_MODE_UNSUBDIV, "UNSUBDIV", 0, "Un-Subdivide", "Use un-subdivide face reduction"},
|
{MOD_DECIM_MODE_UNSUBDIV, "UNSUBDIV", 0, "Un-Subdivide", "Use un-subdivide face reduction"},
|
||||||
|
{MOD_DECIM_MODE_DISSOLVE, "DISSOLVE", 0, "Planar", "Dissolve geometry to form planar polygons"},
|
||||||
{0, NULL, 0, NULL, NULL}
|
{0, NULL, 0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1130,20 +1131,31 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
|
|||||||
RNA_def_property_ui_text(prop, "Mode", "");
|
RNA_def_property_ui_text(prop, "Mode", "");
|
||||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* (mode == MOD_DECIM_MODE_COLLAPSE) */
|
||||||
prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE);
|
prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE);
|
||||||
RNA_def_property_float_sdna(prop, NULL, "percent");
|
RNA_def_property_float_sdna(prop, NULL, "percent");
|
||||||
RNA_def_property_range(prop, 0, 1);
|
RNA_def_property_range(prop, 0, 1);
|
||||||
RNA_def_property_ui_range(prop, 0, 1, 1, 4);
|
RNA_def_property_ui_range(prop, 0, 1, 1, 4);
|
||||||
RNA_def_property_ui_text(prop, "Ratio", "Ratio of triangles to reduce to");
|
RNA_def_property_ui_text(prop, "Ratio", "Ratio of triangles to reduce to (collapse only)");
|
||||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* (mode == MOD_DECIM_MODE_UNSUBDIV) */
|
||||||
prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_UNSIGNED);
|
prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_UNSIGNED);
|
||||||
RNA_def_property_int_sdna(prop, NULL, "iter");
|
RNA_def_property_int_sdna(prop, NULL, "iter");
|
||||||
RNA_def_property_range(prop, 0, SHRT_MAX);
|
RNA_def_property_range(prop, 0, SHRT_MAX);
|
||||||
RNA_def_property_ui_range(prop, 1, 100, 1, 0);
|
RNA_def_property_ui_range(prop, 1, 100, 1, 0);
|
||||||
RNA_def_property_ui_text(prop, "Iterations", "Number of times to unsubdivide");
|
RNA_def_property_ui_text(prop, "Iterations", "Number of times reduce the geometry (unsubdivide only)");
|
||||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* (mode == MOD_DECIM_MODE_DISSOLVE) */
|
||||||
|
prop = RNA_def_property(srna, "angle_limit", PROP_FLOAT, PROP_ANGLE);
|
||||||
|
RNA_def_property_float_sdna(prop, NULL, "angle");
|
||||||
|
RNA_def_property_range(prop, 0, DEG2RAD(180));
|
||||||
|
RNA_def_property_ui_range(prop, 0, DEG2RAD(180), 100, 2);
|
||||||
|
RNA_def_property_ui_text(prop, "Angle Limit", "Only dissolve angles below this(planar/dissolve only)");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* (mode == MOD_DECIM_MODE_COLLAPSE) */
|
||||||
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
|
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
|
||||||
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
|
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
|
||||||
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name");
|
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name");
|
||||||
@ -1154,7 +1166,9 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
|
|||||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_INVERT_VGROUP);
|
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_INVERT_VGROUP);
|
||||||
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
|
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
|
||||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
/* end collapse-only option */
|
||||||
|
|
||||||
|
/* all modes use this */
|
||||||
prop = RNA_def_property(srna, "face_count", PROP_INT, PROP_NONE);
|
prop = RNA_def_property(srna, "face_count", PROP_INT, PROP_NONE);
|
||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_ui_text(prop, "Face Count", "The current number of faces in the decimated mesh");
|
RNA_def_property_ui_text(prop, "Face Count", "The current number of faces in the decimated mesh");
|
||||||
|
@ -64,6 +64,7 @@ static void initData(ModifierData *md)
|
|||||||
DecimateModifierData *dmd = (DecimateModifierData *) md;
|
DecimateModifierData *dmd = (DecimateModifierData *) md;
|
||||||
|
|
||||||
dmd->percent = 1.0;
|
dmd->percent = 1.0;
|
||||||
|
dmd->angle = DEG2RADF(15.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyData(ModifierData *md, ModifierData *target)
|
static void copyData(ModifierData *md, ModifierData *target)
|
||||||
@ -73,6 +74,7 @@ static void copyData(ModifierData *md, ModifierData *target)
|
|||||||
|
|
||||||
tdmd->percent = dmd->percent;
|
tdmd->percent = dmd->percent;
|
||||||
tdmd->iter = dmd->iter;
|
tdmd->iter = dmd->iter;
|
||||||
|
tdmd->angle = dmd->angle;
|
||||||
BLI_strncpy(tdmd->defgrp_name, dmd->defgrp_name, sizeof(tdmd->defgrp_name));
|
BLI_strncpy(tdmd->defgrp_name, dmd->defgrp_name, sizeof(tdmd->defgrp_name));
|
||||||
tdmd->flag = dmd->flag;
|
tdmd->flag = dmd->flag;
|
||||||
tdmd->mode = dmd->mode;
|
tdmd->mode = dmd->mode;
|
||||||
@ -149,9 +151,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
|
|||||||
case MOD_DECIM_MODE_UNSUBDIV:
|
case MOD_DECIM_MODE_UNSUBDIV:
|
||||||
BM_mesh_decimate_unsubdivide(bm, dmd->iter);
|
BM_mesh_decimate_unsubdivide(bm, dmd->iter);
|
||||||
break;
|
break;
|
||||||
|
case MOD_DECIM_MODE_DISSOLVE:
|
||||||
|
BM_mesh_decimate_dissolve(bm, dmd->angle);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (vweights) {
|
if (vweights) {
|
||||||
MEM_freeN(vweights);
|
MEM_freeN(vweights);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user