Search code examples
c#vectormatrixangledecomposition

How to calculate the angles XYZ from a Matrix4x4


I am trying to ascertain the X,Y,Z angles held within a Matrix by decomposing the matrix. I am using .net 4.5 c#.

I created a test to check the following:

  • If I create an Matrix4x4 with identity values only
  • Rotate the matrix by 45 degrees
  • Decompose the matrix and evaluate the quaternion returned (gives the x,y,z angles)
  • Check that the X value out matches the 45 degrees put in

I get the following results: X:0.5 Y:0 Z:0

I was expecting: X:0.45 Y:0 Z:0

Test Code

Quaternion quatDecomposed;
Vector3D translation;

Matrix4x4 rot = Matrix4x4.RotationAroundX(45);
rot.DecomposeNoScaling(out quatDecomposed, out translation);

I have created my own Matrix4x4, Vector3D and Angle3D structures shown in the examples below.

My Matrix4x4 rotate around x method is as follows:

    public static Matrix4x4 RotationAroundX(double degrees)
    {
        // [1, 0,  0,   0]
        // [0, cos,-sin,0]
        // [0, sin,cos, 0]
        // [0, 0,  0,   1]

        // convert degrees to radians.
        double radians = DoubleExtensions.DegreesToRadians(degrees);

        // return matrix.
        var matrixTransformed = Matrix4x4.Identity;

        matrixTransformed.M22 = (float)Math.Cos(radians);
        matrixTransformed.M23 = (float)-(Math.Sin(radians));

        matrixTransformed.M32 = (float)Math.Sin(radians);
        matrixTransformed.M33 = (float)Math.Cos(radians);

        //return matrix;
        return matrixTransformed;
    }

My decompose no scaling method is as follows:

    public void DecomposeNoScaling(out Quaternion rotation, out Vector3D translation)
    {
        translation.X = this[1, 4];
        translation.Y = this[2, 4];
        translation.Z = this[3, 4];

        rotation = new Quaternion(new Matrix3x3(this));
    }

What I am looking to get out is the angles contained within the Matrix4x4, I do this as follows:

Angle3D angles = new Angle3D(quatDecomposed.X, quatDecomposed.Y, quatDecomposed.Z);

Can anyone spot what I'm doing wrong? What I am REALLY trying to work out is the Euler angles from the matrix4x4 in ZYX order.

Thanks in advance!


Solution

  • Just in case anyone else needs to know, this is how I get the Euler angles directly from the Matrix:

        public static Angle3D GetAngles(Matrix4x4 source)
        {
            double thetaX, thetaY, thetaZ = 0.0;
            thetaX = Math.Asin(source.M32);
    
            if (thetaX < (Math.PI / 2))
            {
                if (thetaX > (-Math.PI / 2))
                {
                    thetaZ = Math.Atan2(-source.M12, source.M22);
                    thetaY = Math.Atan2(-source.M31, source.M33);
                }
                else
                {
                    thetaZ = -Math.Atan2(-source.M13, source.M11);
                    thetaY = 0;
                }
            }
            else
            {
                thetaZ = Math.Atan2(source.M13, source.M11);
                thetaY = 0;
            }
    
            // Create return object.
            Angle3D angles = new Angle3D(thetaX, thetaY, thetaZ);
    
            // Convert to degrees.;
            angles.Format = AngleFormat.Degrees;
    
            // Return angles.
            return angles;
        }