Cleanup: Convert float to double during uv unwrap
buildbot/vdev-code-daily-coordinator Build done. Details

`sinf(float_angle)` is sometimes producing different results on
x86_64 cpus and apple silicon cpus. Convert to double precision
to increase accuracy and consistency.

Partial fix for #104513. More to come.
This commit is contained in:
Chris Blackbourn 2023-05-07 12:03:32 +12:00
parent a684e61cbf
commit 0eba9e41bf
Notes: blender-bot 2023-06-08 04:30:36 +02:00
Referenced by issue #107717, Lineart modifier crashes Blender
Referenced by issue #107829, How to handle difference in sinf/cosf for M1
Referenced by commit 9d25c4aaa6, Fix #104513: UV packing produces different results on x86 vs apple silicon
3 changed files with 46 additions and 33 deletions

View File

@ -140,6 +140,8 @@ MINLINE float max_ffff(float a, float b, float c, float d);
MINLINE double min_dd(double a, double b);
MINLINE double max_dd(double a, double b);
MINLINE double min_ddd(double a, double b, double c);
MINLINE double max_ddd(double a, double b, double c);
MINLINE int min_ii(int a, int b);
MINLINE int max_ii(int a, int b);

View File

@ -545,6 +545,15 @@ MINLINE unsigned long long max_ulul(unsigned long long a, unsigned long long b)
return (b < a) ? a : b;
}
MINLINE double min_ddd(double a, double b, double c)
{
return min_dd(min_dd(a, b), c);
}
MINLINE double max_ddd(double a, double b, double c)
{
return max_dd(max_dd(a, b), c);
}
MINLINE float min_fff(float a, float b, float c)
{
return min_ff(min_ff(a, b), c);

View File

@ -303,12 +303,12 @@ static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
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)
double *r_fix,
double *r_a1,
double *r_a2)
{
const float max_angle = float(M_PI) * (179.0f / 180.0f);
const float fix_amount = *r_fix - max_angle;
const double max_angle = M_PI * 179.0f / 180.0f;
const double fix_amount = *r_fix - max_angle;
if (fix_amount < 0.0f) {
return; /* angle is reasonable, i.e. less than 179 degrees. */
}
@ -325,17 +325,17 @@ static void fix_large_angle(const float v_fix[3],
* tan(*r_a1) = s / x1
* tan(*r_a2) = s / x2
*
* Remember that `tan = sin / cos`, `sin(s) ~= s` and `cos(s) = 1`
* Remember that `tan(angle) ~= angle`
*
* 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;
const double dist_v1 = len_v3v3(v_fix, v1);
const double dist_v2 = len_v3v3(v_fix, v2);
const double sum = dist_v1 + dist_v2;
const double weight = (sum > 1e-20f) ? dist_v2 / sum : 0.5f;
/* Ensure sum of angles in triangle is unchanged. */
*r_fix -= fix_amount;
@ -344,7 +344,7 @@ static void fix_large_angle(const float v_fix[3],
}
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)
const float v1[3], const float v2[3], const float v3[3], double *r_a1, double *r_a2, double *r_a3)
{
*r_a1 = angle_v3v3v3(v3, v1, v2);
*r_a2 = angle_v3v3v3(v1, v2, v3);
@ -356,12 +356,12 @@ static void p_triangle_angles(
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);
*r_a1 = max_dd(*r_a1, 0.001f);
*r_a2 = max_dd(*r_a2, 0.001f);
*r_a3 = max_dd(*r_a3, 0.001f);
}
static void p_face_angles(PFace *f, float *r_a1, float *r_a2, float *r_a3)
static void p_face_angles(PFace *f, double *r_a1, double *r_a2, double *r_a3)
{
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
@ -2315,12 +2315,14 @@ static void p_abf_free_system(PAbfSystem *sys)
static void p_abf_compute_sines(PAbfSystem *sys)
{
int i;
float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha;
float *sine = sys->sine;
float *cosine = sys->cosine;
const float *alpha = sys->alpha;
for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) {
*sine = sinf(*alpha);
*cosine = cosf(*alpha);
for (int i = 0; i < sys->nangles; i++) {
const double angle = alpha[i];
sine[i] = sin(angle);
cosine[i] = cos(angle);
}
}
@ -2691,7 +2693,7 @@ static bool p_chart_abf_solve(PChart *chart)
/* compute initial angles */
for (f = chart->faces; f; f = f->nextlink) {
float a1, a2, a3;
double a1, a2, a3;
e1 = f->edge;
e2 = e1->next;
@ -3104,7 +3106,7 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
for (PFace *f = chart->faces; f; f = f->nextlink) {
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
float a1, a2, a3;
double a1, a2, a3;
if (alpha) {
/* Use abf angles if present. */
@ -3122,29 +3124,29 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
std::swap(v2, v3);
}
float sina1 = sinf(a1);
float sina2 = sinf(a2);
float sina3 = sinf(a3);
double sina1 = sin(a1);
double sina2 = sin(a2);
double sina3 = sin(a3);
const float sinmax = max_fff(sina1, sina2, sina3);
const double sinmax = max_ddd(sina1, sina2, sina3);
/* Shift vertices to find most stable order. */
if (sina3 != sinmax) {
SHIFT3(PVert *, v1, v2, v3);
SHIFT3(float, a1, a2, a3);
SHIFT3(float, sina1, sina2, sina3);
SHIFT3(double, a1, a2, a3);
SHIFT3(double, sina1, sina2, sina3);
if (sina2 == sinmax) {
SHIFT3(PVert *, v1, v2, v3);
SHIFT3(float, a1, a2, a3);
SHIFT3(float, sina1, sina2, sina3);
SHIFT3(double, a1, a2, a3);
SHIFT3(double, sina1, sina2, sina3);
}
}
/* Angle based lscm formulation. */
const float ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
const float cosine = cosf(a1) * ratio;
const float sine = sina1 * ratio;
const double ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
const double cosine = cos(a1) * ratio;
const double sine = sina1 * ratio;
EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);