Redpoll's 60
 Home / 3Dプログラミング入門 / 第3章 $§$3-15
第3章 3D空間の基礎

$§$3-15 オイラー角 2


前節に引き続き、オイラー角による回転について扱う。本節では、オブジェクトの姿勢制御をオイラー角経由で行うことについて見ていく (前節でも述べたが、この講義におけるオイラー角回転は Z-X-Yオーダーの extrinsic rotations である)。


A) オブジェクトの姿勢制御

オブジェクトに対して実行する変換は平行移動、回転、スケールの3つである。3D空間内におけるオブジェクトの運動は、この3つの変換を合成したものをオブジェクトに対して実行することで実現される。オブジェクトの姿勢制御は、オブジェクトに対して実行する3つの変換のうち、主として回転に関係するものである。すなわち、オブジェクトに何らかの姿勢をとらせるためには、その姿勢にするために必要な回転をオブジェクトに実行する必要がある。
ここでは、姿勢を制御するための回転をオイラー角によって指定し、回転の表現形式には今まで通り回転行列を用いる。

問題を簡単にするために、今回はオブジェクトの姿勢制御に必要な回転行列は1つのみとし、この1つの回転行列をオブジェクトに実行することでオブジェクトの姿勢を制御する(例えば、人体のような複雑なオブジェクトの場合は、姿勢制御のために数十個から数百個のボーンと呼ばれるオブジェクトを用意し、人体を運動させる際には、それらのボーンの1つ1つに回転を実行するのである)。

図1のオブジェクトMiniPlaneは、初期状態で中心部分が原点に置かれており、オブジェクトの先端がちょうどz軸上の $z = -1$ にある。図2はMiniPlaneと半径1の球面である。球面の半径は$1$なので、初期状態でのMiniPlaneの先端は球面上の$(0,\ 0,\ -1)$にある。

図1 MiniPlane 初期状態
図2 MiniPlaneと単位球面(半径1)

本節におけるアニメーションは、次のコードにおけるオイラー角の数値を変えてMiniPlaneに実行した結果である。
Matrix4x4 R_zxy = TH3DMath.GetEulerRotation4x4(i_eulX, i_eulY, i_eulZ);
MiniPlane.SetMatrix(R_zxy);

TH3DMath.GetEulerRotation4x4() は前節でも使用したカスタムライブラリーのメソッドで、引数で指定された3つの角度を元にして、オイラー角による$4\times4$の回転行列を計算するものである。取得される回転行列 R_zxy は、z軸周りの回転、x軸周りの回転、y軸周りの回転をこの順序で行う行列である。
i_eulXi_eulYi_eulZ は、それぞれ xー角度、y-角度、z-角度を表すインスタンス変数で、本節の図における白い数字はこれらの値を表したものである (前節と同じく本節においても x軸周りの回転角度、y軸周りの回転角度、z軸周りの回転角度を x-角度、y-角度、z-角度 と表記する)。


以下の図は初期状態のMiniPlaneに対して、左から x-角度だけを変化させたもの、y-角度だけを変化させたもの、z-角度だけを変化させたものである。

  • 図3 x-角度を変化させる
  • 図4 y-角度を変化させる
  • 図5 z-角度を変化させる(Roll)

前節と同様に球面上の縦方向の線を経線、横方向の線を緯線とすれば、これら3つの運動は次のように表される。
x-角度だけを変える場合、MiniPlaneの先端は縦方向の線、つまり経線上を動く(図3 ; y-角度を変化させていない状態ではx軸周りの回転と同じである)。
y-角度だけを変える場合、MiniPlaneの先端は横方向の線、つまり緯線上を動く(図4)。
z-角度だけを変える場合は、MiniPlaneの先端は球面上での位置は変化しない。この場合のMiniPlaneは、その場所においてRoll回転を行う(図5 ; x-角度、y-角度を変化させていない状態におけるRoll回転は図に示されるようにz軸周りの回転と同じである)。


次の図は、y-角度を左から $y = 60^\circ$、$y = -90^\circ$に固定して、x-角度だけを変化させたものである。

図6 x-角度の変化 (y = 60°)
図7 x-角度の変化 (y = -90°)

y-角度を $60^\circ$ に固定して、x-角度だけを変化させる場合は、MiniPlaneの先端が経度 $60^\circ$ の経線上を動く(図6)。
y-角度を $-90^\circ$ に固定して、x-角度だけを変化させる場合は、MiniPlaneの先端が経度 $-90^\circ$ の経線上を動く(図7)。


次の図は、x-角度、y-角度を左から $(x = 20^\circ,\ y = 80^\circ)$、$(x = -10^\circ,\ y = -120^\circ)$に固定して、z-角度だけを変化させたものである。

図8 z-角度の変化 (緯度 20°, 経度 80°)
図9 z-角度の変化 (緯度 -10°, 経度 -120°)

