Fix precision issues in 'interp_weights_poly_v2'

These precision issues were evident in corrected uvs when the option
`"Correct Face Attributes"` is enabled.
This commit is contained in:
Germano Cavalcante 2020-07-28 09:29:38 -03:00
parent b99358315e
commit 47b82fc02f
3 changed files with 46 additions and 18 deletions

View File

@ -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]);

View File

@ -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 */

View File

@ -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;