4

Unity offer a easy way to get Euler angles and Quaternion. But the angles are not correct in other 3D softwares such as 3dsmax because the order of rotation in Unity is Y-X-Z but others not. Is there a way to convert Euler angles between different rotation orders? More details: Actually, I need to export model in Unity as .fbx file. By using FBX SDK, I've solved the differences of coordinates between Unity and 3dsmax by calling GlobalSetting.SetAxisSystem().As the image show below: rotation provided in Unity

If I set the rotation data directly in fbx file,and import the fbx model to Unity:

Rotation showed imported

I've check the coordinate is correct. I think the vital is Euler order which in Unity is y-x-z,but fbx not. So Unity would do some extra operation on rotation when importing.

Sandiago.C
  • 101
  • 5
  • According to the [docs](https://docs.unity3d.com/ScriptReference/Quaternion-eulerAngles.html) the order of rotations is z, x, y – Kay Jun 19 '18 at 08:29
  • The order of rotation matrices is z-x-y, so the rotation order should be y-x-z. And both cause this problem. – Sandiago.C Jun 19 '18 at 08:43
  • A crude way would be to compute the matrices for each angle, rearrange these matrices, and re-convert to Euler angles. – meowgoesthedog Jun 19 '18 at 19:54
  • How to calculate the matrix(x-y-z order) by using another Euler angles(y-x-z order,Unity provide)?@meowgoesthedog This is crude but not simple.Notice that the angles attained was ordered. – Sandiago.C Jun 20 '18 at 03:15
  • 1
    The matrices themselves (given [here](https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations)) are simple enough. The formula to convert from a matrix back to Euler angles is also readily available (e.g. [here](https://answers.unity.com/questions/11363/converting-matrix4x4-to-quaternion-vector3.html)). Google is your friend. – meowgoesthedog Jun 20 '18 at 09:08
  • Methods referenced in the web link is easy enough,but it can not solve the problem I think. According to the article:1 Change Euler angles(y-x-z order) to matrix;2.Get Euler angles from matrix. But the results in step.2 are y-x-z order... @meowgoesthedog – Sandiago.C Jun 21 '18 at 00:37
  • In another word: how to get the matrix in xyz rotation order that make identical effect with the matrix in yxz rotation order? – Sandiago.C Jun 21 '18 at 01:31
  • Swapping the matrices between "steps" 1 and 2 has the effect of shuffling the axis labels. Just remember to rearrange the final Euler angle vector too. – meowgoesthedog Jun 21 '18 at 14:40
  • Sorry,I don't clearly understand "Swapping the matrices between 'step'1 and 'step'2 has the effect.." Does the matrices converted from X-Y-Z Euler or Y-X-Z Euler angles?@meowgoesthedog – Sandiago.C Jun 26 '18 at 03:58

1 Answers1

4

Three.js is the only open-source library (I could find) to address conversion in different rotation orders. For example, let's say you have a third-party program (e.g. your 3D modeling program) with a rotation order of XZY and it exports rotations as Euler angles in degrees. The conversion to a Unity rotation is

public static Quaternion XZYToUnity( Vector3 r ) {

  return  

    Quaternion.AngleAxis( r.x, Vector3.right ) *
    Quaternion.AngleAxis( r.z, Vector3.forward ) *
    Quaternion.AngleAxis( r.y, Vector3.up );
}

Notice that in Unity, quaternions are applied from left to right, opposite to (typically) rotation matrices. To be clear, the above code yields a rotation that, when you assign it to Transform.localRotation, rotates the transform first around the local X axis, then the local Z axis, then the local Y axis, in that order. See this thread about quaternion multiplication order.

Now, for the other direction, you can find the correct case for your rotation order in the Three.js Euler source code. Converting our particular case 'XZY' to C#:

public static Vector3 UnityToXZY( Quaternion q ) {

  var m = Matrix4x4.Rotate( q );   
  float m11 = m[ 0, 0 ], m12 = m[ 0, 1 ], m13 = m[ 0, 2 ];
  float m21 = m[ 1, 0 ], m22 = m[ 1, 1 ], m23 = m[ 1, 2 ];
  float m31 = m[ 2, 0 ], m32 = m[ 2, 1 ], m33 = m[ 2, 2 ];

  float x, y, z;
  z = Mathf.Asin( - Mathf.Clamp( m12, -1, 1 ));

  if( Mathf.Abs( m12 ) < 0.9999999f ) {

    x = Mathf.Atan2( m32, m22 );
    y = Mathf.Atan2( m13, m11 );
  }
  else {

    x = Mathf.Atan2( - m23, m33 );
    y = 0;
  }

   return new Vector3( x, y, z ) * Mathf.Rad2Deg;
}

If you feed a Transform.localRotation to this method, it gives us back the XZY Euler angles in degrees we put in the first method (ignoring the numerical error and representational non-uniqueness of Euler angles). Formally, going from Unity quaternion to XZY and back guarantees to preserve the orientation in space.