てんちょーの技術日誌

自分がつまづいたこととかメモ

【Unity】回転関連について整理してみた"実践編" C#

quaternionについて知りたい方はこちらから shop-0761.hatenablog.com

ユニティちゃんライセンス

このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。

さて、前回あれだけ悩まされた回転と、quaternionですがやりたい回転が思ったより簡単に実装できてしまって拍子抜けしてるところです。 というのも原因は滑らかに回転させたくてiTweenというAssetを使ってたのですが、これはこれで癖があったようで混乱してたみたいです。

実装したかったこと

こういうカメラ移動です。あっちこっち見上げたり見回したりする感じのあれです。 f:id:shop_0761:20150704114252g:plain

これを先週iTweenで実装するとこうなってました。 f:id:shop_0761:20150704114916g:plain 途中上下?にカメラも回転させて星空みれたらなと思ってたのですが、思うように制御できないせいでぐるぐるしてますね…

何のためにあんなにquaternionやったんだ…いらなかったんだ… 通りで記事が見つからないわけだ…

実装例

基本的には

                if (Input.GetKey(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, -3f, 0),Space.World);
        }

        if (Input.GetKey(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, 3f, 0), Space.World);
        }

        if (Input.GetKey(KeyCode.UpArrow))
        {
            transform.Rotate(new Vector3(-3f, 0, 0));
        }

        if (Input.GetKey(KeyCode.DownArrow))
        {
            transform.Rotate(new Vector3(3f, 0, 0));
        }

のように大人しくtransform.Rotateを使ってください。どこの記事でもそう書いてます。(iTweenで滑らかに…とかやるとハマりました) iTweenはお手軽です。わかりやすいです。けどちょっと凝ったことしようとすると途端に苦しくなる印象です。

だってRotateで生成するベクトルの大きさを小さくすればそれっぽく見えるんだもの。

ポイントとしてはy軸回転のみlocalで回転させないで、worldで回転させてるところですね。 今回は定点でのカメラ回転なのでなんとも言えませんが、こうすることで上手くいきました。

ちなみに全部localだとどうなるかunityちゃんに回ってもらうと f:id:shop_0761:20150704121557g:plain こうなります。unityちゃんが軸になってるのがよくわかります。

また全部worldだとこうなります f:id:shop_0761:20150704122012g:plain これは普通にworldの軸がよく見えます。

問題点

何度もRotateを実行してしまうため、非常にハイコストですね。 それなりのPCで実行する分にはなんてことはないと思いますが、GearVRのようにモバイルとなると話は変わってきますよね。 とはいっても、そういうのって視点移動はトラッキングがあるので気にしなくてもいいんじゃないかなとか思ってます。(持ってないけど)

他の回転方法

quaternionを使った回転方法もせっかくなのでやりたい。(基礎編の記事に時間かかったしまだ読むべきquaternionの資料もあるし)

無理やり書いてみるなら

transform.rotation = new Quaternion(1, 0, 0, 0) * new Quaternion(transform.position.x,transform.position.y,transform.position.z,0) * new Quaternion(-1, 0, 0, 0);  

前回の記事で言うところのRPQですね。これはunityの仕様で(x,y,z,w)の順で指定しなきゃいけません(wはcos(theta/2)) 簡単に言うと、x軸に対して180度回転する…はずです。

たしかにこれでも回転することは回転しますが、なにやら不穏な空気を感じたのでやめましょう。 そもそもコードが長くなるので美しくないです。

Quaternionで移動しよう

なにやらテラシュールブログさんによると、QuaternionにVectorをかけてVector?を得られるとのこと。 詳しくは見てください。 tsubakit1.hateblo.jp 3Dでやったけど上手く行かなかったです…

Quaternion.AngleAxis

これはその軸に関してだけの回転には使えます。が、実験してみると回転軸を変えて再度回転すると その前の初期位置に戻ってから回転する?みたいな挙動のためx軸に関して30度その後、y軸に関して30度みたいな回転ができないようです。 f:id:shop_0761:20150704134025g:plain これはそれぞれ軸ごとにAngleAxisを使って回転させるようにしてるのですが、ご覧のように回転軸が変わると よくない挙動します。これはその軸に関しての回転情報を保存しておいて、その軸に関してまた回転してねってなると、 保存しておいたところから回転を始めてる感じです。 これはまた大人しくRotateを使えということなのか。

おまけ1 オイラー角での制御

これは要するにいつも使ってる30度回転の30度って感じの度数で制御するやつです。たしかにこれは人間的にはわかりやすいのですが、 これだとジンバルロックが発生する可能性があります。 ジンバルロックはあっちこっちの記事で言われているとおり、ある条件を満たすと回転できなくなるあれです。 詳しくはこちらの記事とか見てみてください。

naochang | 座標変換:クォータニオン、オイラー角

なのでちょいとリスキーなのでUnityは全て内部的にはquaternionを使ってるみたいです。 オイラー角だけで制御するより、オイラー角に変換して、またquaternionに戻すみたいな使い方だとちょっと手間な感じありますね… ただ便利なのは具体的な角度で分岐させたいときはいいと思います。 直接値を書き換えるよりかは参照程度にしておく、みたいな使い方が個人的にはいいんじゃないかなとおもいます。

おまけ2 回転行列での制御

3次元の回転行列についてはそんなに詳しくないのですが、調べた限りだと行列だとデータが必然的に大きくなりがちなので あまり使われないみたいなのを見ました。 おとなしく quaternionしますね…

まとめ

あんなにquaternion勉強したのにそんなに出てこない!!嬉しい事なんだけど!! その分考慮されてUnityができてるんですね。というかよほど特殊なことをしない限りRotate使えば良さそうな気がしてます。 ひょっとしたらfpsの調整にまたこのquaternionが絡んできそうな予感も… 普通に回転するならRotate使いましょう。 次はshaderが気になってきたのでその辺かも