three.js で始めるオイラー角とクォータニオンについて
3Dオブジェクトの回転について勉強しました。
オブジェクトの姿勢(角度)を表すのには、
下記の2つの方法があるようです。
- オイラー角
- クォータニオン
オイラー角
オイラー角による回転角の指定とは
直交座標系(X,Y,Z)の軸に対して、
それぞれに回転角を指定する方法。
xは何度
yは何度
zは何度
という感じ。
回転角の演算の順番
x,y,z それぞれの角度の適用順序によって
最終的な姿勢は異なる事になる。
three.js の演算順はデフォルトで
X-Y-Z の順番で演算される。
(変更することも可能。)
オイラー角による指定
arrows.rotation.x = Math.PI / 6;
arrows.rotation.y = Math.PI / 6;
arrows.rotation.z = Math.PI / 6;
直交座標系に対して角度を設定し、
最終的にレンダリングする際に計算される。
計算される際にX-Y-Zの順で演算するという事なので、上記コードの指定順がレンダリングに影響するわけではない。
ジンバルロック
ジンバルとは、ジャイロスコープなどに使われる。
それぞれの軸が直交するようにリングを重ねたもので、物体を回転させる回転台となる。
三軸あるものが一般的。
そして、ジンバルロックとは、
三軸のうちに2軸が同一平面上に揃う場合に、自由回転出来なくなる現象。
ジンバルリングがロックしちゃうから、
ジンバルロックという。
これを回避するためには、更にもう1つ軸を追加する事で回避できる。
アポロ13号のジャイロスコープの話しでも出てくるみたいですが、アポロ13号では軽量化のために四軸ではなく、三軸を採用していたそうです。
そのため、ジンバルロックが発生しない角度で運航できるように、経路を計画していたようです。
クォータニオン(四元数)
正規化された、ベクトルに対しての回転度を表す。
オイラー角とは違い、直交座標系(xyz)に対してそれぞれの回転角を指定するのではなく、任意の方向を軸に回転させるというものだ。
こちらの方法は、任意方向で回転軸が1つになる為に、
ジンバルロックという現象が発生しない。
3D演算では主にこちらが採用されている。
Unity では、内部では全てクォータニオンで扱っているとの事。
var axis = new THREE.Vector3(1,1,1);
axis.normalize();
var angle = Math.PI / 3;
var q = new THREE.Quaternion();
q.setFromAxisAngle(axis, angle);
新しいクォータニオンを生成してmultipleメソッドで積をする事で、更に回転させる事が可能。
しかし、x軸、y軸、z軸、それぞれにクォータニオンを使って、指定した場合と、
オイラー角でそれぞれに回転角を指定するのは、一体何が違うのだろうか…。
同様にジンバルロックは起こらないものなのかな??
このmultipleの積の処理が何か特別なロジックになっているのだろうか…。
(謎は深まるばかり。。)
おしまい
プログラム的に扱いやすいのは、オイラー角だが、
ジンバルロックというものが発生するために、気軽に使ってると罠にはまりそうです。
クォータニオンは、難しく見えるが
実空間においてこっちに回転させたいと、直感的に操作できるのは、こちらのクォータニオンだと思いました。
こういうものだ、こうやって使うという事は分かったものの、
内部的にどういった計算がされているのかまでは理解できなかった…。
そもそも、
ジンバルロックすら正直イメージできないので、地球ゴマでも買ってみれば、イメージできるようになるのかな?