[Bf-blender-cvs] [473be239c3c] master: LineArt: Improve certain edge cases in occlusion

YimingWu noreply at git.blender.org
Wed Nov 17 07:32:28 CET 2021


Commit: 473be239c3c3669643853d549f06723d40b941bb
Author: YimingWu
Date:   Wed Nov 17 14:30:08 2021 +0800
Branches: master
https://developer.blender.org/rB473be239c3c3669643853d549f06723d40b941bb

LineArt: Improve certain edge cases in occlusion

This patch includes:
View vector fix for ortho back face.
Point on segment logic correction.
Better handling of boundary cases.

See review page for detailed description.

Reviewed By: Sebastian Parborg (zeddb)

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

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

M	source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
M	source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
M	source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c

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

diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index d8926a63307..869f93f832e 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -476,11 +476,32 @@ typedef struct LineartBoundingArea {
 #define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
 
 #define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c))
+#define LRT_PABC(index) (index == 0 ? pa : (index == 1 ? pb : pc))
 
+#define DBL_LOOSER 1e-5
+#define LRT_DOUBLE_CLOSE_LOOSER(a, b) (((a) + DBL_LOOSER) >= (b) && ((a)-DBL_LOOSER) <= (b))
 #define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
+#define LRT_DOUBLE_CLOSE_ENOUGH_TRI(a, b) \
+  (((a) + DBL_TRIANGLE_LIM) >= (b) && ((a)-DBL_TRIANGLE_LIM) <= (b))
 
-BLI_INLINE int lineart_LineIntersectTest2d(
-    const double *a1, const double *a2, const double *b1, const double *b2, double *aRatio)
+/* Notes on this function:
+
+ * r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it
+ * fixes the value to zero or one, this makes it easier to identify "on the tip" situations.
+ *
+ * r_aligned: True when 1) a and b is exactly on the same straight line and 2) a and b share a
+ * common end-point.
+ *
+ * Important: if r_aligned is true, r_ratio will be either 0 or 1 depending on which point from
+ * segment a is shared with segment b. If it's a1 then r_ratio is 0, else then r_ratio is 1. This
+ * extra information is needed for line art occlusion stage to work correctly in such cases.
+ */
+BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
+                                         const double *a2,
+                                         const double *b1,
+                                         const double *b2,
+                                         double *r_ratio,
+                                         bool *r_aligned)
 {
 /* Legacy intersection math aligns better with occlusion function quirks. */
 /* #define USE_VECTOR_LINE_INTERSECTION */
@@ -504,27 +525,27 @@ BLI_INLINE int lineart_LineIntersectTest2d(
     double rr;
 
     if (fabs(a2[0] - a1[0]) > fabs(a2[1] - a1[1])) {
-      *aRatio = ratiod(a1[0], a2[0], rx);
+      *r_ratio = ratiod(a1[0], a2[0], rx);
       if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) {
         rr = ratiod(b1[0], b2[0], rx);
       }
       else {
         rr = ratiod(b1[1], b2[1], ry);
       }
-      if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) {
+      if ((*r_ratio) > 0 && (*r_ratio) < 1 && rr > 0 && rr < 1) {
         return 1;
       }
       return 0;
     }
 
-    *aRatio = ratiod(a1[1], a2[1], ry);
+    *r_ratio = ratiod(a1[1], a2[1], ry);
     if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) {
       rr = ratiod(b1[0], b2[0], rx);
     }
     else {
       rr = ratiod(b1[1], b2[1], ry);
     }
-    if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) {
+    if ((*r_ratio) > 0 && (*r_ratio) < 1 && rr > 0 && rr < 1) {
       return 1;
     }
     return 0;
@@ -539,34 +560,62 @@ BLI_INLINE int lineart_LineIntersectTest2d(
   double x_diff = (a2[0] - a1[0]);
   double x_diff2 = (b2[0] - b1[0]);
 
+  *r_aligned = false;
+
   if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff, 0)) {
     if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
-      *aRatio = 0;
+      /* This means two segments are both vertical. */
+      if ((LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b1[1])) ||
+          (LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b2[1]))) {
+        *r_aligned = true;
+        *r_ratio = 1;
+      }
+      else if ((LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b1[1])) ||
+               (LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b2[1]))) {
+        *r_aligned = true;
+        *r_ratio = 0;
+      }
       return 0;
     }
     double r2 = ratiod(b1[0], b2[0], a1[0]);
     x = interpd(b2[0], b1[0], r2);
     y = interpd(b2[1], b1[1], r2);
