ピッチ角、ロール角、ヨー角があります。これらを方向ベクトルに変換するにはどうすればよいですか?
これのクォータニオンおよび/または行列表現を見せていただければ、特にクールです!
ピッチ角、ロール角、ヨー角があります。これらを方向ベクトルに変換するにはどうすればよいですか?
これのクォータニオンおよび/または行列表現を見せていただければ、特にクールです!
残念ながら、これらを定義する方法にはさまざまな規則があり (また、ロール、ピッチ、ヨーはオイラー角とはまったく同じではありません)、注意が必要です。
ピッチ = 0 を水平 (z = 0) として定義し、ヨーを x 軸から反時計回りとして定義すると、方向ベクトルは次のようになります。
x = cos(ヨー)*cos(ピッチ) y = sin(ヨー)*cos(ピッチ) z = sin(ピッチ)
ロールを使用していないことに注意してください。これは方向単位ベクトルであり、姿勢を指定しません。飛行物体のフレームに物を運ぶ回転行列を書くのは簡単ですが (たとえば、左翼端がどこを指しているか知りたい場合)、最初に規則を指定することをお勧めします。問題について詳しく教えていただけますか?
編集:( 私は2年半の間、この質問に戻るつもりでした。)
完全な回転行列の場合、上記の規則を使用し、ベクトルを最初にヨー、次にピッチ、次に回転させたい場合は、ワールド座標フレームで最終的な座標を取得するために、逆の順序で回転行列を適用する必要があります。
最初のロール:
| 1 0 0 |
| 0 cos(roll) -sin(roll) |
| 0 sin(roll) cos(roll) |
次にピッチ:
| cos(pitch) 0 -sin(pitch) |
| 0 1 0 |
| sin(pitch) 0 cos(pitch) |
次に、ヨーイングします。
| cos(yaw) -sin(yaw) 0 |
| sin(yaw) cos(yaw) 0 |
| 0 0 1 |
それらを組み合わせると、総回転行列は次のようになります。
| cos(yaw)cos(pitch) -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) -cos(yaw)sin(pitch)cos(roll)+sin(yaw)sin(roll)|
| sin(yaw)cos(pitch) -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) -sin(yaw)sin(pitch)cos(roll)-cos(yaw)sin(roll)|
| sin(pitch) cos(pitch)sin(roll) cos(pitch)sin(roll)|
したがって、x 軸から始まる単位ベクトルの場合、最終的な座標は次のようになります。
x = cos(yaw)cos(pitch)
y = sin(yaw)cos(pitch)
z = sin(pitch)
y 軸 (左翼端) から始まる単位ベクトルの場合、最終的な座標は次のようになります。
x = -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll)
y = -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll)
z = cos(pitch)sin(roll)
適用される順序に応じて、3 つのオイラー角を行列に変換する 6 つの方法があります。
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 など)。これを行うと、sin と cos の初期値を計算するために 6 回ではなく 3 回の呼び出しで少し高速化できます。
更新: 実際には、右利きまたは左利きの結果が必要かどうかに応じて、12 の方法があります。角度を無効にすることで、「利き手」を変更できます。
ベータ版は私の一日を救いました。ただし、私はわずかに異なる参照座標系を使用しており、ピッチの私の定義はアップ\ダウン(一致して頭をうなずく)であり、正のピッチは負のyコンポーネントになります。私の参照ベクトルは OpenGl スタイル (-z 軸方向) であるため、yaw=0、pitch=0 の場合、結果の単位ベクトルは (0, 0, -1) に等しくなります。誰かがこの投稿に出くわし、ベータ版の式をこの特定のシステムに翻訳するのに苦労している場合、私が使用する方程式は次のとおりです。
vDir->X = sin(yaw);
vDir->Y = -(sin(pitch)*cos(yaw));
vDir->Z = -(cos(pitch)*cos(yaw));
符号の変化とヨー <-> ピッチのスワップに注意してください。これが誰かの時間を節約することを願っています。