z-角度だけを変化させる場合は、MiniPlaneの先端が球面上のどの位置にあっても、その場所でRoll回転をするのである。たとえば、図8ではMiniPlaneの先端が球面上の緯度 $20^\circ$ 、経度 $80^\circ$ にある状態でRoll回転をしている (図には表示されていないが、このRoll回転はMiniPlaneの先端と原点を結ぶ軸を回転軸とする回転になっている)。


次の図は、x-角度を左から $x = 10^\circ$ 、$x = 20^\circ$ に固定して、y-角度だけを変化させたものである。

図10 y-角度の変化 (x = 10°)
図11 y-角度の変化 (x = 20°)

x-角度を $10^\circ$ に固定して、y-角度だけを変化させる場合は、MiniPlaneの先端が緯度 $10^\circ$ の緯線上を動く(図10)。
x-角度を $20^\circ$ に固定して、y-角度だけを変化させる場合は、MiniPlaneの先端が緯度 $20^\circ$ の緯線上を動く(図11)。


以上を要約する。
今回のMiniPlaneは初期状態で、その中心部分が原点に置かれている。このとき、MiniPlaneの先端はz軸上の $z = -1$ すなわち、$(0,\ 0, -1)$に位置している。オイラー角による回転行列をMiniPlaneに実行するとき、MiniPlaneの先端は半径$1$の球面上の運動を行うが、MiniPlaneの先端に着目してこの運動を述べると次のようになる。
MiniPlaneの先端が、球面上のどこにあっても
x-角度を変化させると、その位置から縦方向、すなわち経線上を動く。
y-角度を変化させると、その位置から横方向、すなわち緯線上を動く(ただし、極点においてはあてはまらない)。
z-角度を変化させると、その位置でRoll回転を行う。


B) ジンバルロック

次の図12、図13は、x-角度を左から $x = 70^\circ$ 、$x = 80^\circ$ に固定して、y-角度だけを変化させたものである。それぞれ、MiniPlaneの先端が緯度 $70^\circ$、$80^\circ$ の緯線上で運動することになる。

図12 y-角度の変化 (x = 70°)
図13 y-角度の変化 (x = 80°)

先ほどの図10、図11、及び今回の図12、図13はMiniPlaneの先端の緯線上の運動であるが、具体的には緯線の作る円周上をMiniPlaneの先端が回転することになる。図10、図11は緯度 $10^\circ$、緯度 $20^\circ$ の緯線上の運動であるが、そういった低緯度地帯では緯線の作る円周が大きいために、MiniPlaneの先端の動く範囲も大きい。
x-角度を増加させると、MiniPlaneはその先端をより高い緯度に向けるようになる。
図12、図13は緯度 $70^\circ$、緯度 $80^\circ$ の緯線上の運動であるが、このような高緯度地帯になると緯線の作る円周が小さくなるために、MiniPlaneの先端の動きも小さい範囲になっていく。
さらにx-角度を上げていき、最終的に $x = 90^\circ$ の状態にした結果が図14である。
図14においては、MiniPlaneの先端は球面上の極点(地球における北極)を向いている。極点には緯線が存在しないので、緯線の作る円周も存在しない。したがって、MiniPlaneの先端はこの状態においては緯線の作る円周上を動くということができなくなるわけである。

図14 x-角度 90°(x軸周りの90°の回転)
図15 y-角度の変化 (x = 90° ; ジンバルロック)

オイラー角による回転において、このような状態をジンバルロック(Gimbal lock)という。図15は、この状態からy-角度を変化させたアニメーションである。
ジンバルロックでは運動の次元が1つ減るといった表現もされる。今回の例では、y-角度を変化させてもMiniPlaneの先端は(緯線がないために)緯線方向の運動ができなくなっている。

では、図14の状態から x-角度を変化させたもの、z-角度を変化させたものを図16、図17に示す。

図16 x-角度の変化 (x = 90° を中心とする)
図17 z-角度の変化 (x = 90°)

MiniPlaneの先端が極点を向いている場合でも、x-角度を変化させれば先端部分は経線上を動く(図16)。
z-角度を変化させると、その位置でRoll回転をすると先に述べたが、この場合のようにMiniPlaneの先端が極点を向いている場合でも z-角度を変化させると、他の場合と変わりなくRoll回転をする(図17)。
図15、図17を比較すればわかるように、Z-X-Yオーダーのジンバルロックでは、y-角度を変化させる運動と、z-角度を変化させる運動は同じものになってしまうのである。


C) 補足
ここでは MiniPlaneを使用した回転の各状況において、Z-X-Yオーダーのオイラー角による回転の回転軸を表示する。図30に示されるR軸、B軸は今回使用する補助的な道具で、MiniPlaneに実行する回転において、実際の回転軸の役割を務める。R軸は初期状態でx軸と重なっており、B軸は初期状態でz軸と重なっている(長さは同じであり、2つの軸は原点で交差している)。
回転については上で見てきたように、MiniPlaneの先端の回転に着目する。まずはy-角度を変化させる場合の回転である。Z-X-Yオーダーのオイラー角による回転では、y-角度を変化させる場合は図32に示されるように、MiniPlaneの先端は必ずy軸周りの回転、すなわち球面における緯線上を回転する(先端が球面上のどこに位置していても、その位置から緯線上を回転する)。

  • 図30 R軸とB軸
  • 図31 初期状態
  • 図32 y-角度を変化させる

