[Bf-blender-cvs] [d936f6977fe] master: Fix T58571: Limited dissolve ignores boundaries between delimited faces

Campbell Barton noreply at git.blender.org
Sat Feb 15 07:57:01 CET 2020


Commit: d936f6977fedaf5282c368bd32f545a76127770f
Author: Campbell Barton
Date:   Sat Feb 15 17:45:53 2020 +1100
Branches: master
https://developer.blender.org/rBd936f6977fedaf5282c368bd32f545a76127770f

Fix T58571: Limited dissolve ignores boundaries between delimited faces

When a vertex between two edges is being collapsed,
it's important that edges between delimiting faces use the
angle between edges without scaling it down.

While faces with different materials wont ever be merged into a single
face, all the detail between the two faces may be removed.

===================================================================

M	source/blender/bmesh/tools/bmesh_decimate_dissolve.c

===================================================================

diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 010245fa93d..d4bce75d08b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -35,10 +35,21 @@
 
 #define COST_INVALID FLT_MAX
 
+struct DelimitData;
+
+static bool bm_edge_is_delimiter(const BMEdge *e,
+                                 const BMO_Delimit delimit,
+                                 const struct DelimitData *delimit_data);
+static bool bm_vert_is_delimiter(const BMVert *v,
+                                 const BMO_Delimit delimit,
+                                 const struct DelimitData *delimit_data);
+
 /* 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)
+static float bm_vert_edge_face_angle(BMVert *v,
+                                     const BMO_Delimit delimit,
+                                     const struct DelimitData *delimit_data)
 {
 #define UNIT_TO_ANGLE DEG2RADF(90.0f)
 #define ANGLE_TO_UNIT (1.0f / UNIT_TO_ANGLE)
@@ -46,12 +57,18 @@ 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;
+    /* Checking delimited is important here,
+     * otherwise the boundary between two materials for e.g.
+     * will collapse if the faces on either side of the edge have a small angle.
+     *
+     * This way, delimiting edges are treated like boundary edges,
+     * the detail between two delimiting regions won't over-collapse. */
+    if (!bm_vert_is_delimiter(v, delimit, delimit_data)) {
+      return ((angle * ANGLE_TO_UNIT) * (BM_edge_calc_face_angle(v->e) * ANGLE_TO_UNIT)) *
+             UNIT_TO_ANGLE;
+    }
   }
+  return angle;
 
 #undef UNIT_TO_ANGLE
 #undef ANGLE_TO_UNIT
@@ -79,44 +96,76 @@ static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e,
   return true;
 }
 
-static float bm_edge_calc_dissolve_error(const BMEdge *e,
-                                         const BMO_Delimit delimit,
-                                         const struct DelimitData *delimit_data)
+static bool bm_edge_is_delimiter(const BMEdge *e,
+                                 const BMO_Delimit delimit,
+                                 const struct DelimitData *delimit_data)
 {
-  if (!BM_edge_is_manifold(e)) {
-    goto fail;
-  }
-
-  if ((delimit & BMO_DELIM_SEAM) && (BM_elem_flag_test(e, BM_ELEM_SEAM))) {
-    goto fail;
-  }
+  /* Caller must ensure. */
+  BLI_assert(BM_edge_is_manifold(e));
 
-  if ((delimit & BMO_DELIM_SHARP) && (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0)) {
-    goto fail;
-  }
-
-  if ((delimit & BMO_DELIM_MATERIAL) && (e->l->f->mat_nr != e->l->radial_next->f->mat_nr)) {
-    goto fail;
+  if (delimit != 0) {
+    if (delimit & BMO_DELIM_SEAM) {
+      if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
+        return true;
+      }
+    }
+    if (delimit & BMO_DELIM_SHARP) {
+      if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
+        return true;
+      }
+    }
+    if (delimit & BMO_DELIM_MATERIAL) {
+      if (e->l->f->mat_nr != e->l->radial_next->f->mat_nr) {
+        return true;
+      }
+    }
+    if (delimit & BMO_DELIM_NORMAL) {
+      if (!BM_edge_is_contiguous(e)) {
+        return true;
+      }
+    }
+    if (delimit & BMO_DELIM_UV) {
+      if (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0) {
+        return true;
+      }
+    }
   }
 
-  const bool is_contig = BM_edge_is_contiguous(e);
+  return false;
+}
 
-  if ((delimit & BMO_DELIM_NORMAL) && (is_contig == false)) {
-    goto fail;
-  }
+static bool bm_vert_is_delimiter(const BMVert *v,
+                                 const BMO_Delimit delimit,
+                                 const struct DelimitData *delimit_data)
+{
+  BLI_assert(v->e != NULL);
 
-  if ((delimit & BMO_DELIM_UV) && (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0)) {
-    goto fail;
+  if (delimit != 0) {
+    const BMEdge *e, *e_first;
+    e = e_first = v->e;
+    do {
+      if (BM_edge_is_manifold(e)) {
+        if (bm_edge_is_delimiter(e, delimit, delimit_data)) {
+          return true;
+        }
+      }
+    } while ((e = BM_DISK_EDGE_NEXT(e, v)) != e_first);
   }
+  return false;
+}
 
-  float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
-  if (is_contig) {
-    angle_cos_neg *= -1;
+static float bm_edge_calc_dissolve_error(const BMEdge *e,
+                                         const BMO_Delimit delimit,
+                                         const struct DelimitData *delimit_data)
+{
+  if (BM_edge_is_manifold(e) && !bm_edge_is_delimiter(e, delimit, delimit_data)) {
+    float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
+    if (BM_edge_is_contiguous(e)) {
+      angle_cos_neg *= -1;
+    }
+    return angle_cos_neg;
   }
 
-  return angle_cos_neg;
-
-fail:
   return COST_INVALID;
 }
 
@@ -411,7 +460,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm,
     for (i = 0; i < vinput_len; i++) {
       BMVert *v = vinput_arr[i];
       if (LIKELY(v != NULL)) {
-        const float cost = bm_vert_edge_face_angle(v);
+        const float cost = bm_vert_edge_face_angle(v, delimit, &delimit_data);
         vheap_table[i] = BLI_heap_insert(vheap, cost, v);
         BM_elem_index_set(v, i); /* set dirty */
       }
@@ -452,7 +501,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm,
           BM_ITER_ELEM (v_iter, &iter, e_new, BM_VERTS_OF_EDGE) {
             const int j = BM_elem_index_get(v_iter);
             if (j != -1 && vheap_table[j]) {
-              const float cost = bm_vert_edge_face_angle(v_iter);
+              const float cost = bm_vert_edge_face_angle(v_iter, delimit, &delimit_data);
               BLI_heap_node_value_update(vheap, vheap_table[j], cost);
             }
           }
@@ -472,7 +521,8 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm,
                 const int j = BM_elem_index_get(l_cycle_iter->v);
                 if (j != -1 && vheap_table[j] &&
                     (BLI_heap_node_value(vheap_table[j]) == COST_INVALID)) {
-                  const float cost = bm_vert_edge_face_angle(l_cycle_iter->v);
+                  const float cost = bm_vert_edge_face_angle(
+                      l_cycle_iter->v, delimit, &delimit_data);
                   BLI_heap_node_value_update(vheap, vheap_table[j], cost);
                 }
               } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);



More information about the Bf-blender-cvs mailing list