is there a way to control the rotation order?

It appears the current order is zxy.

Is there a way to modify that, or do we just work with it that way?

is there a way to control the rotation order?

It appears the current order is zxy.

Is there a way to modify that, or do we just work with it that way?

The order is XYZ, in Euler angles; that is rotation around the x axis, rotation around Y, rotation around Z.

If you don’t like the order provided by Euler angles, just do it manually:

```
// For example, in whichever order you like....
rotation = Quaternion.AngleAxis(xAngle, Vector3.right) *
Quaternion.AngleAxis(zAngle, Vector3.forward) *
Quaternion.AngleAxis(yAngle, Vector3.up);
```

4 Likes

@manta-

I don’t believe that is true-

This is proven by creating a cube in Maya (setting the rotation order to XYZ), and one in unity. Start entering Euler values and you quickly see they are different.

EDIT:

Geez, I didn’t even notice maya is right-handed, and unity is left handed. This sort of thing makes my head hurt.

Wrong.

See the official docs [here].

5 Likes

I was doing a rudimentary fbx writer script and encountered similar problems with the rotations quaternion to euler order being not correct.

I stumbled upon a couple of c++ functions providing quaternion to euler conversion with various orders applied. I dont understand much of how it actually does the math but i ported it into c# and experimented.

When converting a unity rotation to a fbx rotation i found that quaternion2Euler(conv, RotSeq.zyx) seemed to do the trick.

Anyway here is the original c++ code source from a guy called Birdy:

http://bediyap.com/programming/convert-quaternion-to-euler-rotations/

And here is my port of the functions doing the work:

```
enum RotSeq
{
zyx, zyz, zxy, zxz, yxz, yxy, yzx, yzy, xyz, xyx, xzy,xzx
};
Vector3 twoaxisrot(float r11, float r12, float r21, float r31, float r32){
Vector3 ret = new Vector3();
ret.x = Mathf.Atan2( r11, r12 );
ret.y = Mathf.Acos ( r21 );
ret.z = Mathf.Atan2( r31, r32 );
return ret;
}
Vector3 threeaxisrot(float r11, float r12, float r21, float r31, float r32){
Vector3 ret = new Vector3();
ret.x = Mathf.Atan2( r31, r32 );
ret.y = Mathf.Asin ( r21 );
ret.z = Mathf.Atan2( r11, r12 );
return ret;
}
Vector3 quaternion2Euler(Quaternion q, RotSeq rotSeq)
{
switch(rotSeq){
case RotSeq.zyx:
return threeaxisrot( 2*(q.x*q.y + q.w*q.z),
q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
-2*(q.x*q.z - q.w*q.y),
2*(q.y*q.z + q.w*q.x),
q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z);
case RotSeq.zyz:
return twoaxisrot( 2*(q.y*q.z - q.w*q.x),
2*(q.x*q.z + q.w*q.y),
q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
2*(q.y*q.z + q.w*q.x),
-2*(q.x*q.z - q.w*q.y));
case RotSeq.zxy:
return threeaxisrot( -2*(q.x*q.y - q.w*q.z),
q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
2*(q.y*q.z + q.w*q.x),
-2*(q.x*q.z - q.w*q.y),
q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z);
case RotSeq.zxz:
return twoaxisrot( 2*(q.x*q.z + q.w*q.y),
-2*(q.y*q.z - q.w*q.x),
q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
2*(q.x*q.z - q.w*q.y),
2*(q.y*q.z + q.w*q.x));
case RotSeq.yxz:
return threeaxisrot( 2*(q.x*q.z + q.w*q.y),
q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
-2*(q.y*q.z - q.w*q.x),
2*(q.x*q.y + q.w*q.z),
q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z);
case RotSeq.yxy:
return twoaxisrot( 2*(q.x*q.y - q.w*q.z),
2*(q.y*q.z + q.w*q.x),
q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
2*(q.x*q.y + q.w*q.z),
-2*(q.y*q.z - q.w*q.x));
case RotSeq.yzx:
return threeaxisrot( -2*(q.x*q.z - q.w*q.y),
q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
2*(q.x*q.y + q.w*q.z),
-2*(q.y*q.z - q.w*q.x),
q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z);
case RotSeq.yzy:
return twoaxisrot( 2*(q.y*q.z + q.w*q.x),
-2*(q.x*q.y - q.w*q.z),
q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
2*(q.y*q.z - q.w*q.x),
2*(q.x*q.y + q.w*q.z));
case RotSeq.xyz:
return threeaxisrot( -2*(q.y*q.z - q.w*q.x),
q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
2*(q.x*q.z + q.w*q.y),
-2*(q.x*q.y - q.w*q.z),
q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z);
case RotSeq.xyx:
return twoaxisrot( 2*(q.x*q.y + q.w*q.z),
-2*(q.x*q.z - q.w*q.y),
q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
2*(q.x*q.y - q.w*q.z),
2*(q.x*q.z + q.w*q.y));
case RotSeq.xzy:
return threeaxisrot( 2*(q.y*q.z + q.w*q.x),
q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
-2*(q.x*q.y - q.w*q.z),
2*(q.x*q.z + q.w*q.y),
q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z);
case RotSeq.xzx:
return twoaxisrot( 2*(q.x*q.z - q.w*q.y),
2*(q.x*q.y + q.w*q.z),
q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
2*(q.x*q.z + q.w*q.y),
-2*(q.x*q.y - q.w*q.z));
default:
Debug.LogError("No good sequence");
return Vector3.zero;
}
}
```

2 Likes

Sorry for resurrecting an old thread but just wanted to thank thoobes, this code saved my life.

Also, I am not sure if I did something wrong but, although Unity’s documentation states that the rotation order is ZXY, when comparing the euler values from quaternion.eulerAngles and the values I get from the same quaternion using the function above, it seems Unity’s order is ZYX. If anyone knows why would this happen please let me know.

Cheers!

1 Like

Sorry for replying on such an old thread but I just had to express my gratitude for this comment made by some random person 12 years ago. I just spent the last 5 hours troubleshooting some issues with camera rotations in a game where you walk around a spherical planet and this comment GREATLY helped me solve them. Thanks for the help!

I can definitely confirm that ZYX is the correct orientation for Unity.

Also, thank you for the code thoobes!!

Converting EulerAngles to a 3*3 Matrix requires to use ZXY order, which can be described as can be seen in the code below.

The bottom method is simple the Z-rotation-matrix, multiplied by X-rotation-matrix, multiplied by the Y rotation Matrix (= ZXY Matrix). This is the order that Unity uses for their matrix calculation.

```
public static float[,] CreateFromEuler(Vector3 eulerInRadians)
{
float cx = Mathf.Cos(eulerInRadians.x);
float cy = Mathf.Cos(eulerInRadians.y);
float cz = Mathf.Cos(eulerInRadians.z);
float sx = Mathf.Sin(eulerInRadians.x);
float sy = Mathf.Sin(eulerInRadians.y);
float sz = Mathf.Sin(eulerInRadians.z);
float[,] lmx = new float[3,3];
lmx[0, 0] = cz * cy + sz * sx * sy;
lmx[1, 0] = sz * cx;
lmx[2, 0] = -cz * sy + cy * sz * sx;
lmx[0, 1] = -sz * cy + cz * sx * sy;
lmx[1, 1] = cz * cx;
lmx[2, 1] = sz * sy + cz * sx * cy;
lmx[0, 2] = cx * sy;
lmx[1, 2] = -sx;
lmx[2, 2] = cx * cy;
return lmx;
}
```

2 Likes