Skip to main content

オイラー(Euler)回転の弱点:ジンバルロック

ここまで学んできた回転方法は「オイラー」(Euler)回転といい、x, y, zの各軸ごとに別々に回転することにより、オブジェクトに連続に適用すると、自由に回転できる…

image.png

設定しても、回転順番を決めないといけない。X→Y→Z / Y→Z→X / X→Z→Y などの様々な組み合わせがあり、それぞれの最終結果がことなるので、混乱する可能性がある。

 また、「ジンバルロック」という問題もある。次の装置を見てください。この装置は「X(赤)→  Y(緑)→  Z(青)」の順番で回転する装置。この状態で、物体が各軸の周りの回転を自由にできる。

X 軸の周り

image116.gif

image158.gif

Y 軸の周り
Z 軸の周り

image243.gif

 ここで、Y軸の周りを90度回転してみると2つの回転軸が重なってしまうこの状態は「ジンバルロック」といい、1つの回転自由度が失ってしまった:

  • 重なったXとZを回転しても、同じ回転になってしまう。
  • 矢印の方向に回転したくても、できない

image154.gif

 この場合はうまく回転できなくなるので、何かの解決を実装しないといけない。

一時的な解決:Angle-Axis(度-軸)回転

 ジンバルロックになってしまった場合、一時的に新しい回転軸を作成し、その「仮想軸」の周りに回転ができる。この方法を使うと、定番のXYZだけではなく、お好みのベクトルの周りに回転ができる。

image.png

 式は、今までの回転と同じアイデアである。sinとcosを使うが、回転する面はあるベクトル「v」を直交する

 この場合は、回転行列は以下のようになる:

image.png

ここで、

image.png


image.png


θ は回転角度で、

 

v は回転軸になる任意の3D単位ベクトルである



image.png

image.png

これは今までの回転行列の一般な形である。例えば、回転軸は Z にすると:

image.png

とすると、行列を更新すると:

image.png

image.png

image.png

でも、image.png、なので…

image.png

これで、Z 軸周りの回転行列に戻った!

Unityのサポート

Unityでは「Quaternion.AngleAxis」を使用し、任意の軸周りの回転ができる:

// 以下、X 軸周りに45度を回転する相当:
Vector3 axis = new Vector3(1, 0, 0); // 軸
float angle = 45; // 角度

transform.localRotation = Quaternion.AngleAxis(angle, axis); // 度・軸の回転

練習

惑星と月を真似しましょう。月が惑星の軸周りを従って回転させましょう:

  • Moonスクリプトを作成し、
    • 回転速度
    • 追跡する惑星
    • 惑星から離れる距離
  • Inspectorで設定できるようにする
  • Quaternion.AngleAxis を使用し、惑星の「上向きベクトル」(transform.up) の周りに回転する
  • 実行し、Sceneビューで惑星を傾いて、回転を確認する。

汎用的な解決
Quaternion(クォータニオン - 四元数)

「クォータニオン」は、回転を表す4次元の数値である。一般な形は

image.png

ここでは、「+」は加算ではなく、次元を表してる。ベクトルの表現にすると:

image.png

 と等しいのである。4次元の数値であるため演算は多少ややこしいので、ゲームで使う目的だけに注目しましょう。

 単位クォータニオンの特徴は:

  • ジンバルロックせず、どの回転でも表現ができる
  • 2つのクォータニオンを乗算は、2つの回転を連続に適用すると同じものである
  • 逆クォータニオン(共役)は、逆回転と同じである
  • クォータニオン⇔回転行列の変換ができる

 クォータニオンがゲームの中で回転でよく使われるので、Unityがすでに実装されている。Unityは「Quaternion」というクラスがあり、すべての回転は「Quaternion」で行う。そもそも「transform.rotation」のデータ型は「Quaternion」だ!

// Unityの中で、すべての回転は「Quaternion型」である
Quaternion rot = transform.rotation; 

オイラー角度と Quaternion の変換

Unityではオイラー角度(XYZ回転)と Quaternion の変換メソッドが実装されている:

// 回転を Quaternion として表現されている
Quaternion rotA = transform.rotation;

// オイラー角度を知りたいなら:
Vector3 angles = rot.eulerAngles;

// 逆に、オイラー角度から Quaternion にしたいなら:
Quaternion rotB = Quaternion.Euler(x, y, z); // x, y, z は各軸の回転である

// このまま回転として利用できる
transform.rotation = rotB;

掛け算(乗算)

クォータニオンが重要なので簡単にクォータニオンの掛け算を理解していきましょう。なお、式を覚えるよりも、掛け算はどのような影響があるのかを覚えてください。

2つのクォータニオン「q」と「p」があり、それぞれは別の回転であるとしたら「p × q」は、連続に2つの回転を適用したことと同じである。

クォータニオン「p」による回転

image281.gif

クォータニオン「p」による回転

image137.gif

クォータニオン「q」による回転

image54.gifq × p の結果

式は教科書にある(泣きたくなるぐらい大変)が、Unity の Quaternion なら「*」で計算できる:

// 「p」と「q」それぞれは「Quaternion」である
Quaternion qp = q * p; 

 注意:クォータニオンの積は可換でない。回転の順番により、最後の結果が変わるので、行列と同様に:

image.png

image54.gif

q × p

image177.gif

p × q

回転行列との関係

任意の単位クォータニオンを今まで勉強してきた回転行列として表現ができるので、他の変換と組み合わせることができる。

image.png

「a, b, c, d」はクォータニオンの成分である。これで、クォータニオンを回転行列に変換でき、他の変換(移動、拡大縮小)との連結できるようになる。