今回はUnityでゲームオブジェクトの回転について見ていきます。
UnityのインスペクタではTransformのRotationでゲームオブジェクトの角度を見る事が出来ますが、これはオイラー角を表しています。
しかしUnityの内部ではQuaternion型で角度の処理をしています。
Quaternion型の数値は人が見てすぐにわかる数値ではないのでインスペクタではオイラー角で表示されています。
内部でオイラー角を使わない理由はジンバルロックが発生するからだそうですが、わたくしには何のことやら・・・・(^_^;)
その辺りは
Unityのスクリプトリファレンスを見てください。
Unityのスクリプトでもオイラー角をQuaternion型へと変換しそれをキャラクターの角度に設定したりと必ず変換をして角度を変更しています。
よく使用するのがQuaternion.Eulerで指定したオイラー角をQuaternion型に変換します。
Quaternion.Euler(0, 90, 0)
ではXを0、Yを90、Zを0のオイラー角をQuaternion型に変換し利用しています。
ゲームオブジェクトを回転させる
ゲームを本格的に制作していくとゲームオブジェクトの角度を扱う場面によく遭遇する事になります。
主人公キャラを敵キャラの方に向かせたい、主人公キャラと敵キャラの位置の角度の計算をしたいといった場面です。
これらの処理はtransform.LookAtやVector3.Angleを用いて機能を作成する事が出来ます。
他には、あるゲームオブジェクトを他のゲームオブジェクトからの角度で相対的に変更したい場面があります。
つまり現在の角度の状態から新しい角度回転させるという場合です。
文章を見ても解り辛いですね・・・・(^_^;)
ゲームオブジェクトを回転させるサンプル
試しにサンプルを作成し実行してみましょう。
↑のように2つのCubeを作成し、回転するゲームオブジェクトをRotatingGameObject、回転角度用のゲームオブジェクトをRotationAngleとします。
RotatingGameObjectは↑のような角度に設定しました。
RotationAngleの角度は↑のようにしました。
左がRotationAngleで右がRotatingGameObjectになります。
次にスクリプトを作成し、マウスの左ボタンが押されるたびにRotatingGameObjectの角度をRotationAngleの角度分変更していきます。
スクリプトはRotatingGameObjectゲームオブジェクトに設定します。
RotationTestのインスペクタのobjにRotationAngleゲームオブジェクトをドラッグ&ドロップして設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using UnityEngine; using System.Collections; public class RotationTest : MonoBehaviour { public Transform obj; void Update () { if (Input.GetButtonDown ("Fire1")) { transform.rotation = transform.rotation * obj.rotation; } } } |
元の角度から新しい角度の影響を与えるには元の角度に新しい角度をかけます。
オイラー角で表した場合(実際はQuaternion型)、元の角度が(0, 0, 0)でこれを(0, 90, 0)度変更するには
(0, 0, 0) × (0, 90, 0)
とします。
すると(0, 90, 0)という角度が得られます。
もう一回同じ事をすると
(0, 90, 0) × (0, 90, 0)
なので(0, 180, 0)が得られます。
前の角度から90度回転させているのでこうなります。
↑のスクリプトの例ではRotatingGameObjectゲームオブジェクトの角度をインスペクタで設定したobjの角度分回転させています。
Quaternionの角度は掛けるとその分の回転結果が得られますが、オイラー角の場合は
Transform.Rotate
を使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using UnityEngine; using System.Collections; public class RotationTest : MonoBehaviour { public Transform obj; public Transform otherBase; void Update () { if (Input.GetButtonDown ("Fire1")) { Debug.Log ((transform.rotation * obj.rotation).eulerAngles); transform.rotation = transform.rotation * obj.rotation; otherBase.Rotate (obj.eulerAngles, Space.Self); Debug.Log (otherBase.eulerAngles); } } } |
別のゲームオブジェクトotherBaseをobjの角度分回転させる場合は
otherBase.Rotate (obj.eulerAngles, Space.Self);
でotherBaseの角度をobjのオイラー角分回転させます。
第2引数がローカル(Space.Self)かワールド(Space.World)の角度で回転させるかの指定です。
ローカルとワールドの部分で少し混乱しますが、ゲームオブジェクトを選択した時にUnityのツールバーでローカルとワールド座標を切り替えられますが、
その状態で回転するかどうかです。
ローカルだとそのゲームオブジェクトが向いている向きを軸として回転させますが、ワールドだとX、Y、Z軸は常に同じ方向を向いていてその向きで回転させます。
今回の例ではotherBaseの角度をローカルで回転させています。
ローカルとワールドどちらで回転させるかわからなくなった時はツールバーでローカル、ワールドの座標を切り替えて確認してみるとわかりやすいです。
↑がワールド座標軸で表示した時で常に同じ方向を示しています。
Space.Worldを選択した場合はこの軸で回転させます。
↑がローカル座標軸で表示した時でそのゲームオブジェクトのローカルの方向軸を示しています。
Space.Selfまたは何も設定しない時はこの方向軸で回転させます。
それでは実行してみましょう。
↑のように元のゲームオブジェクトが自身の角度からRotateゲームオブジェクトの角度分回転していきます。
結局このサンプルのような事は何に使えるんだ!?
という声も聴こえてきそうですが・・・。
例えばキャラクターの向いている角度に合わせてそのゲームオブジェクトの角度を回転させたい時などです。
の当たりでこの角度の掛け算を利用しています。
角度にベクトルをかけた場合は何が得られる?
Quaternion型とQuaternion型をかけると最初の角度を次の角度分回転させた角度が得られますが、
Quaternion型にVector3型の値をかけると何が得られるんでしょうか?
Quaternion型にVector3の値をかけるとその角度方向のベクトル値(Vector3)が得られます。
試しにメインカメラにスクリプトを取り付け検証してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using UnityEngine; using System.Collections; public class RotateTest : MonoBehaviour { // Use this for initialization void Start () { Debug.Log (transform.rotation * new Vector3 (0f, 0f, 2f)); } // Update is called once per frame void Update () { Debug.DrawRay (transform.position, transform.rotation * new Vector3(0f, 0f, 2f), Color.red, 1f, true); } } |
Startメソッドでメインカメラの角度にVector3の(0f, 0f, 2f)をかけて出力しています。
出力した値だけでは解り辛いのでUpdateメソッドでメインカメラから角度にベクトルをかけた方向に線を引いてわかりやすく表示します。
↑のように角度にベクトルをかけるとその角度のベクトルが得られる事がわかります。
Vector3の(0f, 0f, 2f)と言う事はメインカメラの前方を表す(0f, 0f, 1f)の長さの2倍のベクトルです。
つまりメインカメラの角度に(0f, 0f, 2f)の方向ベクトルをかけるとメインカメラの前方のベクトルが得られます。
先ほどのメインカメラはRotationのX軸を20にしているので20度の方向のVector3(0f, 0f, 2f)のベクトルが求められます。
↑のような感じですね。
Debug.DrawRayでレイを視覚化しているのは長さが1mなので実際にはあと1m先が計算で求められる位置です。
Debug.DrawRayの長さも2にすればよかったかも・・・・(-_-)
終わりに
今回角度について取り上げたのは自分がいまいちわかっていなかったからです。
結局の所いまいちわかっていない状態は変わっていないですが・・・・(^_^;)
元の角度から回転させたい時も出てくると思うのでそんな時にこの記事が役立つかもしれません(謎)
わたくしは以前からオイラー角を足して計算した結果をそのままオイラー角に入れたり、Quaternion型に変換して角度を変更していますが、
オブジェクトを回転させる時はTransform.Rotateを使った方が良さそうですね。
オイラー角の場合計算結果が360を越えると角度がうまく計算されなくなるみたいなので、以前の記事も見直さないといけないかも・・・( ノД`)シクシク…