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);
@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].
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;
}
}
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!
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;
}