3

I am attempting to convert euler angle rotations between Unity and Threejs. There are two main issues with this.

Problem 1:

Unity and Threejs have different coordinate systems

Unity:

enter image description here

Threejs

enter image description here

Problem 2:

Unity does euler math in the order ZXY whereas Threejs defaults to XYZ. I have found some formulas on the Threejs side for creating Euler angles using a different order of multiplication, but I would like to know the math behind this so I can go back and forth between the two systems. I am also not sure how the different coordinate systems plays into this conversion math.

EDIT 1

I found this stack overflow post about converting a Unity Quaternion to Threejs:

Convert Unity transforms to THREE.js rotations

However, I was not able to get this code to work for going the opposite direction of Threejs to Unity which is what I need.

Community
  • 1
  • 1
Matt
  • 177
  • 2
  • 13

2 Answers2

3

I finally found a solution to this using the links below. There may be an easier solution, but nothing else I tried gave me the intended effect. It is worth noting that this was tested with a Threejs camera that is -z facing where +y is up. My unity camera is -z facing with +y facing up. If you have a +z facing camera, which is common in Unity, simply child the GameObject to an empty GameObject and apply a 180 degree Euler rotation to the empty GameObject. This also assumes that the Threejs Euler rotation is the default XYZ ordering.

http://answers.unity3d.com/storage/temp/12048-lefthandedtorighthanded.pdf

http://en.wikipedia.org/wiki/Euler_angles

http://forum.unity3d.com/threads/how-to-assign-matrix4x4-to-transform.121966/

    /// <summary>
    /// Converts the given XYZ euler rotation taken from Threejs to a Unity Euler rotation
    /// </summary>
    public static Vector3 ConvertThreejsEulerToUnity(Vector3 eulerThreejs)
    {
        eulerThreejs.x *= -1;
        eulerThreejs.z *= -1;
        Matrix4x4 threejsMatrix = CreateRotationalMatrixThreejs(ref eulerThreejs);

        Matrix4x4 unityMatrix = threejsMatrix;
        unityMatrix.m02 *= -1;
        unityMatrix.m12 *= -1;
        unityMatrix.m20 *= -1;
        unityMatrix.m21 *= -1;

        Quaternion rotation = ExtractRotationFromMatrix(ref unityMatrix);
        Vector3 eulerRotation = rotation.eulerAngles;
        return eulerRotation;
    }

    /// <summary>
    /// Creates a rotation matrix for the given threejs euler rotation
    /// </summary>
    private static Matrix4x4 CreateRotationalMatrixThreejs(ref Vector3 eulerThreejs)
    {
        float c1 = Mathf.Cos(eulerThreejs.x);
        float c2 = Mathf.Cos(eulerThreejs.y);
        float c3 = Mathf.Cos(eulerThreejs.z);
        float s1 = Mathf.Sin(eulerThreejs.x);
        float s2 = Mathf.Sin(eulerThreejs.y);
        float s3 = Mathf.Sin(eulerThreejs.z);
        Matrix4x4 threejsMatrix = new Matrix4x4();
        threejsMatrix.m00 = c2 * c3;
        threejsMatrix.m01 = -c2 * s3;
        threejsMatrix.m02 = s2;
        threejsMatrix.m10 = c1 * s3 + c3 * s1 * s2;
        threejsMatrix.m11 = c1 * c3 - s1 * s2 * s3;
        threejsMatrix.m12 = -c2 * s1;
        threejsMatrix.m20 = s1 * s3 - c1 * c3 * s2;
        threejsMatrix.m21 = c3 * s1 + c1 * s2 * s3;
        threejsMatrix.m22 = c1 * c2;
        threejsMatrix.m33 = 1;
        return threejsMatrix;
    }

    /// <summary>
    /// Extract rotation quaternion from transform matrix.
    /// </summary>
    /// <param name="matrix">Transform matrix. This parameter is passed by reference
    /// to improve performance; no changes will be made to it.</param>
    /// <returns>
    /// Quaternion representation of rotation transform.
    /// </returns>
    public static Quaternion ExtractRotationFromMatrix(ref Matrix4x4 matrix)
    {
        Vector3 forward;
        forward.x = matrix.m02;
        forward.y = matrix.m12;
        forward.z = matrix.m22;

        Vector3 upwards;
        upwards.x = matrix.m01;
        upwards.y = matrix.m11;
        upwards.z = matrix.m21;

        return Quaternion.LookRotation(forward, upwards);
    }
Matt
  • 177
  • 2
  • 13
-2

Problem 1:

Granted I only minored in math but I believe you should simply be able to do a straight mapping as follows for points:

(X, Y, Z) => (X, Y, -Z)

And that should work both ways.

As far as I remember once you convert between coordinates the math should be the same, just make sure you work all in one system or the other to make your life easier. Then you can export results back as needed.

CShannon
  • 135
  • 4
  • 1
    This will not work as we are talking about rotations in these two systems. If we were talking about position differences this might work but it will not work for euler angle rotations. – Matt Mar 31 '15 at 21:50
  • Have you looked into rotation matrices then? I believe that might be a good way to resolve both conflicts since they can be used to abstract the ordering of rotations. Then you should just be left with simple coordinate conversions. – CShannon Mar 31 '15 at 21:55
  • I have been looking into rotation matrices. I was able to get the Euler angles from Threejs into a rotation matrix using this wiki: http://en.wikipedia.org/wiki/Euler_angles At this point I attempted to convert the matrix from a right handed to left handed coordinate system using: http://stackoverflow.com/questions/1263072/changing-a-matrix-from-right-handed-to-left-handed-coordinate-system At this point I attempted to extract the rotation as a quaternion back out of the matrix. One of the last 2 steps did not work however because the rotations do not line up. Check my edit if you can – Matt Apr 01 '15 at 21:22