図32での回転ではMiniPlaneとともにR軸、B軸も回転している。R軸、B軸は、x-角度、z-角度を変化させるときの回転軸となるものであるが、以下でそれを見てみよう。

図33 x-角度を変化させる (y = 70°)
図34 z-角度を変化させる (x = 50°, y = 70°)

図33は、x-角度を変化させるときの様子である。前節でも述べたが、Z-X-Yオーダーのオイラー角による回転では、x-角度を変化させる場合の回転軸はx軸とは限らない。その回転軸は、図33に示されるようにR軸である(x軸周りの回転になるのは、x軸とR軸が重なっている場合のみである)。
本節で何度か述べたように、x-角度を変化させるとMiniPlaneの先端はそのときの位置から経線上を運動する。経線も緯線と同様に球面上では円周を作っているが、この経線の作る円周というのは、MiniPlaneの先端からR軸へ垂線を下ろし、その垂線の足を中心とし、垂線を半径とする円周のことである(3-10節参照)。
また、x-角度を変化させるとMiniPlaneとともにB軸も回転することに注意(Z-X-Yオーダーのオイラー角による回転では、y-角度を変化させるとR軸、B軸が回転し、x-角度を変化させるとB軸のみが回転する)。
図34は、z-角度を変化させるときの様子である。Z-X-Yオーダーのオイラー角による回転では、z-角度を変化させる場合においても、その回転軸はz軸とは限らない。回転軸は、図34に示されるようにB軸である(z軸周りの回転になるのは、z軸とB軸が重なっている場合のみである)。
z-角度を変化させるとMiniPlaneは、その位置でRoll回転をする(先端の位置は動かない)。図34からわかるように、これはB軸周りの回転を行っているのである。





# Code1
本節のアニメーションにおけるMiniPlaneの運動は次のプログラムを実行したものである。

[Code1]
if (Input.GetKeyDown(KeyCode.X))
{
    i_eulX += (THUtil.IsShiftDown()) ? -10 : 10; 
}
else if (Input.GetKeyDown(KeyCode.Y))
{
    i_eulY += (THUtil.IsShiftDown()) ? -10 : 10; 
}
else if (Input.GetKeyDown(KeyCode.Z))
{
    i_eulZ += (THUtil.IsShiftDown()) ? -10 : 10; 
}

Matrix4x4 R = TH3DMath.GetEulerRotation4x4(i_eulX, i_eulY, i_eulZ);
MiniPlane.SetMatrix(R);

このプログラムは、Xキー、Yキー、Zキーを押して i_eulXi_eulYi_eulZ の値を変化させるもので、1回押すごとに角度が $10^\circ$ ずつ増加する(長押しには対応していない)。また、Shiftキーと同時に押すと角度が $10^\circ$ ずつ減少する (プログラム中の THUtil.IsShiftDown() はShiftキーが押されていればtrueを返すカスタムライブラリのメソッドである)。
なお、このCode1及び次のCode2では x-角度の変更範囲は $-90^\circ$ から $90^\circ$ の範囲に制限してある。つまり、x-角度を押し続けても $90^\circ$ あるいは $-90^\circ$ を越える値にはならない。

プログラム実行中に各キーを押すことで、MiniPlaneの先端が球面上において経線、緯線上を $10^\circ$ ずつ移動したり、あるいは MiniPlaneがそのときいる場所において $10^\circ$ ずつRoll回転を行うようになる。


# Code2
Code1では、MiniPlaneの運動はキーを1回1回押さなければいけないものあったが、次のプログラムはキー操作をキーの長押しに変更し、MiniPlaneの運動がなめらかに行われるようにしたものである。

[Code2]
if (Input.GetKey(KeyCode.X))
{
    i_eulX += (THUtil.IsShiftDown()) ? -1 : 1; 
}
else if (Input.GetKey(KeyCode.Y))
{
    i_eulY += (THUtil.IsShiftDown()) ? -1 : 1; 
}
else if (Input.GetKey(KeyCode.Z))
{
    i_eulZ += (THUtil.IsShiftDown()) ? -1 : 1; 
}

Matrix4x4 R = TH3DMath.GetEulerRotation4x4(i_eulX, i_eulY, i_eulZ);
MiniPlane.SetMatrix(R);

このプログラムは、Code1において Input.GetKeyDown(..) となっていた箇所を Input.GetKey(..) に変え、1フレームあたりの角度の増減を $1^\circ$ ずつに変更しただけである。












© 2020-2024 Redpoll's 60 (All rights reserved)