根据它们的应用顺序,有六种不同的方法可以将三个欧拉角转换为矩阵:
typedef float Matrix[3][3];
struct EulerAngle { float X, Y, Z; };
// Euler Order enum.
enum EEulerOrder
{
ORDER_XYZ,
ORDER_YZX,
ORDER_ZXY,
ORDER_ZYX,
ORDER_YXZ,
ORDER_XZY
};
Matrix EulerAnglesToMatrix(const EulerAngle &inEulerAngle, EEulerOrder EulerOrder)
{
// Convert Euler Angles passed in a vector of Radians
// into a rotation matrix. The individual Euler Angles are
// processed in the order requested.
Matrix Mx;
const FLOAT Sx = sinf(inEulerAngle.X);
const FLOAT Sy = sinf(inEulerAngle.Y);
const FLOAT Sz = sinf(inEulerAngle.Z);
const FLOAT Cx = cosf(inEulerAngle.X);
const FLOAT Cy = cosf(inEulerAngle.Y);
const FLOAT Cz = cosf(inEulerAngle.Z);
switch (EulerOrder)
{
case ORDER_XYZ:
Mx.M[0][0] = Cy*Cz;
Mx.M[0][1] = -Cy*Sz;
Mx.M[0][2] = Sy;
Mx.M[1][0] = Cz*Sx*Sy + Cx*Sz;
Mx.M[1][1] = Cx*Cz - Sx*Sy*Sz;
Mx.M[1][2] = -Cy*Sx;
Mx.M[2][0] = -Cx*Cz*Sy + Sx*Sz;
Mx.M[2][1] = Cz*Sx + Cx*Sy*Sz;
Mx.M[2][2] = Cx*Cy;
break;
case ORDER_YZX:
Mx.M[0][0] = Cy*Cz;
Mx.M[0][1] = Sx*Sy - Cx*Cy*Sz;
Mx.M[0][2] = Cx*Sy + Cy*Sx*Sz;
Mx.M[1][0] = Sz;
Mx.M[1][1] = Cx*Cz;
Mx.M[1][2] = -Cz*Sx;
Mx.M[2][0] = -Cz*Sy;
Mx.M[2][1] = Cy*Sx + Cx*Sy*Sz;
Mx.M[2][2] = Cx*Cy - Sx*Sy*Sz;
break;
case ORDER_ZXY:
Mx.M[0][0] = Cy*Cz - Sx*Sy*Sz;
Mx.M[0][1] = -Cx*Sz;
Mx.M[0][2] = Cz*Sy + Cy*Sx*Sz;
Mx.M[1][0] = Cz*Sx*Sy + Cy*Sz;
Mx.M[1][1] = Cx*Cz;
Mx.M[1][2] = -Cy*Cz*Sx + Sy*Sz;
Mx.M[2][0] = -Cx*Sy;
Mx.M[2][1] = Sx;
Mx.M[2][2] = Cx*Cy;
break;
case ORDER_ZYX:
Mx.M[0][0] = Cy*Cz;
Mx.M[0][1] = Cz*Sx*Sy - Cx*Sz;
Mx.M[0][2] = Cx*Cz*Sy + Sx*Sz;
Mx.M[1][0] = Cy*Sz;
Mx.M[1][1] = Cx*Cz + Sx*Sy*Sz;
Mx.M[1][2] = -Cz*Sx + Cx*Sy*Sz;
Mx.M[2][0] = -Sy;
Mx.M[2][1] = Cy*Sx;
Mx.M[2][2] = Cx*Cy;
break;
case ORDER_YXZ:
Mx.M[0][0] = Cy*Cz + Sx*Sy*Sz;
Mx.M[0][1] = Cz*Sx*Sy - Cy*Sz;
Mx.M[0][2] = Cx*Sy;
Mx.M[1][0] = Cx*Sz;
Mx.M[1][1] = Cx*Cz;
Mx.M[1][2] = -Sx;
Mx.M[2][0] = -Cz*Sy + Cy*Sx*Sz;
Mx.M[2][1] = Cy*Cz*Sx + Sy*Sz;
Mx.M[2][2] = Cx*Cy;
break;
case ORDER_XZY:
Mx.M[0][0] = Cy*Cz;
Mx.M[0][1] = -Sz;
Mx.M[0][2] = Cz*Sy;
Mx.M[1][0] = Sx*Sy + Cx*Cy*Sz;
Mx.M[1][1] = Cx*Cz;
Mx.M[1][2] = -Cy*Sx + Cx*Sy*Sz;
Mx.M[2][0] = -Cx*Sy + Cy*Sx*Sz;
Mx.M[2][1] = Cz*Sx;
Mx.M[2][2] = Cx*Cy + Sx*Sy*Sz;
break;
}
return(Mx);
}
FWIW,某些CPU可以同时计算Sin&Cos(例如x86上的fsincos)。 如果执行此操作,则可以通过三个调用而不是6个来更快地计算初始sin&cos值。
更新:实际上,共有12种方法,具体取决于您想要的是惯用右手还是惯用左手的结果-您可以通过否定角度来更改“惯用性”。