From 47b82fc02fb41b3d51784e0b571ad584eb468ea0 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 28 Jul 2020 09:29:38 -0300 Subject: [PATCH] Fix precision issues in 'interp_weights_poly_v2' These precision issues were evident in corrected uvs when the option `"Correct Face Attributes"` is enabled. --- source/blender/blenlib/BLI_math_vector.h | 3 ++ source/blender/blenlib/intern/math_geom.c | 45 +++++++++++-------- .../blenlib/intern/math_vector_inline.c | 16 +++++++ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index d46c02a961c..362ab3769a0 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -133,6 +133,7 @@ MINLINE void sub_v3_v3v3_db(double r[3], const double a[3], const double b[3]); MINLINE void sub_v4_v4(float r[4], const float a[4]); MINLINE void sub_v4_v4v4(float r[4], const float a[4], const float b[4]); +MINLINE void sub_v2db_v2fl_v2fl(double r[2], const float a[2], const float b[2]); MINLINE void sub_v3db_v3fl_v3fl(double r[3], const float a[3], const float b[3]); MINLINE void mul_v2_fl(float r[2], float f); @@ -205,6 +206,7 @@ MINLINE double dot_v3db_v3fl(const double a[3], const float b[3]) ATTR_WARN_UNUS MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]); MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]); MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3]); @@ -221,6 +223,7 @@ MINLINE float len_manhattan_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE int len_manhattan_v2_int(const int v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_manhattan_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE double len_v2_db(const double v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE double len_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_v2v2_int(const int v1[2], const int v2[2]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index ecdf108d00e..937bf8b1ae6 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -4176,8 +4176,8 @@ int interp_sparse_array(float *array, const int list_size, const float skipval) #define DIR_V2_SET(d_len, va, vb) \ { \ - sub_v2_v2v2((d_len)->dir, va, vb); \ - (d_len)->len = len_v2((d_len)->dir); \ + sub_v2db_v2fl_v2fl((d_len)->dir, va, vb); \ + (d_len)->len = len_v2_db((d_len)->dir); \ } \ (void)0 @@ -4185,8 +4185,8 @@ struct Float3_Len { float dir[3], len; }; -struct Float2_Len { - float dir[2], len; +struct Double2_Len { + double dir[2], len; }; /* Mean value weights - smooth interpolation weights for polygons with @@ -4209,21 +4209,30 @@ static float mean_value_half_tan_v3(const struct Float3_Len *d_curr, return 0.0f; } -static float mean_value_half_tan_v2(const struct Float2_Len *d_curr, - const struct Float2_Len *d_next) +/** + * Mean value weights - same as #mean_value_half_tan_v3 but for 2D vectors. + * + * \note When interpolating a 2D polygon, a point can be considered "outside" + * the polygon's bounds. Thus, when the point is very distant and the vectors + * have relatively close values, the precision problems are evident since they + * do not indicate a point "inside" the polygon. + * To resolve this, doubles are used. + */ +static double mean_value_half_tan_v2_db(const struct Double2_Len *d_curr, + const struct Double2_Len *d_next) { - /* different from the 3d version but still correct */ - const float area = cross_v2v2(d_curr->dir, d_next->dir); + /* Different from the 3d version but still correct. */ + const double area = cross_v2v2_db(d_curr->dir, d_next->dir); /* Compare against zero since 'FLT_EPSILON' can be too large, see: T73348. */ - if (LIKELY(area != 0.0f)) { - const float dot = dot_v2v2(d_curr->dir, d_next->dir); - const float len = d_curr->len * d_next->len; - const float result = (len - dot) / area; + if (LIKELY(area != 0.0)) { + const double dot = dot_v2v2_db(d_curr->dir, d_next->dir); + const double len = d_curr->len * d_next->len; + const double result = (len - dot) / area; if (isfinite(result)) { return result; } } - return 0.0f; + return 0.0; } void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3]) @@ -4328,11 +4337,11 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ const float eps_sq = eps * eps; const float *v_curr, *v_next; - float ht_prev, ht; /* half tangents */ + double ht_prev, ht; /* half tangents */ float totweight = 0.0f; int i_curr, i_next; char ix_flag = 0; - struct Float2_Len d_curr, d_next; + struct Double2_Len d_curr, d_next; /* loop over 'i_next' */ i_curr = n - 1; @@ -4343,7 +4352,7 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ DIR_V2_SET(&d_curr, v_curr - 2 /* v[n - 2] */, co); DIR_V2_SET(&d_next, v_curr /* v[n - 1] */, co); - ht_prev = mean_value_half_tan_v2(&d_curr, &d_next); + ht_prev = mean_value_half_tan_v2_db(&d_curr, &d_next); while (i_next < n) { /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close @@ -4362,8 +4371,8 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ d_curr = d_next; DIR_V2_SET(&d_next, v_next, co); - ht = mean_value_half_tan_v2(&d_curr, &d_next); - w[i_curr] = (ht_prev + ht) / d_curr.len; + ht = mean_value_half_tan_v2_db(&d_curr, &d_next); + w[i_curr] = (float)((ht_prev + ht) / d_curr.len); totweight += w[i_curr]; /* step */ diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index ca405907bdd..1b47832589e 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -509,6 +509,12 @@ MINLINE void sub_v3_v3v3_db(double r[3], const double a[3], const double b[3]) r[2] = a[2] - b[2]; } +MINLINE void sub_v2db_v2fl_v2fl(double r[2], const float a[2], const float b[2]) +{ + r[0] = (double)a[0] - (double)b[0]; + r[1] = (double)a[1] - (double)b[1]; +} + MINLINE void sub_v3db_v3fl_v3fl(double r[3], const float a[3], const float b[3]) { r[0] = (double)a[0] - (double)b[0]; @@ -917,6 +923,11 @@ MINLINE float cross_v2v2(const float a[2], const float b[2]) return a[0] * b[1] - a[1] * b[0]; } +MINLINE double cross_v2v2_db(const double a[2], const double b[2]) +{ + return a[0] * b[1] - a[1] * b[0]; +} + MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]) { BLI_assert(r != a && r != b); @@ -997,6 +1008,11 @@ MINLINE float len_v2(const float v[2]) return sqrtf(v[0] * v[0] + v[1] * v[1]); } +MINLINE double len_v2_db(const double v[2]) +{ + return sqrt(v[0] * v[0] + v[1] * v[1]); +} + MINLINE float len_v2v2(const float v1[2], const float v2[2]) { float x, y;