Sculpt dyntopo
* Non-manifold "fins" are now detected and automatically deleted. * Fixed compile error on linux.
This commit is contained in:
parent
bb1096f475
commit
9f3bafc4ab
|
@ -161,7 +161,6 @@ static void pbvh_bmesh_verify(PBVH *pbvh);
|
|||
|
||||
struct EdgeQueueContext;
|
||||
|
||||
static bool check_for_flaps(PBVH *pbvh, BMVert *v);
|
||||
static bool check_face_is_tri(PBVH *pbvh, BMFace *f);
|
||||
static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v);
|
||||
static void pbvh_split_edges(struct EdgeQueueContext *eq_ctx,
|
||||
|
@ -2205,121 +2204,192 @@ static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool check_for_flaps(PBVH *pbvh, BMVert *v)
|
||||
static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
|
||||
{
|
||||
const int updateflag = DYNVERT_NEED_VALENCE | DYNVERT_NEED_DISK_SORT | DYNVERT_NEED_BOUNDARY;
|
||||
static int max_faces = 64;
|
||||
BMFace **stack = NULL;
|
||||
BLI_array_staticdeclare(stack, 32);
|
||||
|
||||
bool ret = false;
|
||||
BMLoop *l = e_root->l;
|
||||
BMLoop **ls = NULL;
|
||||
BMFace **fs = NULL;
|
||||
BLI_array_staticdeclare(ls, 5);
|
||||
int minfs = INT_MAX;
|
||||
|
||||
if (!v->e) {
|
||||
if (!l) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BMEdge *e = v->e;
|
||||
BMEdge *enext;
|
||||
do {
|
||||
enext = BM_DISK_EDGE_NEXT(e, v);
|
||||
BLI_array_append(ls, l);
|
||||
} while ((l = l->radial_next) != e_root->l);
|
||||
|
||||
BMLoop *l = e->l;
|
||||
BMLoop *lnext;
|
||||
for (int i = 0; i < BLI_array_len(ls); i++) {
|
||||
SmallHash visit;
|
||||
BLI_smallhash_init(&visit);
|
||||
|
||||
bool ok = !l;
|
||||
ok = ok || (l == l->radial_next->radial_next);
|
||||
BMLoop *l = ls[i];
|
||||
BMFace *f = l->f;
|
||||
BMFace **fs2 = NULL;
|
||||
BLI_array_staticdeclare(fs2, 32);
|
||||
|
||||
if (false) { //! l) {
|
||||
BMVert *v2 = BM_edge_other_vert(e, v);
|
||||
BLI_array_clear(stack);
|
||||
BLI_array_append(stack, f);
|
||||
BLI_array_append(fs2, f);
|
||||
|
||||
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
|
||||
mv1->flag |= updateflag;
|
||||
BLI_smallhash_insert(&visit, (uintptr_t)f, NULL);
|
||||
|
||||
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v2);
|
||||
mv2->flag |= updateflag;
|
||||
bool bad = false;
|
||||
|
||||
BM_log_edge_removed(pbvh->bm_log, e);
|
||||
BM_edge_kill(pbvh->bm, e);
|
||||
while (BLI_array_len(stack) > 0) {
|
||||
f = BLI_array_pop(stack);
|
||||
BMLoop *l = f->l_first;
|
||||
|
||||
#if 0
|
||||
if (!v2->e) {
|
||||
pbvh_bmesh_vert_remove(pbvh, v2);
|
||||
BM_log_vert_removed(pbvh->bm_log, v2, pbvh->cd_vert_mask_offset);
|
||||
BM_vert_kill(pbvh->bm, v2);
|
||||
}
|
||||
#endif
|
||||
do {
|
||||
if (l->radial_next == l || l->radial_next->radial_next != l) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!v->e) {
|
||||
void **val = NULL;
|
||||
BMFace *f2 = l->radial_next->f;
|
||||
|
||||
if (!BLI_smallhash_ensure_p(&visit, (uintptr_t)f2, &val)) {
|
||||
if (BLI_array_len(fs2) > max_faces) {
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
|
||||
*val = NULL;
|
||||
BLI_array_append(stack, f2);
|
||||
BLI_array_append(fs2, f2);
|
||||
}
|
||||
} while ((l = l->next) != f->l_first);
|
||||
|
||||
if (bad) {
|
||||
break;
|
||||
}
|
||||
|
||||
enext = BM_DISK_EDGE_NEXT(v->e, v);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
continue;
|
||||
if (!bad && BLI_array_len(fs2) < minfs) {
|
||||
minfs = BLI_array_len(fs2);
|
||||
fs = BLI_array_alloca(fs, BLI_array_len(fs2));
|
||||
memcpy(fs, fs2, sizeof(*fs) * BLI_array_len(fs2));
|
||||
}
|
||||
|
||||
do {
|
||||
lnext = l->radial_next;
|
||||
BLI_array_free(fs2);
|
||||
BLI_smallhash_release(&visit);
|
||||
}
|
||||
|
||||
bool ok2 = l->f->len == 3;
|
||||
// ok2 = ok2 && l->next->radial_next == l->next;
|
||||
// ok2 = ok2 && l->prev->radial_next == l->prev;
|
||||
int nupdateflag = PBVH_UpdateOtherVerts | PBVH_UpdateDrawBuffers | PBVH_UpdateBB |
|
||||
PBVH_UpdateTriAreas;
|
||||
nupdateflag = nupdateflag | PBVH_UpdateNormals | PBVH_UpdateTris | PBVH_RebuildDrawBuffers;
|
||||
|
||||
if (ok2) {
|
||||
ret = true;
|
||||
printf("destroying non-manifold triangle\n");
|
||||
if (!fs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BMVert *delv = l->prev->v;
|
||||
if (fs) {
|
||||
printf("manifold fin size: %d\n", minfs);
|
||||
const int tag = BM_ELEM_TAG_ALT;
|
||||
|
||||
// pbvh_bmesh_vert_remove(pbvh, delv);
|
||||
// BM_log_vert_removed(pbvh->bm_log, delv, pbvh->cd_vert_mask_offset);
|
||||
for (int i = 0; i < minfs; i++) {
|
||||
BMFace *f = fs[i];
|
||||
|
||||
BMEdge *e1 = l->next->e;
|
||||
BMEdge *e2 = l->prev->e;
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
l->v->head.hflag &= ~tag;
|
||||
l->e->head.hflag &= ~tag;
|
||||
} while ((l = l->next) != f->l_first);
|
||||
}
|
||||
|
||||
pbvh_bmesh_face_remove(pbvh, l->f, true, false, false);
|
||||
BM_face_kill(pbvh->bm, l->f);
|
||||
BMVert **vs = NULL;
|
||||
BLI_array_staticdeclare(vs, 32);
|
||||
|
||||
if (e1 != e && !e1->l) {
|
||||
BM_log_edge_removed(pbvh->bm_log, e1);
|
||||
BM_edge_kill(pbvh->bm, e1);
|
||||
BMEdge **es = NULL;
|
||||
BLI_array_staticdeclare(es, 32);
|
||||
|
||||
for (int i = 0; i < minfs; i++) {
|
||||
BMFace *f = fs[i];
|
||||
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
if (!(l->v->head.hflag & tag)) {
|
||||
l->v->head.hflag |= tag;
|
||||
BLI_array_append(vs, l->v);
|
||||
}
|
||||
|
||||
if (e2 != e && !e2->l) {
|
||||
BM_log_edge_removed(pbvh->bm_log, e2);
|
||||
BM_edge_kill(pbvh->bm, e2);
|
||||
if (!(l->e->head.hflag & tag)) {
|
||||
l->e->head.hflag |= tag;
|
||||
BLI_array_append(es, l->e);
|
||||
}
|
||||
} while ((l = l->next) != f->l_first);
|
||||
}
|
||||
|
||||
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
|
||||
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
|
||||
for (int i = 0; i < minfs; i++) {
|
||||
BMFace *f = fs[i];
|
||||
|
||||
mv1->flag |= updateflag;
|
||||
mv2->flag |= updateflag;
|
||||
|
||||
if (!v->e) { // check that v still has edges left
|
||||
break;
|
||||
}
|
||||
|
||||
// enext might not be valid, reset it
|
||||
enext = BM_DISK_EDGE_NEXT(v->e, v);
|
||||
// return true;
|
||||
int ni = BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
|
||||
if (ni >= 0 && ni < pbvh->totnode) {
|
||||
pbvh->nodes[ni].flag |= nupdateflag;
|
||||
}
|
||||
} while ((l = lnext) != e->l);
|
||||
} while ((e = enext) != v->e);
|
||||
|
||||
return ret;
|
||||
pbvh_bmesh_face_remove(pbvh, f, true, false, false);
|
||||
BM_face_kill(pbvh->bm, f);
|
||||
}
|
||||
|
||||
const int mupdateflag = DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_DISK_SORT | DYNVERT_NEED_VALENCE;
|
||||
|
||||
for (int i = 0; i < BLI_array_len(es); i++) {
|
||||
BMEdge *e = es[i];
|
||||
|
||||
if (!e->l) {
|
||||
BM_log_edge_removed(pbvh->bm_log, e);
|
||||
BM_edge_kill(pbvh->bm, e);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < BLI_array_len(vs); i++) {
|
||||
BMVert *v = vs[i];
|
||||
|
||||
if (!v->e) {
|
||||
pbvh_bmesh_vert_remove(pbvh, v);
|
||||
|
||||
BM_log_vert_removed(pbvh->bm_log, v, pbvh->cd_vert_mask_offset);
|
||||
BM_vert_kill(pbvh->bm, v);
|
||||
}
|
||||
else {
|
||||
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
|
||||
mv->flag |= mupdateflag;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_array_free(vs);
|
||||
BLI_array_free(es);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_for_flaps_face(PBVH *pbvh, BMFace *f)
|
||||
static bool check_for_fins(PBVH *pbvh, BMVert *v)
|
||||
{
|
||||
BMLoop *l = f->l_first;
|
||||
BMEdge *e = v->e;
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
if (check_for_flaps(pbvh, l->v)) {
|
||||
return true;
|
||||
if (e->l) {
|
||||
BMLoop *l = e->l->f->l_first;
|
||||
|
||||
do {
|
||||
if (l != l->radial_next && l != l->radial_next->radial_next) {
|
||||
if (destroy_nonmanifold_fins(pbvh, e)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while ((l = l->next) != e->l->f->l_first);
|
||||
}
|
||||
} while ((l = l->next) != f->l_first);
|
||||
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -2489,8 +2559,18 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
|
|||
BMEdge **edges = td->edges;
|
||||
for (int j = 0; j < td->totedge; j++) {
|
||||
BMEdge *e = edges[j];
|
||||
|
||||
if (bm_elem_is_free((BMElem *)e, BM_EDGE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
e->head.hflag &= ~BM_ELEM_TAG;
|
||||
|
||||
if (e->l && e->l != e->l->radial_next->radial_next) {
|
||||
// deal with non-manifold iffyness
|
||||
destroy_nonmanifold_fins(pbvh, e);
|
||||
}
|
||||
|
||||
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(cd_dyn_vert, e->v1);
|
||||
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(cd_dyn_vert, e->v2);
|
||||
|
||||
|
@ -3163,6 +3243,10 @@ static bool pbvh_bmesh_subdivide_long_edges(
|
|||
BLI_mempool_free(eq_ctx->pool, pair);
|
||||
pair = NULL;
|
||||
|
||||
if (bm_elem_is_free((BMElem *)v1, BM_VERT) || bm_elem_is_free((BMElem *)v2, BM_VERT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that the edge still exists */
|
||||
if (!(e = BM_edge_exists(v1, v2))) {
|
||||
continue;
|
||||
|
@ -3787,7 +3871,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
}
|
||||
|
||||
#if 0
|
||||
check_for_flaps(pbvh, v_conn);
|
||||
|
||||
e = v_conn->e;
|
||||
if (e) {
|
||||
|
@ -3797,9 +3880,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
|
||||
MDynTopoVert *mv4 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v2);
|
||||
|
||||
if (check_for_flaps(pbvh, v2)) {
|
||||
break;
|
||||
}
|
||||
} while ((e = enext) != v_conn->e);
|
||||
}
|
||||
#endif
|
||||
|
@ -4455,6 +4535,11 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
|
|||
}
|
||||
|
||||
BMVert *v = ectx->val34_verts[vi];
|
||||
|
||||
if (bm_elem_is_free((BMElem *)v, BM_VERT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int n = BM_ELEM_CD_GET_INT(v, cd_vert_node);
|
||||
|
||||
if (n == DYNTOPO_NODE_NONE) {
|
||||
|
@ -4465,6 +4550,10 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (check_for_fins(pbvh, v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
|
||||
|
||||
mv->flag &= ~DYNVERT_VALENCE_TEMP;
|
||||
|
@ -4797,16 +4886,12 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
|
|||
pbvh_kill_vert(pbvh, v);
|
||||
|
||||
if (f1 && !bm_elem_is_free((BMElem *)f1, BM_FACE)) {
|
||||
check_for_flaps_face(pbvh, f1);
|
||||
|
||||
if (!bm_elem_is_free((BMElem *)f1, BM_FACE)) {
|
||||
check_face_is_manifold(pbvh, pbvh->bm, f1);
|
||||
}
|
||||
}
|
||||
|
||||
if (f2 && !bm_elem_is_free((BMElem *)f2, BM_FACE)) {
|
||||
check_for_flaps_face(pbvh, f2);
|
||||
|
||||
if (!bm_elem_is_free((BMElem *)f2, BM_FACE)) {
|
||||
check_face_is_manifold(pbvh, pbvh->bm, f2);
|
||||
}
|
||||
|
@ -5241,7 +5326,7 @@ typedef struct EdgeQueueContext {
|
|||
printf("collapse max_steps %d\n", max_steps);
|
||||
#endif
|
||||
|
||||
printf("max_steps %d\n", max_steps);
|
||||
// printf("max_steps %d\n", max_steps);
|
||||
pbvh_bmesh_check_nodes(pbvh);
|
||||
modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, &deleted_faces, max_steps);
|
||||
pbvh_bmesh_check_nodes(pbvh);
|
||||
|
|
|
@ -1413,6 +1413,8 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert,
|
|||
int sharpcount = 0;
|
||||
int seamcount = 0;
|
||||
int fsetcount = 0;
|
||||
int quadcount = 0;
|
||||
|
||||
#if 0
|
||||
struct FaceSetRef {
|
||||
int fset;
|
||||
|
@ -1445,6 +1447,16 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert,
|
|||
}
|
||||
|
||||
if (e->l) {
|
||||
if (e->l != e->l->radial_next) {
|
||||
if (e->l->f->len > 3) {
|
||||
quadcount++;
|
||||
}
|
||||
|
||||
if (e->l->radial_next->f->len > 3) {
|
||||
quadcount++;
|
||||
}
|
||||
}
|
||||
|
||||
int fset = BKE_pbvh_do_fset_symmetry(
|
||||
BM_ELEM_CD_GET_INT(e->l->f, cd_faceset_offset), bound_symmetry, v2->co);
|
||||
|
||||
|
@ -1511,7 +1523,7 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert,
|
|||
}
|
||||
|
||||
mv->valence = val;
|
||||
if (val < 4 && (mv->flag & DYNVERT_BOUNDARY)) {
|
||||
if ((mv->flag & DYNVERT_BOUNDARY) && quadcount >= 3) {
|
||||
mv->flag |= DYNVERT_CORNER;
|
||||
}
|
||||
|
||||
|
|
|
@ -426,7 +426,6 @@ static void bm_log_edge_customdata(
|
|||
|
||||
static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *lf)
|
||||
{
|
||||
#ifdef CUSTOMDATA
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
|
||||
if (!entry || !lf) {
|
||||
|
@ -454,7 +453,6 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
|
|||
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, l->head.data, &lf->customdata[i]);
|
||||
} while ((i++, l = l->next) != f->l_first);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Update a BMLogVert with data from a BMVert */
|
||||
|
@ -2769,26 +2767,26 @@ static int bmlog_entry_memsize(BMLogEntry *entry)
|
|||
int ret = 0;
|
||||
|
||||
if (entry->type == LOG_ENTRY_PARTIAL) {
|
||||
ret += BLI_mempool_get_size(entry->pool_verts);
|
||||
ret += BLI_mempool_get_size(entry->pool_edges);
|
||||
ret += BLI_mempool_get_size(entry->pool_faces);
|
||||
ret += entry->vdata.pool ? BLI_mempool_get_size(entry->vdata.pool) : 0;
|
||||
ret += entry->edata.pool ? BLI_mempool_get_size(entry->edata.pool) : 0;
|
||||
ret += entry->ldata.pool ? BLI_mempool_get_size(entry->ldata.pool) : 0;
|
||||
ret += entry->pdata.pool ? BLI_mempool_get_size(entry->pdata.pool) : 0;
|
||||
ret += (int)BLI_mempool_get_size(entry->pool_verts);
|
||||
ret += (int)BLI_mempool_get_size(entry->pool_edges);
|
||||
ret += (int)BLI_mempool_get_size(entry->pool_faces);
|
||||
ret += entry->vdata.pool ? (int)BLI_mempool_get_size(entry->vdata.pool) : 0;
|
||||
ret += entry->edata.pool ? (int)BLI_mempool_get_size(entry->edata.pool) : 0;
|
||||
ret += entry->ldata.pool ? (int)BLI_mempool_get_size(entry->ldata.pool) : 0;
|
||||
ret += entry->pdata.pool ? (int)BLI_mempool_get_size(entry->pdata.pool) : 0;
|
||||
|
||||
// estimate ghash memory usage
|
||||
ret += BLI_ghash_len(entry->added_verts) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->added_edges) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->added_faces) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->added_verts) * (int)sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->added_edges) * (int)sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->added_faces) * (int)sizeof(void *) * 4;
|
||||
|
||||
ret += BLI_ghash_len(entry->modified_verts) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->modified_edges) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->modified_faces) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->modified_verts) * (int)sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->modified_edges) * (int)sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->modified_faces) * (int)sizeof(void *) * 4;
|
||||
|
||||
ret += BLI_ghash_len(entry->deleted_verts) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->deleted_edges) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->deleted_faces) * sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->deleted_verts) * (int)sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->deleted_edges) * (int)sizeof(void *) * 4;
|
||||
ret += BLI_ghash_len(entry->deleted_faces) * (int)sizeof(void *) * 4;
|
||||
}
|
||||
else if (entry->type == LOG_ENTRY_FULL_MESH) {
|
||||
Mesh *me = entry->full_copy_mesh;
|
||||
|
|
|
@ -375,6 +375,7 @@ static EnumPropertyItem rna_enum_brush_dyntopo_inherit[] = {
|
|||
{DYNTOPO_INHERIT_SPACING, "SPACING", ICON_NONE, "Spacing", ""},
|
||||
{DYNTOPO_CLEANUP, "CLEANUP", ICON_NONE, "Cleanup", ""},
|
||||
{DYNTOPO_INHERIT_DETAIL_SIZE, "DETAIL_SIZE", ICON_NONE, "Detail Size", ""},
|
||||
{DYNTOPO_INHERIT_RADIUS_SCALE, "RADIUS_SCALE", ICON_NONE, "Radius Scale", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue