[Bf-blender-cvs] [984cd552f00] master: Fix T56625: Bevel sometimes made zero area UV faces.

Howard Trickey noreply at git.blender.org
Fri Apr 22 17:35:03 CEST 2022


Commit: 984cd552f0033c674b3cef6ec55d1facdcb81c2d
Author: Howard Trickey
Date:   Fri Apr 22 09:26:34 2022 -0400
Branches: master
https://developer.blender.org/rB984cd552f0033c674b3cef6ec55d1facdcb81c2d

Fix T56625: Bevel sometimes made zero area UV faces.

This substantially redoes the logic by which bevel chooses, for
the middle segment when there are an odd number of segments,
which face to interpolate in, and which vertices to snap to which
edges before doing that interpolation. It changes the UV layouts
of a number of the regression tests, for the better.
An example, in the reference bug, is a cube with all seams, unwrapped
and then packed with some margin around them, now looks much
better in UV space when there are an odd number of segments.

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

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

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

diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index be5521d45ab..ea2cc1c24d6 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -675,7 +675,7 @@ static BMFace *bev_create_ngon(BMesh *bm,
                                const int totv,
                                BMFace **face_arr,
                                BMFace *facerep,
-                               BMEdge **edge_arr,
+                               BMEdge **snap_edge_arr,
                                int mat_nr,
                                bool do_interp)
 {
@@ -699,8 +699,8 @@ static BMFace *bev_create_ngon(BMesh *bm,
         }
         if (interp_f) {
           BMEdge *bme = NULL;
-          if (edge_arr) {
-            bme = edge_arr[i];
+          if (snap_edge_arr) {
+            bme = snap_edge_arr[i];
           }
           float save_co[3];
           if (bme) {
@@ -734,44 +734,6 @@ static BMFace *bev_create_ngon(BMesh *bm,
   return f;
 }
 
-static BMFace *bev_create_quad(BMesh *bm,
-                               BMVert *v1,
-                               BMVert *v2,
-                               BMVert *v3,
-                               BMVert *v4,
-                               BMFace *f1,
-                               BMFace *f2,
-                               BMFace *f3,
-                               BMFace *f4,
-                               int mat_nr)
-{
-  BMVert *varr[4] = {v1, v2, v3, v4};
-  BMFace *farr[4] = {f1, f2, f3, f4};
-  return bev_create_ngon(bm, varr, 4, farr, f1, NULL, mat_nr, true);
-}
-
-static BMFace *bev_create_quad_ex(BMesh *bm,
-                                  BMVert *v1,
-                                  BMVert *v2,
-                                  BMVert *v3,
-                                  BMVert *v4,
-                                  BMFace *f1,
-                                  BMFace *f2,
-                                  BMFace *f3,
-                                  BMFace *f4,
-                                  BMEdge *e1,
-                                  BMEdge *e2,
-                                  BMEdge *e3,
-                                  BMEdge *e4,
-                                  BMFace *frep,
-                                  int mat_nr)
-{
-  BMVert *varr[4] = {v1, v2, v3, v4};
-  BMFace *farr[4] = {f1, f2, f3, f4};
-  BMEdge *earr[4] = {e1, e2, e3, e4};
-  return bev_create_ngon(bm, varr, 4, farr, frep, earr, mat_nr, true);
-}
-
 /* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
 static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2, int layer_index)
 {
@@ -828,6 +790,25 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
   return true;
 }
 
+/**
+ * In array face_component of total totface elements, swap values c1 and c2
+ * whereever they occur.
+ */
+static void swap_face_components(int *face_component, int totface, int c1, int c2)
+{
+  if (c1 == c2) {
+    return; /* Nothing to do. */
+  }
+  for (int f = 0; f < totface; f++) {
+    if (face_component[f] == c1) {
+      face_component[f] = c2;
+    }
+    else if (face_component[f] == c2) {
+      face_component[f] = c1;
+    }
+  }
+}
+
 /*
  * Set up the fields of bp->math_layer_info.
  * We always set has_math_layers to the correct value.
@@ -836,6 +817,7 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
  */
 static void math_layer_info_init(BevelParams *bp, BMesh *bm)
 {
+  int f;
   bp->math_layer_info.has_math_layers = false;
   bp->math_layer_info.face_component = NULL;
   for (int i = 0; i < bm->ldata.totlayer; i++) {
@@ -860,12 +842,12 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
   bool *in_stack = MEM_malloc_arrayN(totface, sizeof(bool), __func__);
 
   /* Set all component ids by DFS from faces with unassigned components. */
-  for (int f = 0; f < totface; f++) {
+  for (f = 0; f < totface; f++) {
     face_component[f] = -1;
     in_stack[f] = false;
   }
   int current_component = -1;
-  for (int f = 0; f < totface; f++) {
+  for (f = 0; f < totface; f++) {
     if (face_component[f] == -1 && !in_stack[f]) {
       int stack_top = 0;
       current_component++;
@@ -910,6 +892,44 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
   }
   MEM_freeN(stack);
   MEM_freeN(in_stack);
+  /* We can usually get more pleasing result if components 0 and 1
+   * are the topmost and bottommost (in z-coordinate) componenets,
+   * so adjust component indices to make that so.
+   */
+  if (current_component <= 0) {
+    return; /* Only one component, so no need to do this. */
+  }
+  BMFace *top_face = NULL;
+  float top_face_z = -1e30f;
+  int top_face_component = -1;
+  BMFace *bot_face = NULL;
+  float bot_face_z = 1e30f;
+  int bot_face_component = -1;
+  for (f = 0; f < totface; f++) {
+    float cent[3];
+    BMFace *bmf = BM_face_at_index(bm, f);
+    BM_face_calc_center_bounds(bmf, cent);
+    float fz = cent[2];
+    if (fz > top_face_z) {
+      top_face_z = fz;
+      top_face = bmf;
+      top_face_component = face_component[f];
+    }
+    if (fz < bot_face_z) {
+      bot_face_z = fz;
+      bot_face = bmf;
+      bot_face_component = face_component[f];
+    }
+  }
+  BLI_assert(top_face != NULL && bot_face != NULL);
+  swap_face_components(face_component, totface, face_component[0], top_face_component);
+  if (bot_face_component != top_face_component) {
+    if (bot_face_component == 0) {
+      /* It was swapped with old top_face_component. */
+      bot_face_component = top_face_component;
+    }
+    swap_face_components(face_component, totface, face_component[1], bot_face_component);
+  }
 }
 
 /**
@@ -3843,8 +3863,8 @@ static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *
  * where ns2 = floor(nseg / 2).
  * But these overlap data from previous and next i: there are some forced equivalences.
  * Let's call these indices the canonical ones: we will just calculate data for these
- *    0 <= j <= ns2, 0 <= k < ns2  (for odd ns2)
- *    0 <= j < ns2, 0 <= k <= ns2  (for even ns2)
+ *    0 <= j <= ns2, 0 <= k <= ns2  (for odd ns)
+ *    0 <= j < ns2, 0 <= k <= ns2  (for even ns)
  *    also (j=ns2, k=ns2) at i=0 (for even ns2)
  * This function returns the canonical one for any i, j, k in [0,n],[0,ns],[0,ns].
  */
@@ -4118,7 +4138,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
   for (int i = 0; i < n_boundary; i++) {
     float co1[3], co2[3], acc[3];
     EdgeHalf *e = bndv->elast;
-    /* Generate tangents. This is hacked together and would ideally be done elsewhere and then only
+    /* Generate tangents. This is hacked together and would ideally be done elsewere and then only
      * used here. */
     float tangent[3], tangent2[3], normal[3];
     bool convex = true;
@@ -4185,7 +4205,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
       sub_v3_v3v3(co1, mesh_vert(vm_in, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 1)->co);
       sub_v3_v3v3(co2, mesh_vert(vm_in, i, 0, 1)->co, mesh_vert(vm_in, i, 0, 2)->co);
       cross_v3_v3v3(tangent, co1, co2);
-      /** The following constant is chosen to best match the old results. */
+      /** The following constant is choosen to best match the old results. */
       normalize_v3_length(tangent, 1.5f / ns_out);
     }
     /** Copy corner vertex. */
@@ -4799,46 +4819,85 @@ static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2)
   return e2;
 }
 
-/* Snap co to the closest edge of face f. Return the edge in *r_snap_e,
- * the coordinates of snap point in r_ snap_co,
- * and the distance squared to the snap point as function return */
-static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, float *r_snap_co)
+/**
+ * Find which BoundVerts of \a bv are internal to face \a f.
+ * That is, when both the face and the point are projected to 2d,
+ * the point is on the boundary of or inside the projected face.
+ * There can only be up to three of then, since, including miters,
+ * that is the maximum number of BoundVerts that can be between two edges.
+ * Return the number of face-internal vertices found.
+ */
+static int find_face_internal_boundverts(const BevVert *bv,
+                                         const BMFace *f,
+                                         BoundVert *(r_internal[3]))
 {
-  BMEdge *beste = NULL;
-  float beste_d2 = 1e20f;
-  BMIter iter;
-  BMEdge *e;
-  BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
-    float closest[3];
-    closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co);
-    float d2 = len_squared_v3v3(closest, co);
-    if (d2 < beste_d2) {
-      beste_d2 = d2;
-      beste = e;
-      copy_v3_v3(r_snap_co, closest);
+  if (f == NULL) {
+    return 0;
+  }
+  int n_internal = 0;
+  VMesh *vm = bv->vmesh;
+  BLI_assert(vm != NULL);
+  BoundVert *v = vm->boundstart;
+  do {
+    /* Possible speedup: do the matrix projection done by the following
+     * once, outside the loop, or even better, cache it if ever done
+     * in the course of Bevel. */
+    if (BM_face_point_inside_test(f, v->nv.co)) {
+      r_internal[n_internal++] = v;
+      if (n_internal == 3) {
+        break;
+      }
     }
+  } while ((v = v->next) != vm->boundstart);
+  for (int i = n_internal; i < 3; i++) {
+    r_internal[i] = NULL;
   }
-  *r_snap_e = beste;
-  return beste_d2;
+  return n_internal;
 }
 
-/* What would be the area of the polygon around bv if interpolated in face frep?
+/**
+ * Find where the coordinates of the BndVerts in \a bv should snap to in face \a f.
+ * Face \a f should contain vertex `bv->v`.
+ * Project the snapped verts to 2d, then return the area of the resulting polygon.
+ * Usually one BndVert is inside the face, sometimes up to 3 (if there are miters),
+ * so don't snap those to an edge; all the rest snap to one of the edges of \a bmf
+ * incident on `bv->v`.
  */
-static float interp_poly_area(BevVert *bv, BMFace *frep)
+static float projected_boundary_area(BevVert *bv, BMFace *f)
 {
+  BMEdge *e1, *e2;
   VMesh *vm = bv->vmesh;
-
+  float(*proj_co)[2] = BLI_array_alloca(proj_co, vm->cou

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list