[Bf-blender-cvs] [94e211ced91] master: Fix T100874: improve uv unwrap of degenerate geometry

Chris Blackbourn noreply at git.blender.org
Mon Sep 12 04:29:19 CEST 2022


Commit: 94e211ced914faff7c1f8d0f68209038afa974bf
Author: Chris Blackbourn
Date:   Mon Sep 12 12:58:14 2022 +1200
Branches: master
https://developer.blender.org/rB94e211ced914faff7c1f8d0f68209038afa974bf

Fix T100874: improve uv unwrap of degenerate geometry

Provide reasonable defaults for UV unwrap for triangles with zero area:

* Three vertices are arranged in a line.
* Two vertices are at the same 3D location.
* All three vertices are at the same 3D location.

Change fixes quads / ngons which have triangulations with zero area.

Change fixes both "Angle Based" method and "Conformal" method.

Differential Revision: https://developer.blender.org/D15922

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

M	source/blender/geometry/intern/uv_parametrizer.cc

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

diff --git a/source/blender/geometry/intern/uv_parametrizer.cc b/source/blender/geometry/intern/uv_parametrizer.cc
index 4f763b09bef..f074febe23a 100644
--- a/source/blender/geometry/intern/uv_parametrizer.cc
+++ b/source/blender/geometry/intern/uv_parametrizer.cc
@@ -307,12 +307,70 @@ static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2
 {
   return angle_v2v2v2(v1, v2, v3);
 }
+
+/* Angles close to 0 or 180 degrees cause rows filled with zeros in the linear_solver.
+ * The matrix will then be rank deficient and / or have poor conditioning.
+ * => Reduce the maximum angle to 179 degrees, and spread the remainder to the other angles.
+ */
+static void fix_large_angle(const float v_fix[3],
+                            const float v1[3],
+                            const float v2[3],
+                            float *r_fix,
+                            float *r_a1,
+                            float *r_a2)
+{
+  const float max_angle = (float)M_PI * (179.0f / 180.0f);
+  const float fix_amount = *r_fix - max_angle;
+  if (fix_amount < 0.0f) {
+    return; /* angle is reasonable, i.e. less than 179 degrees. */
+  }
+
+  /* The triangle is probably degenerate, or close to it.
+   * Without loss of generality, transform the triangle such that
+   *   v_fix == {  0, s}, *r_fix = 180 degrees
+   *   v1    == {-x1, 0}, *r_a1  = 0
+   *   v2    == { x2, 0}, *r_a2  = 0
+   *
+   * With `s = 0`, `x1 > 0`, `x2 > 0`
+   *
+   * Now make `s` a small number and do some math:
+   *  tan(*r_a1) = s / x1
+   *  tan(*r_a2) = s / x2
+   *
+   * Remember that `tan = sin / cos`, `sin(s) ~= s` and `cos(s) = 1`
+   *
+   * Rearrange to obtain:
+   *  *r_a1 = fix_amount * x2 / (x1 + x2)
+   *  *r_a2 = fix_amount * x1 / (x1 + x2)
+   */
+
+  const float dist_v1 = len_v3v3(v_fix, v1);
+  const float dist_v2 = len_v3v3(v_fix, v2);
+  const float sum = dist_v1 + dist_v2;
+  const float weight = (sum > 1e-20f) ? dist_v2 / sum : 0.5f;
+
+  /* Ensure sum of angles in triangle is unchanged. */
+  *r_fix -= fix_amount;
+  *r_a1 += fix_amount * weight;
+  *r_a2 += fix_amount * (1.0f - weight);
+}
+
 static void p_triangle_angles(
     const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3)
 {
   *r_a1 = p_vec_angle(v3, v1, v2);
   *r_a2 = p_vec_angle(v1, v2, v3);
-  *r_a3 = (float)M_PI - *r_a2 - *r_a1;
+  *r_a3 = p_vec_angle(v2, v3, v1);
+
+  /* Fix for degenerate geometry e.g. v1 = sum(v2 + v3). See T100874 */
+  fix_large_angle(v1, v2, v3, r_a1, r_a2, r_a3);
+  fix_large_angle(v2, v3, v1, r_a2, r_a3, r_a1);
+  fix_large_angle(v3, v1, v2, r_a3, r_a1, r_a2);
+
+  /* Workaround for degenerate geometry, e.g. v1 == v2 == v3. */
+  *r_a1 = max_ff(*r_a1, 0.001f);
+  *r_a2 = max_ff(*r_a2, 0.001f);
+  *r_a3 = max_ff(*r_a3, 0.001f);
 }
 
 static void p_face_angles(PFace *f, float *r_a1, float *r_a2, float *r_a3)
@@ -2266,7 +2324,6 @@ using PAbfSystem = struct PAbfSystem {
   float *bAlpha, *bTriangle, *bInterior;
   float *lambdaTriangle, *lambdaPlanar, *lambdaLength;
   float (*J2dt)[3], *bstar, *dstar;
-  float minangle, maxangle;
 };
 
 static void p_abf_setup_system(PAbfSystem *sys)
@@ -2294,9 +2351,6 @@ static void p_abf_setup_system(PAbfSystem *sys)
   for (i = 0; i < sys->ninterior; i++) {
     sys->lambdaLength[i] = 1.0;
   }
-
-  sys->minangle = 1.0 * M_PI / 180.0;
-  sys->maxangle = (float)M_PI - sys->minangle;
 }
 
 static void p_abf_free_system(PAbfSystem *sys)
@@ -2707,25 +2761,6 @@ static bool p_chart_abf_solve(PChart *chart)
     e3 = e2->next;
     p_face_angles(f, &a1, &a2, &a3);
 
-    if (a1 < sys.minangle) {
-      a1 = sys.minangle;
-    }
-    else if (a1 > sys.maxangle) {
-      a1 = sys.maxangle;
-    }
-    if (a2 < sys.minangle) {
-      a2 = sys.minangle;
-    }
-    else if (a2 > sys.maxangle) {
-      a2 = sys.maxangle;
-    }
-    if (a3 < sys.minangle) {
-      a3 = sys.minangle;
-    }
-    else if (a3 > sys.maxangle) {
-      a3 = sys.maxangle;
-    }
-
     sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1;
     sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2;
     sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3;



More information about the Bf-blender-cvs mailing list