diff options
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 63 |
1 files changed, 30 insertions, 33 deletions
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index fb885527cce..b5d3a04acb8 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2156,50 +2156,50 @@ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll) */ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3]) { -#define THETA_THRESHOLD_NEGY 1.0e-9f -#define THETA_THRESHOLD_NEGY_CLOSE 1.0e-5f + const float THETA_SAFE = 1.0e-5f; /* theta above this value are always safe to use. */ + const float THETA_CRITICAL = 1.0e-9f; /* above this is safe under certain conditions. */ - float theta; + const float x = nor[0]; + const float y = nor[1]; + const float z = nor[2]; + + const float theta = 1.0f + y; + const float theta_alt = x * x + z * z; float rMatrix[3][3], bMatrix[3][3]; BLI_ASSERT_UNIT_V3(nor); - theta = 1.0f + nor[1]; - - /* With old algo, 1.0e-13f caused T23954 and T31333, 1.0e-6f caused T27675 and T30438, - * so using 1.0e-9f as best compromise. - * - * New algo is supposed much more precise, since less complex computations are performed, - * but it uses two different threshold values... - * - * Note: When theta is close to zero, we have to check we do have non-null X/Z components as well - * (due to float precision errors, we can have nor = (0.0, 0.99999994, 0.0)...). + /* When theta is close to zero (nor is aligned close to negative Y Axis), + * we have to check we do have non-null X/Z components as well. + * Also, due to float precision errors, nor can be (0.0, -0.99999994, 0.0) which results + * in theta being close to zero. This will cause problems when theta is used as divisor. */ - if (theta > THETA_THRESHOLD_NEGY_CLOSE || ((nor[0] || nor[2]) && theta > THETA_THRESHOLD_NEGY)) { - /* nor is *not* -Y. + if (theta > THETA_SAFE || ((x || z) && theta > THETA_CRITICAL)) { + /* nor is *not* aligned to negative Y-axis (0,-1,0). * We got these values for free... so be happy with it... ;) */ - bMatrix[0][1] = -nor[0]; - bMatrix[1][0] = nor[0]; - bMatrix[1][1] = nor[1]; - bMatrix[1][2] = nor[2]; - bMatrix[2][1] = -nor[2]; - if (theta > THETA_THRESHOLD_NEGY_CLOSE) { - /* If nor is far enough from -Y, apply the general case. */ - bMatrix[0][0] = 1 - nor[0] * nor[0] / theta; - bMatrix[2][2] = 1 - nor[2] * nor[2] / theta; - bMatrix[2][0] = bMatrix[0][2] = -nor[0] * nor[2] / theta; + + bMatrix[0][1] = -x; + bMatrix[1][0] = x; + bMatrix[1][1] = y; + bMatrix[1][2] = z; + bMatrix[2][1] = -z; + + if (theta > THETA_SAFE) { + /* nor differs significantly from negative Y axis (0,-1,0): apply the general case. */ + bMatrix[0][0] = 1 - x * x / theta; + bMatrix[2][2] = 1 - z * z / theta; + bMatrix[2][0] = bMatrix[0][2] = -x * z / theta; } else { - /* If nor is too close to -Y, apply the special case. */ - theta = nor[0] * nor[0] + nor[2] * nor[2]; - bMatrix[0][0] = (nor[0] + nor[2]) * (nor[0] - nor[2]) / -theta; + /* nor is close to negative Y axis (0,-1,0): apply the special case. */ + bMatrix[0][0] = (x + z) * (x - z) / -theta_alt; bMatrix[2][2] = -bMatrix[0][0]; - bMatrix[2][0] = bMatrix[0][2] = 2.0f * nor[0] * nor[2] / theta; + bMatrix[2][0] = bMatrix[0][2] = 2.0f * x * z / theta_alt; } } else { - /* If nor is -Y, simple symmetry by Z axis. */ + /* nor is very close to negative Y axis (0,-1,0): use simple symmetry by Z axis. */ unit_m3(bMatrix); bMatrix[0][0] = bMatrix[1][1] = -1.0; } @@ -2209,9 +2209,6 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m /* Combine and output result */ mul_m3_m3m3(r_mat, rMatrix, bMatrix); - -#undef THETA_THRESHOLD_NEGY -#undef THETA_THRESHOLD_NEGY_CLOSE } void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3]) |