3D アプリケーションの回転は、たいていクォータ二オンかオイラー角のどちらかによって表されています。 それぞれ、利点と欠点があります。Unity では内部でクォータ二オンを採用していますが、編集しやすいように、インスペクターでは同等のオイラー角で表しています。
オイラー角は、3つの角度の値を X、Y、Z 軸に順に当てはめて回転を表す簡易な方法です。オイラー角をあるオブジェクトに応用する場合は、オブジェクトを各軸に沿って与えられた角度で回転させます。
クォータニオンは、オブジェクトの向きや回転を表すのに使用されます。この表現法では、内部で 4つの数字 (Unity では x、y、z、w と呼びます) で構成されています。ただし、この数字は、角度や軸を表現しているわけでなく、通常、直接アクセスすることはありません。クォータ二オン (四元数)について特別に興味がない限り、クォータニオンが 3D 空間の回転を表しているのだということを知っているだけで十分で、通常、x、y、z プロパティーを操作したり変更することはありません。
ベクトルが位置と方向 (方向は原点から測ります) を表現するのと同様に、クォータ二オンは向きと回転を表現できます。回転は、回転「基準」か「単位」を基準に測られます。回転を、ある向きからもう一方の向きへの方向として計測するため、クォータ二オンでは、180度より大きな回転を表現することができません。
Unity では、ゲームオブジェクトのすべての回転は、内部ではクォータ二オンで保存します。なぜなら、利点のほうが、制限を上回るためです。
しかし、Transform Inspector では、回転は、理解しやすく編集しやすいオイラー角で表示されます。 ゲームオブジェクトを回転させるために Inspector に新しい値を入力すると、目に見えない内部で、新しいクォータニオン回転値に変換されます。
この影響で、Inspector に X: 0、Y: 365、Z: 0 といったゲームオブジェクトの回転値の入力が可能になります。このような値はクォータニオンでは表せないため、プレイするとき、オブジェクトの回転値は X: 0、Y: 5、Z: 0 (または、これに近い値) に変わります。これは「360度のフル回転プラス 5度」という概念のないクォータニオンに、回転値が変換されたためです。値は、回転が同じ方向になるように、単純に置き換えられたものです。
スクリプトで回転を扱うとき、Quaternion クラスとその関数を使用し、回転値を作成、変更します。ある状況では、オイラー角の使用が有効な場合もあります。ただし、以下の注意が必要です。 - オイラー角を扱える Quaternion クラス関数を使用してください。 - 回転からオイラー角を取得、変更、再適用することは、意図しない作用の原因になることがあります。
Unity の Quaternion クラスには、多くの関数が備わっており、オイラー角をまったく使用しないで回転を作成し、操作することができます。以下は、その例です。
作成
操作
ただし、スクリプトでオイラー角を使用したほうがよい場合があります。そのような場合は、角度を変数に代入し、オイラー角として回転に適用するためにだけ使用することが重要です。オイラー角をクォータニオンから取得することは可能ですが、取得、変更、再適用すると、問題が発生します。
ここで、一般的によくある誤りの例を、オブジェクトを X 軸の周りで 1秒につき 10度回転させようとする場合を例にとって紹介します。以下は誤った使用法です。
// rotation scripting mistake #1
// the mistake here is that we are modifying the x value of a quaternion
// this value does not represent an angle, and will not produce desired results
void Update () {
var rot = transform.rotation;
rot.x += Time.deltaTime * 10;
transform.rotation = rot;
}
// rotation scripting mistake #2
// the mistake here is that we are reading, modifying then writing the Euler
// values from a quaternion. Because these values calculated from a Quaternion,
// each new rotation may return very different Euler angles, which may suffer from gimbal lock.
void Update () {
var angles = transform.rotation.eulerAngles;
angles.x += Time.deltaTime * 10;
transform.rotation = Quaternion.Euler(angles);
}
以下は、スクリプトでオイラー角を使う時の正しい使用法です。
// rotation scripting with Euler angles correctly.
// here we store our Euler angle in a class variable, and only use it to
// apply it as a Euler angle, but we never rely on reading the Euler back.
float x;
void Update () {
x += Time.deltaTime * 10;
transform.rotation = Quaternion.Euler(x,0,0);
}
Unity 内部のアニメーションウィンドウを含め、多くの 3D オーサリングパッケージでは、アニメーションの間に、オイラー角で回転を指定することができます。
このような回転値は、しばしば、クォータニオンで表現できる範囲を超越することがあります。例えば、オブジェクトがその場で 720度回転する場合、オイラー角では X: 0、Y: 720、Z:0 と示します。しかし、これは、実際にクォータニオンで表現できる値ではありません。
Unity のアニメーションウィンドウ内で、どのように回転を補間するか ( クォータニオンとオイラー角どちらを使用するか ) を指定できるオプションがあります。オイラー角での補間を指定すると、Unity は角度で指定されたすべての範囲を含む動きを可能にします。一方、クォータニオン回転では、単に特定の向きを向かせることが目的なので、Unity は、クォータニオン補間で最短距離を通って回転させます。詳しい情報は、アニメーションカーブを使用するを参照してください。
アニメーションを外部ソースからインポートする場合、これらのファイルは、通常はオイラー形式の回転キーフレームアニメーションを含んでいます。Unity のデフォルトのビヘイビアでは、これらのアニメーションをリサンプルして、各フレームごとに新しくクォータニオンキーフレームを生成し、キーフレーム間の回転がクォータニオンの有効範囲を超える状況をすべて回避しようとします。
例えば、6フレーム離れた 2つのキーフレーム ( 最初のフレームの X値が 0、 2番目のフレームの X値が270 ) があるとします。リサンプリングしないと、クォータニオン補間で、この 2つのキーフレームを逆方向に 90度回転させます。なぜなら、これが、最初の向きから2番目の向きにするための最短の方法だからです。しかし、リサンプリングして各フレームにキーフレームを加えると、今度はキーフレーム間に45度しかないので、正しく回転します。
リサンプリングを行っても、インポートしたアニメーションのクォータニオン表示がオリジナルに十分近い値にならない場合があります。このため、Unity 5.3 以降では、アニメーションリサンプリングをオフにするオプションがあります。これを使うと、代わりに、ランタイムにオイラーアニメーションキーフレームを使用します。詳しい情報は、Animation Import of Euler Curve Rotations を参照してください。