-    *aRatio = ratio = ratiod(a1[1], a2[1], y);
+    *r_ratio = ratio = ratiod(a1[1], a2[1], y);
   }
   else {
     if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
       ratio = ratiod(a1[0], a2[0], b1[0]);
       x = interpd(a2[0], a1[0], ratio);
-      *aRatio = ratio;
+      *r_ratio = ratio;
     }
     else {
-      k1 = (a2[1] - a1[1]) / x_diff;
-      k2 = (b2[1] - b1[1]) / x_diff2;
-
-      if (k1 == k2)
+      double y_diff = a2[1] - a1[1], y_diff2 = b2[1] - b1[1];
+      k1 = y_diff / x_diff;
+      k2 = y_diff2 / x_diff2;
+
+      if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(k2, k1)) {
+        /* This means two segments are parallel. This also handles k==0 (both completely
+         * horizontal) cases. */
+        if ((LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b1[1])) ||
+            (LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b2[1]))) {
+          *r_aligned = true;
+          *r_ratio = 1;
+        }
+        else if ((LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b1[0]) &&
+                  LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b1[1])) ||
+                 (LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b2[0]) &&
+                  LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b2[1]))) {
+          *r_aligned = true;
+          *r_ratio = 0;
+        }
         return 0;
+      }
 
       x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
 
       ratio = (x - a1[0]) / x_diff;
 
-      *aRatio = ratio;
+      *r_ratio = ratio;
     }
   }
 
@@ -580,6 +629,13 @@ BLI_INLINE int lineart_LineIntersectTest2d(
            (b2[0] < b1[0] && x < b2[0]))
     return 0;
 
+  if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(*r_ratio, 1)) {
+    *r_ratio = 1;
+  }
+  else if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(*r_ratio, 0)) {
+    *r_ratio = 0;
+  }
+
   return 1;
 #endif
 }
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index f3110cf87b6..88dcfb89c25 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -634,6 +634,8 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
       }
     }
   }
+  /* Get rid of those very short "zig-zag" lines that jumps around visibility. */
+  MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM);
   LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) {
     lineart_bounding_area_link_chain(rb, iec);
   }
@@ -890,6 +892,9 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
   float last_point[2];
 
   eci = ec->chain.first;
+  if (!eci) {
+    return 0;
+  }
   copy_v2_v2(last_point, eci->pos);
   for (eci = ec->chain.first; eci; eci = eci->next) {
     dist = len_v2v2(eci->pos, last_point);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 93e9062e910..88d717eb032 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -502,6 +502,10 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
   rb->edge_mark.last = rb->edge_mark.first;
   rb->floating.last = rb->floating.first;
 
+  /* This is needed because the occlusion function expects the camera vector to point towards the
+   * camera. */
+  negate_v3_db(rb->view_vector);
+
   TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
 
   for (i = 0; i < thread_count; i++) {
@@ -567,20 +571,30 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
     return 0;
   }
 
-  if (v1[0] - v0[0]) {
+  if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[0], v0[0])) {
     c1 = ratiod(v0[0], v1[0], v[0]);
   }
-  else if (v[0] == v1[0]) {
-    c2 = ratiod(v0[1], v1[1], v[1]);
-    return (c2 >= 0 && c2 <= 1);
+  else {
+    if (LRT_DOUBLE_CLOSE_ENOUGH(v[0], v1[0])) {
+      c2 = ratiod(v0[1], v1[1], v[1]);
+      return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM);
+    }
+    else {
+      return false;
+    }
   }
 
-  if (v1[1] - v0[1]) {
+  if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) {
     c2 = ratiod(v0[1], v1[1], v[1]);
   }
-  else if (v[1] == v1[1]) {
-    c1 = ratiod(v0[0], v1[0], v[0]);
-    return (c1 >= 0 && c1 <= 1);
+  else {
+    if (LRT_DOUBLE_CLOSE_ENOUGH(v[1], v1[1])) {
+      c1 = ratiod(v0[0], v1[0], v[0]);
+      return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM);
+    }
+    else {
+      return false;
+    }
   }
 
   if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
@@ -1529,7 +1543,7 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
   dot_1 = dot_v3v3_db(view_vector, tri1->gn);
   dot_2 = dot_v3v3_db(view_vector, tri2->gn);
 
-  if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+  if ((result = dot_1 * dot_2) <= 0 && (fabs(dot_1) + fabs(dot_2))) {
     edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
   }
 
@@ -2305,7 +2319,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
   { \
     index = (num < is[order[0]] ? \
                  order[0] : \
-                 (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : order[2]))); \
+                 (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : -1))); \
   }
 
 /* `ia ib ic` are ordered. */
@@ -2313,7 +2327,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
   { \
     index = (num > is[order[2]] ? \
                  order[2] : \
-                 (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : order[0]))); \
+                 (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \
   }
 
 /**
@@ -2321,6 +2335,22 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
  * the occlusion status between 1(one) triangle and 1(one) line.
  * if returns true, then from/to will carry the occluded segments
  * in ratio from `e->v1` to `e->v2`. The line is later cut with these two values.
+ *
+ * TODO: (Yiming) This function us

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list