Skip to content

Commit fbae395

Browse files
authored
Update raymath.h (#5201)
1 parent 78a607b commit fbae395

File tree

1 file changed

+75
-49
lines changed

1 file changed

+75
-49
lines changed

src/raymath.h

Lines changed: 75 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,65 +2552,91 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
25522552
return result;
25532553
}
25542554

2555-
// Decompose a transformation matrix into its rotational, translational and scaling components
2555+
// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
25562556
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
25572557
{
2558-
// Extract translation.
2558+
float eps = 1e-9;
2559+
2560+
// Extract Translation
25592561
translation->x = mat.m12;
25602562
translation->y = mat.m13;
25612563
translation->z = mat.m14;
25622564

2563-
// Extract upper-left for determinant computation
2564-
const float a = mat.m0;
2565-
const float b = mat.m4;
2566-
const float c = mat.m8;
2567-
const float d = mat.m1;
2568-
const float e = mat.m5;
2569-
const float f = mat.m9;
2570-
const float g = mat.m2;
2571-
const float h = mat.m6;
2572-
const float i = mat.m10;
2573-
const float A = e*i - f*h;
2574-
const float B = f*g - d*i;
2575-
const float C = d*h - e*g;
2576-
2577-
// Extract scale
2578-
const float det = a*A + b*B + c*C;
2579-
Vector3 abc = { a, b, c };
2580-
Vector3 def = { d, e, f };
2581-
Vector3 ghi = { g, h, i };
2582-
2583-
float scalex = Vector3Length(abc);
2584-
float scaley = Vector3Length(def);
2585-
float scalez = Vector3Length(ghi);
2586-
Vector3 s = { scalex, scaley, scalez };
2587-
2588-
if (det < 0) s = Vector3Negate(s);
2589-
2590-
*scale = s;
2591-
2592-
// Remove scale from the matrix if it is not close to zero
2593-
Matrix clone = mat;
2594-
if (!FloatEquals(det, 0))
2565+
// Matrix Columns - Rotation will be extracted into here.
2566+
Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 },
2567+
{ mat.m1, mat.m5, mat.m9 },
2568+
{ mat.m2, mat.m6, mat.m10 } };
2569+
2570+
// Shear Parameters XY, XZ, and YZ (extract and ignored)
2571+
float shear[3] = { 0 };
2572+
2573+
// Normalized Scale Parameters
2574+
Vector3 scl = { 0 };
2575+
2576+
// Max-Normalizing helps numerical stability
2577+
float stabilizer = eps;
2578+
for (int i = 0; i < 3; i++)
2579+
{
2580+
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x));
2581+
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y));
2582+
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z));
2583+
};
2584+
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer);
2585+
matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer);
2586+
matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer);
2587+
2588+
// X Scale
2589+
scl.x = Vector3Length(matColumns[0]);
2590+
if (scl.x > eps)
25952591
{
2596-
clone.m0 /= s.x;
2597-
clone.m4 /= s.x;
2598-
clone.m8 /= s.x;
2599-
clone.m1 /= s.y;
2600-
clone.m5 /= s.y;
2601-
clone.m9 /= s.y;
2602-
clone.m2 /= s.z;
2603-
clone.m6 /= s.z;
2604-
clone.m10 /= s.z;
2605-
2606-
// Extract rotation
2607-
*rotation = QuaternionFromMatrix(clone);
2592+
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
26082593
}
2609-
else
2594+
2595+
// Compute XY shear and make col2 orthogonal
2596+
shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]);
2597+
matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0]));
2598+
2599+
// Y Scale
2600+
scl.y = Vector3Length(matColumns[1]);
2601+
if (scl.y > eps)
26102602
{
2611-
// Set to identity if close to zero
2612-
*rotation = QuaternionIdentity();
2603+
matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y);
2604+
shear[0] /= scl.y; // Correct XY shear
26132605
}
2606+
2607+
// Compute XZ and YZ shears and make col3 orthogonal
2608+
shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]);
2609+
matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1]));
2610+
shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]);
2611+
matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2]));
2612+
2613+
// Z Scale
2614+
scl.z = Vector3Length(matColumns[2]);
2615+
if (scl.z > eps)
2616+
{
2617+
matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z);
2618+
shear[1] /= scl.z; // Correct XZ shear
2619+
shear[2] /= scl.z; // Correct YZ shear
2620+
}
2621+
2622+
// matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
2623+
if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0)
2624+
{
2625+
scl = Vector3Negate(scl);
2626+
matColumns[0] = Vector3Negate(matColumns[0]);
2627+
matColumns[1] = Vector3Negate(matColumns[1]);
2628+
matColumns[2] = Vector3Negate(matColumns[2]);
2629+
}
2630+
2631+
// Set Scale
2632+
*scale = Vector3Scale(scl, stabilizer);
2633+
2634+
// Extract Rotation
2635+
Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0,
2636+
matColumns[1].x, matColumns[1].y, matColumns[1].z, 0,
2637+
matColumns[2].x, matColumns[2].y, matColumns[2].z, 0,
2638+
0, 0, 0, 1 };
2639+
*rotation = QuaternionFromMatrix(rotationMatrix);
26142640
}
26152641

26162642
#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)

0 commit comments

Comments
 (0)