mirror of
https://github.com/raysan5/raylib.git
synced 2025-10-10 03:46:28 +00:00
Update raymath.h (#5201)
This commit is contained in:
118
src/raymath.h
118
src/raymath.h
@@ -2552,65 +2552,91 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompose a transformation matrix into its rotational, translational and scaling components
|
// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
|
||||||
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
|
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
|
||||||
{
|
{
|
||||||
// Extract translation.
|
float eps = 1e-9;
|
||||||
|
|
||||||
|
// Extract Translation
|
||||||
translation->x = mat.m12;
|
translation->x = mat.m12;
|
||||||
translation->y = mat.m13;
|
translation->y = mat.m13;
|
||||||
translation->z = mat.m14;
|
translation->z = mat.m14;
|
||||||
|
|
||||||
// Extract upper-left for determinant computation
|
// Matrix Columns - Rotation will be extracted into here.
|
||||||
const float a = mat.m0;
|
Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 },
|
||||||
const float b = mat.m4;
|
{ mat.m1, mat.m5, mat.m9 },
|
||||||
const float c = mat.m8;
|
{ mat.m2, mat.m6, mat.m10 } };
|
||||||
const float d = mat.m1;
|
|
||||||
const float e = mat.m5;
|
|
||||||
const float f = mat.m9;
|
|
||||||
const float g = mat.m2;
|
|
||||||
const float h = mat.m6;
|
|
||||||
const float i = mat.m10;
|
|
||||||
const float A = e*i - f*h;
|
|
||||||
const float B = f*g - d*i;
|
|
||||||
const float C = d*h - e*g;
|
|
||||||
|
|
||||||
// Extract scale
|
// Shear Parameters XY, XZ, and YZ (extract and ignored)
|
||||||
const float det = a*A + b*B + c*C;
|
float shear[3] = { 0 };
|
||||||
Vector3 abc = { a, b, c };
|
|
||||||
Vector3 def = { d, e, f };
|
|
||||||
Vector3 ghi = { g, h, i };
|
|
||||||
|
|
||||||
float scalex = Vector3Length(abc);
|
// Normalized Scale Parameters
|
||||||
float scaley = Vector3Length(def);
|
Vector3 scl = { 0 };
|
||||||
float scalez = Vector3Length(ghi);
|
|
||||||
Vector3 s = { scalex, scaley, scalez };
|
|
||||||
|
|
||||||
if (det < 0) s = Vector3Negate(s);
|
// Max-Normalizing helps numerical stability
|
||||||
|
float stabilizer = eps;
|
||||||
*scale = s;
|
for (int i = 0; i < 3; i++)
|
||||||
|
|
||||||
// Remove scale from the matrix if it is not close to zero
|
|
||||||
Matrix clone = mat;
|
|
||||||
if (!FloatEquals(det, 0))
|
|
||||||
{
|
{
|
||||||
clone.m0 /= s.x;
|
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x));
|
||||||
clone.m4 /= s.x;
|
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y));
|
||||||
clone.m8 /= s.x;
|
stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z));
|
||||||
clone.m1 /= s.y;
|
};
|
||||||
clone.m5 /= s.y;
|
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer);
|
||||||
clone.m9 /= s.y;
|
matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer);
|
||||||
clone.m2 /= s.z;
|
matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer);
|
||||||
clone.m6 /= s.z;
|
|
||||||
clone.m10 /= s.z;
|
|
||||||
|
|
||||||
// Extract rotation
|
// X Scale
|
||||||
*rotation = QuaternionFromMatrix(clone);
|
scl.x = Vector3Length(matColumns[0]);
|
||||||
}
|
if (scl.x > eps)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Set to identity if close to zero
|
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
|
||||||
*rotation = QuaternionIdentity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute XY shear and make col2 orthogonal
|
||||||
|
shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]);
|
||||||
|
matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0]));
|
||||||
|
|
||||||
|
// Y Scale
|
||||||
|
scl.y = Vector3Length(matColumns[1]);
|
||||||
|
if (scl.y > eps)
|
||||||
|
{
|
||||||
|
matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y);
|
||||||
|
shear[0] /= scl.y; // Correct XY shear
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute XZ and YZ shears and make col3 orthogonal
|
||||||
|
shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]);
|
||||||
|
matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1]));
|
||||||
|
shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]);
|
||||||
|
matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2]));
|
||||||
|
|
||||||
|
// Z Scale
|
||||||
|
scl.z = Vector3Length(matColumns[2]);
|
||||||
|
if (scl.z > eps)
|
||||||
|
{
|
||||||
|
matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z);
|
||||||
|
shear[1] /= scl.z; // Correct XZ shear
|
||||||
|
shear[2] /= scl.z; // Correct YZ shear
|
||||||
|
}
|
||||||
|
|
||||||
|
// matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
|
||||||
|
if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0)
|
||||||
|
{
|
||||||
|
scl = Vector3Negate(scl);
|
||||||
|
matColumns[0] = Vector3Negate(matColumns[0]);
|
||||||
|
matColumns[1] = Vector3Negate(matColumns[1]);
|
||||||
|
matColumns[2] = Vector3Negate(matColumns[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Scale
|
||||||
|
*scale = Vector3Scale(scl, stabilizer);
|
||||||
|
|
||||||
|
// Extract Rotation
|
||||||
|
Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0,
|
||||||
|
matColumns[1].x, matColumns[1].y, matColumns[1].z, 0,
|
||||||
|
matColumns[2].x, matColumns[2].y, matColumns[2].z, 0,
|
||||||
|
0, 0, 0, 1 };
|
||||||
|
*rotation = QuaternionFromMatrix(rotationMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)
|
#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)
|
||||||
|
Reference in New Issue
Block a user