- Home /
How to get the Quaternion Rotation from a Matrix4x4
Hello, I'm trying to create animations during run time. It's going pretty good so far, I just have a few issues with retrieving a quaternion rotation from a matrix4x4. I was able to get the position and scale perfectly by using:
private Vector3 GetPosition(Matrix4x4 matrix)
{
return matrix.GetColumn(3);
}
private Vector3 GetScale(Matrix4x4 matrix)
{
return new Vector3(matrix.GetColumn(0).magnitude, matrix.GetColumn(1).magnitude, matrix.GetColumn(2).magnitude);
}
However, trying to figure out a feasible get rotation function that is exactly the same as unity engines importer for matrices, is another story. I have tried the following, which seem to partially work, but cause a little bit of jitter between key frames:
Both of these work to some extent, but do not produce the same results as unitys importer.
private Quaternion GetRotation(Matrix4x4 matrix) { return Quaternion.LookRotation(matrix.GetColumn(2), matrix.GetColumn(1)); }
and
public static Quaternion QuaternionFromMatrix(Matrix4x4 m) {
Quaternion q = new Quaternion();
float absQ2 = Mathf.Pow(determinant(m), (1 / 3));
q.w = Mathf.Sqrt(Mathf.Max(0, absQ2 + m[0, 0] + m[1, 1] + m[2, 2])) / 2;
q.x = Mathf.Sqrt(Mathf.Max(0, 1 + m[0, 0] - m[1, 1] - m[2, 2])) / 2;
q.y = Mathf.Sqrt(Mathf.Max(0, 1 - m[0, 0] + m[1, 1] - m[2, 2])) / 2;
q.z = Mathf.Sqrt(Mathf.Max(0, 1 - m[0, 0] - m[1, 1] + m[2, 2])) / 2;
q.x *= Mathf.Sign(q.x * (m[2, 1] - m[1, 2]));
q.y *= Mathf.Sign(q.y * (m[0, 2] - m[2, 0]));
q.z *= Mathf.Sign(q.z * (m[1, 0] - m[0, 1]));
return q;
}
public static float determinant(Matrix4x4 m) { float tmp; tmp = m.m03 m.m12 m.m21 m.m30 - m.m02 m.m13 m.m21 m.m30 - m.m03 m.m11 m.m22 m.m30 + m.m01 m.m13 m.m22 m.m30 + m.m02 m.m11 m.m23 m.m30 - m.m01 m.m12 m.m23 m.m30 - m.m03 m.m12 m.m20 m.m31 + m.m02 m.m13 m.m20 m.m31 + m.m03 m.m10 m.m22 m.m31 - m.m00 m.m13 m.m22 m.m31 - m.m02 m.m10 m.m23 m.m31 + m.m00 m.m12 m.m23 m.m31 + m.m03 m.m11 m.m20 m.m32 - m.m01 m.m13 m.m20 m.m32 - m.m03 m.m10 m.m21 m.m32 + m.m00 m.m13 m.m21 m.m32 + m.m01 m.m10 m.m23 m.m32 - m.m00 m.m11 m.m23 m.m32 - m.m02 m.m11 m.m20 m.m33 + m.m01 m.m12 m.m20 m.m33 + m.m02 m.m10 m.m21 m.m33 - m.m00 m.m12 m.m21 m.m33 - m.m01 m.m10 m.m22 m.m33 + m.m00 m.m11 m.m22 m.m33; return tmp; }
To sum it up, I just need to figure out what unity does to get a quaternion rotation from a matrix4x4 on import of keyframes from fbx files.
Thanks so much,
~Matthew.
Answer by xtron32 · Jul 23, 2014 at 11:24 PM
It turns out that you have to use EnsureQuaternionContinuity() on the animation clips after creating them in memory, which will then perfectly convert all rotations to how unity does on import of fbx/dae/etc animation files.
Thanks!
Answer by sethuraj · Jul 17, 2014 at 09:58 AM
You can get the quaternion rotation from 4x4 rotation matrix using this formula
QuaternionW= √(1 + M00 + M11 + M22) /2
QuaternionX = (M21 - M12)/(QuaternionW * 4)
QuaternionY = (M02 - M20)/(QuaternionW * 4)
QuaternionZ = (M10 - M01)/(QuaternionW * 4)
for more refer here
http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
Hi, thank you for answering me so quickly. I have actually looked into it a bit further and found that the first method that I said didn't work, actually did. It's just that unity modifies some of the $$anonymous$$atrix4x4's when it imports fbx files, and I have no idea why it modifies them a bit. If i grab the inverse of bind pose on bones being imported in run time, and run the first function to get the quaternion it matches the same numbers in the animation curves, which is strange. If you have any input on why this is, please let me know.
Thanks :)