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
This commit is contained in:
Gaia Clary 2020-11-21 13:28:44 +03:00 committed by Alexander Gavrilov
parent dfa1c7e554
commit df445cc571
Notes: blender-bot 2023-02-14 06:00:51 +01:00
Referenced by issue #82455, The conversion of roll to matrix breaks in some cases
1 changed files with 8 additions and 9 deletions

View File

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