[Bf-blender-cvs] [e0117df] dyntopo_holes: Sculpt: remove degenerate geometry around holes
Campbell Barton
noreply at git.blender.org
Sun Oct 5 22:23:41 CEST 2014
Commit: e0117df4a7765f874bf8907408957421e70c3b34
Author: Campbell Barton
Date: Sun Oct 5 22:21:26 2014 +0200
Branches: dyntopo_holes
https://developer.blender.org/rBe0117df4a7765f874bf8907408957421e70c3b34
Sculpt: remove degenerate geometry around holes
Remove sharp edges whos faces make low volume tetrahedrons
===================================================================
M source/blender/blenkernel/intern/pbvh_bmesh.c
===================================================================
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 589e996..7154dcb 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -44,6 +44,9 @@
#include <assert.h>
+/* removes skinny areas after making holes (is rather ugly without this) */
+#define USE_HOLE_VOLUME_CLEAN
+
/****************************** Building ******************************/
/* Update node data after splitting */
@@ -569,7 +572,36 @@ static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
edge_queue_insert(eq_ctx, e, -len_sq);
}
-#if 0
+static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
+ BMEdge *e)
+{
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq < eq_ctx->q->limit_len_squared)
+ edge_queue_insert(eq_ctx, e, len_sq);
+}
+
+static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
+ BMFace *f)
+{
+ if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ /* Check each edge of the face */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ long_edge_queue_edge_add(eq_ctx, l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+}
+
+#ifdef USE_HOLE_VOLUME_CLEAN
+
+#define SHARP_THRESHOLD 0.5f
+
+/**
+ * 1.0 == sharp, 0.0 == flat
+ */
static float bm_edge_calc_sharpness(BMEdge *e)
{
if (BM_edge_is_manifold(e)) {
@@ -580,24 +612,48 @@ static float bm_edge_calc_sharpness(BMEdge *e)
e->v1->co,
e->l->radial_next->prev->v->co,
axis);
- return ang / M_PI;
+ return 1.0f - (ang / M_PI);
}
else {
return 1.0f;
}
}
-#endif
-static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+/**
+ * volume weighted by sharpness
+ */
+static float bm_edge_calc_volume_weighted(BMEdge *e)
{
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq < eq_ctx->q->limit_len_squared)
- edge_queue_insert(eq_ctx, e, len_sq);
+ BMLoop *l_a, *l_b;
+
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ BMVert *v1_alt = l_a->prev->v;
+ BMVert *v2_alt = l_b->prev->v;
+ float sharp;
+
+ sharp = bm_edge_calc_sharpness(e);
+
+ if (sharp > SHARP_THRESHOLD) {
+ /* remap from the threshold back to 0-1 */
+ sharp = (sharp - SHARP_THRESHOLD) / (1.0 - SHARP_THRESHOLD);
+ return volume_tetrahedron_v3(e->v1->co, e->v2->co, v1_alt->co, v2_alt->co) / (FLT_EPSILON + (sharp));
+ }
+ }
+
+ return FLT_MAX;
}
-static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void tetrahedron_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
+ BMEdge *e)
+{
+ const float volume = bm_edge_calc_volume_weighted(e);
+ if (volume != FLT_MAX) {
+ edge_queue_insert(eq_ctx, e, volume);
+ }
+}
+
+static void tetrahedron_edge_queue_face_add(EdgeQueueContext *eq_ctx,
+ BMFace *f)
{
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
@@ -606,11 +662,13 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
/* Check each edge of the face */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- long_edge_queue_edge_add(eq_ctx, l_iter->e);
+ tetrahedron_edge_queue_edge_add(eq_ctx, l_iter->e);
} while ((l_iter = l_iter->next) != l_first);
}
}
+#endif /* USE_HOLE_VOLUME_CLEAN */
+
static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
BMFace *f)
{
@@ -706,6 +764,40 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
}
}
+#ifdef USE_HOLE_VOLUME_CLEAN
+static void tetrahedron_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3],
+ float radius)
+{
+ int n;
+
+ eq_ctx->q->heap = BLI_heap_new();
+ eq_ctx->q->center = center;
+ eq_ctx->q->radius_squared = radius * radius;
+ eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+
+ for (n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+
+ /* Check leaf nodes marked for topology update */
+ if ((node->flag & PBVH_Leaf) &&
+ (node->flag & PBVH_UpdateTopology) &&
+ !(node->flag & PBVH_FullyHidden))
+ {
+ GSetIterator gs_iter;
+
+ /* Check each face */
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ tetrahedron_edge_queue_face_add(eq_ctx, f);
+ }
+ }
+ }
+}
+#endif /* USE_HOLE_VOLUME_CLEAN */
+
static void pbvh_bmesh_delete_vert_face(PBVH *bvh, BMVert *v, BMFace *f_del, GSet *deleted_verts, EdgeQueueContext *eq_ctx)
{
BMLoop *l_iter;
@@ -863,7 +955,7 @@ static void close_vert_queue_create(EdgeQueueContext *eq_ctx,
pair[0] = vprev;
pair[1] = vcur;
-#if 1
+#if 0
BLI_heap_insert(eq_ctx->q->heap,
min_ff(len_squared_v3v3(eq_ctx->q->center, vcur->co),
len_squared_v3v3(eq_ctx->q->center, vprev->co)),
@@ -1194,6 +1286,96 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
return any_collapsed;
}
+#ifdef USE_HOLE_VOLUME_CLEAN
+
+static float len_to_tetrahedron_volume(float f)
+{
+ return (f * f * f) / 6.0f;
+}
+
+static bool pbvh_bmesh_collapse_small_tetrahedrons(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ BLI_Buffer *edge_loops,
+ BLI_Buffer *deleted_faces)
+{
+ /* length as a tetrahedron volume, x1.5x to remove more... gives a bit nicer results */
+ float min_volume = len_to_tetrahedron_volume(bvh->bm_min_edge_len) * 1.5f;
+ GSet *deleted_verts;
+ bool any_collapsed = false;
+
+ deleted_verts = BLI_gset_ptr_new("deleted_verts");
+
+ while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
+ BMLoop *l_a, *l_b;
+ BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap);
+ BMVert *v1 = pair[0], *v2 = pair[1];
+ BMEdge *e;
+
+ /* values on either side of the edge */
+ BMLoop *l_adj;
+ BMVert *v1_alt;
+ BMVert *v2_alt;
+ BMEdge *e_alt;
+
+ BLI_mempool_free(eq_ctx->pool, pair);
+ pair = NULL;
+
+ /* Check the verts still exist */
+ if (BLI_gset_haskey(deleted_verts, v1) ||
+ BLI_gset_haskey(deleted_verts, v2))
+ {
+ continue;
+ }
+
+ /* Check that the edge still exists */
+ if (!(e = BM_edge_exists(v1, v2))) {
+ continue;
+ }
+
+ if (!BM_edge_loop_pair(e, &l_a, &l_b)) {
+ continue;
+ }
+
+ v1_alt = l_a->prev->v;
+ v2_alt = l_b->prev->v;
+
+ if (bm_edge_calc_volume_weighted(e) > min_volume) {
+ continue;
+ }
+
+ /* Check that the edge's vertices are still in the PBVH. It's
+ * possible that an edge collapse has deleted adjacent faces
+ * and the node has been split, thus leaving wire edges and
+ * associated vertices. */
+ if ((BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE) ||
+ (BM_ELEM_CD_GET_INT(e->v2, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE))
+ {
+ continue;
+ }
+
+ any_collapsed = true;
+
+ /* Remove all faces adjacent to the edge, we _KNOW_ there are 2! */
+ while ((l_adj = e->l)) {
+ BMFace *f_adj = l_adj->f;
+ pbvh_bmesh_face_remove(bvh, f_adj, eq_ctx->cd_vert_node_offset, eq_ctx->cd_face_node_offset);
+ BM_face_kill(bvh->bm, f_adj);
+ }
+
+ e_alt = BM_edge_create(bvh->bm, v1_alt, v2_alt, NULL, BM_CREATE_NO_DOUBLE);
+
+ pbvh_bmesh_collapse_edge(bvh, e_alt, v1_alt, v2_alt,
+ deleted_verts, edge_loops,
+ deleted_faces, eq_ctx);
+ }
+
+ BLI_gset_free(deleted_verts, NULL);
+
+ return any_collapsed;
+}
+#endif /* USE_HOLE_VOLUME_CLEAN */
+
/************************* Called from pbvh.c *************************/
bool pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
@@ -1241,7 +1423,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
// #define USE_BRIDGE_MERGE_HOLES
/* disallow bridges sharing vertices */
-// #define USE_BRIDGE_STRICT
+#define USE_BRIDGE_STRICT
#define USE_BRIDGE_CLEAN
@@ -1869,6 +2051,21 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
BLI_mempool_destroy(queue_pool);
}
+ /* remove low volume areas (test!) */
+#ifdef USE_HOLE_VOLUME_CLEAN
+ if (mode & PBVH_TopologyGenus) {
+ EdgeQueue q;
+ BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMEdge *),
+ 128, 128, 0);
+ EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+
+ tetrahedron_edge_queue_create(&eq_ctx, bvh, center, radius);
+ pbvh_bmesh_collapse_small_tetrahedrons(&eq_ctx, bvh, &edge_loops, &deleted_faces);
+ BLI_heap_free(q.heap, NULL);
+ BLI_mempool_destroy(queue_pool);
+ }
+#endif
+
if (mode & PBVH_Subdivide) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
More information about the Bf-blender-cvs
mailing list