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:
Threejs
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.
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);
}