diff options
author | Gaia Clary <gaiaclary> | 2020-11-21 13:28:44 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2021-10-20 12:58:19 +0300 |
commit | df445cc571bd1cf7fab4c5c8474f5e185a757fe2 (patch) | |
tree | 2f8c039e8a16ca7db3bb3e00df4ceb8039a0285f | |
parent | dfa1c7e554fcc3ddd40780fb8555cdd6e90eaba3 (diff) |
Fix T82455: vec_roll_to_mat3_normalized returns NaN when nor close to -Y.
In this case theta is completely unsafe to use, so a different
threshold based on x and z has to be used to avoid division by zero.
Ref D9551
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index a60cba3c892..a266718dcfc 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2240,15 +2240,16 @@ 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]) { - 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. */ + const float SAFE_THRESHOLD = 1.0e-5f; /* theta above this value has good enough precision. */ + const float CRITICAL_THRESHOLD = 1.0e-9f; /* above this is safe under certain conditions. */ + const float THRESHOLD_SQUARED = CRITICAL_THRESHOLD * CRITICAL_THRESHOLD; 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; + const float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */ + const float theta_alt = x * x + z * z; /* Helper value for matrix calculations.*/ float rMatrix[3][3], bMatrix[3][3]; BLI_ASSERT_UNIT_V3(nor); @@ -2258,10 +2259,8 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m * 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_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... ;) - */ + if (theta > SAFE_THRESHOLD || (theta > CRITICAL_THRESHOLD && theta_alt > THRESHOLD_SQUARED)) { + /* nor is *not* aligned to negative Y-axis (0,-1,0). */ bMatrix[0][1] = -x; bMatrix[1][0] = x; @@ -2269,7 +2268,7 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m bMatrix[1][2] = z; bMatrix[2][1] = -z; - if (theta > THETA_SAFE) { + if (theta > SAFE_THRESHOLD) { /* 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; |