質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.14%

  • Unity

    2601questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

回転系のメソッドに関して。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 141

tkmnusr

score 107

前提・実現したいこと

回転系のメソッドがいろいろあって、よくわかってないのですが、
インスペクタでTransformのRotationの値を設定することと関係のあるメソッドについて知りたいです。

試したこと

  this.transform.rotation = Quaternion.Euler(0, 30, 0);
  this.transform.Rotate(0, 30, 0);


上記、試してみたのですが、

・Quaternion.Eulerは、インスペクタのTransformのRotationで、引数の値を設定するのと同じ。
・transform.Rotateは、インスペクタのTransformのRotationで、既存の値の後ろに+や-で連結して引数の値を入力するのと同じ。
  (インスペクタでTransformのRotationで、既存の値に対してtransform.Rotateの引数の値を加算や減算するのと同じ。)


という認識で合っていますか?
また、他にインスペクタでTransformのRotationの値を設定するのと同じ挙動のメソッドがあれば教えていただきたいです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

マニュアルによると、インスペクタ上のTransformコンポーネントのPosition、Rotation、Scaleは親に対する相対値だそうですので、インスペクタのRotationに値を設定することと対応するのは、「localRotationにQuaternion.Eulerで作った回転を代入する」ということになるでしょうか。 

transform.Rotateですが、実際に適当なオブジェクトに下記のようなスクリプトをアタッチして試してみてはいかがでしょう。オブジェクトはあらかじめ適当に回転して傾けておくと動きが分かりやすいかと思います。

using UnityEngine;

public class TestScript : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            transform.Rotate(0.0f, 30.0f, 0.0f);
        }
    }
}


おそらく、インスペクタ上の回転角に値を加減算するのとは異なった結果になるのではないでしょうか?transform.Rotateで回転すると、シーンビュー上でオブジェクトから突き出た3色のギズモを軸に回転するはずです。

Self

また、transform.Rotate(0.0f, 30.0f, 0.0f, Space.World);に変えてみると、今度はワールド座標の3軸周りに回転し、こちらもやはりインスペクタへの加減算とは微妙に異なるはずです(オブジェクトを別のオブジェクトの子にして、親オブジェクトもあらかじめ適当に傾けておくと違いが明確になるでしょう)。

World

[コメントを受けて追記]
localEulerAnglesを取得して値を加減算し、ふたたびlocalEulerAnglesに書き戻す手が考えられるかと思います。

using UnityEngine;

public class TestScript : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            var localEuler = transform.localEulerAngles;
            localEuler.y += 30;
            transform.localEulerAngles = localEuler;
        }
    }
}

プレビュー1

ただし、リファレンスの注意書きにあるように、このようにすると意図通りにならない場合があります。たとえば上記のlocalEuler.y += 30;localEuler.x += 30;にすると...

プレビュー2

Unity内部では回転をクォータニオンで持っており、オイラー角が必要になればそのクォータニオンからオイラー角が導出されますが、あるクォータニオンと同じ回転を表すオイラー角は一通りではないという特徴があるため、xだけを操作しているつもりなのにy、zも変化してしまい、最終的にめちゃくちゃな回転になってしまうかもしれません。

オイラー角からクォータニオンへ...の一方通行ならこの問題を回避できるかと思います。
コードをこのようにすると...

using UnityEngine;

public class TestScript : MonoBehaviour
{
    private Vector3 localEuler;

    private void Start()
    {
        this.localEuler = transform.localEulerAngles;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            this.localEuler.x += 30;
            transform.localEulerAngles = this.localEuler;
        }
    }
}

途中のインスペクタの表示ではやはりx、y、zが一斉に変化しており、回転が狂ってしまっているように見えるかもしれませんが、ちゃんと等価な回転になっており、12回の回転で元の向きに戻ります。

プレビュー3

[追記]
エディタ上だとRotationに値を入れると(たとえ±360°を超えるようなものでも)、インスペクタを表示しなおしても勝手に変な値に書き換わることなく、その値が維持されるようです。編集する上では直感的で便利な機能だと思いますが、どうやらUnityは内部的にユーザが入力した、あるいはエディタ上で回転させたオイラー角をクォータニオンを経由させず、そのままの状態で保管しているみたいですね。
How are Editor Transform.Rotation values calculated? : Unity3Dを参考に下記のようにしてみると、インスペクタ上に表示されているのと同じ値を見ることができました。

using UnityEngine;

[ExecuteInEditMode]
public class TestScript : MonoBehaviour
{
    private Vector3 localEuler;

    private void Start()
    {
        this.localEuler = transform.localEulerAngles;
        #if UNITY_EDITOR
        var serializedObject = new UnityEditor.SerializedObject(transform);
        var serializedEulerHint = serializedObject.FindProperty("m_LocalEulerAnglesHint");
        Debug.Log(serializedEulerHint.vector3Value);
        #endif
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            this.localEuler.x += 10;
            this.localEuler.y += 10;
            this.localEuler.z += 10;
            transform.localEulerAngles = this.localEuler;
        }
    }
}

インスペクタの回転表示

実際の実行時には使えないでしょうが、エディタスクリプトでインスペクタ上の角度を意図通りに加減算させたいというようなことがあれば、このあたりをいじることになりそうです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/10 12:04 編集

    ご回答ありがとうございます。
    localRotationにQuaternion.Eulerを代入すれば、インスペクタでRotationを設定するのと同じになるのですね。

    transform.Rotateの件、検証してみました。
    質問時は、キューブを傾けてなかったので気づきませんでしたが、キューブを傾けてtransform.Rotateしたら、確かにインスペクタ上の回転角に値を加減算するのとは異なることが確認できました。

    さらに質問で恐縮ですが、インスペクタ上の回転角に値を加減算する処理をコードで実現する方法はご存知でしょうか?(そもそもコードではできないものなのでしょうか?)
    this.transform.localRotation = this.transform.localRotation * Quaternion.Euler(0, 20, 0);
    を試してみましたが、これもインスペクタ上で加減算するものとは異なりました。
    上記コードは、transform.Rotate(0, 20, 0)と同じ処理ですか?

    キャンセル

  • 2017/12/10 15:13 編集

    試していないですが、コメントのthis.transform.localRotation = this.transform.localRotation * Quaternion.Euler(0, 20, 0);なら、画面上のオブジェクトの向きについては多分大丈夫だろうと思います。
    インスペクタ上の表示がおかしくなったとしたら、それはクォータニオンとオイラー角の変換に関わる問題のような気がします。このへんは仕方ないものとして妥協するべきかもしれません...

    [追記]
    すいません、this.transform.localRotation = this.transform.localRotation * Quaternion.Euler(0, 20, 0);だと回転順が逆でしたね。this.transform.localRotation = Quaternion.Euler(0, 20, 0) * this.transform.localRotation;でどうでしょう?

    [さらに追記]
    たびたびすみません!
    Y軸周り回転の増減だけならthis.transform.localRotation = Quaternion.Euler(0, 20, 0) * this.transform.localRotation;、Z軸周り回転の増減だけならthis.transform.localRotation = this.transform.localRotation * Quaternion.Euler(0, 0, 20);でいけますが、X軸周りおよびこれらの複合には対応できませんでしたね。
    結局ローカルオイラー角をとってきてどうこうしてやるのが妥当な方法なのかもしれません。

    キャンセル

  • 2017/12/10 18:18

    ご回答ありがとうございます。
    すみません、試してみた所、ローカルオイラー角をとってくる方法は、transform.Rotateと同じ処理結果になるように見えるのですが、差異が現れるのを検証するにはどうすればよいでしょうか?

    キャンセル

  • 2017/12/10 19:32

    localEulerAnglesの書き換えでだめでしたか?何が違ったんでしょうか...回転って案外やっかいですね。

    私の試した場合では、親オブジェクトのRotationはX 20、Y 30、Z 40とし、キューブのRotationはX 0、Y 10、Z 20とした状態でスタートして、まず「StartでlocalEulerAnglesを保存し、Updateで保存した角度にX+10、Y+10、Z+10したのちlocalEulerAnglesに代入」のパターンですと、36回の回転で元の向きX 0、Y 10、Z 20に戻ったのに対し、「Startでは何もせず、Updateでtransform.Rotate(10, 10, 10);」では回転中のインスペクタ上の角度は非整数になり、36回の回転後の位置もずれていました(同じ位置にキューブを複製して異なる色を着け、それぞれに異なる回転方法のスクリプトをアタッチすると比較しやすいと思います)。

    キャンセル

  • 2017/12/10 21:13 編集

    ご回答ありがとうございます。
    ご提示いただいた内容で検証できました、確かにlocalEulerAnglesをStartで保存するパターンで元に戻り、transform.Rotateでは元に戻らないことが確認できました。
    まとめると、『インスペクタ上の回転角に値を加減算する回転をコードで処理したい場合は、「StartでlocalEulerAnglesを保存し、Updateで保存した角度にX,Y,Zそれぞれのプロパティに加減算したのちlocalEulerAnglesに代入する」方法が1番近い処理となるが、その方法でも、インスペクタ上の回転角に値を加減算する処理と完全に一致するわけではない』ということでしょうか?

    キャンセル

  • 2017/12/11 05:58

    そうですね、回答に追記したように、インスペクタ上の角度は特別扱いされているようなので、完全一致は難しそうですね。ですがlocalEulerAnglesの方法なら、インスペクタの表示はともかく、向き自体はインスペクタへの加減算と同じにできるのではないかと思います(回答のスクリーンショットにあるように、「90.000...」のような浮動小数点数の精度によると思われる微妙なずれはあるようですが、これは仕方なさそうですね)。

    キャンセル

  • 2017/12/11 21:52

    ご回答ありがとうございます。
    ご丁寧な解説ありがとうございました、理解できました。
    ありがとうございます。

    ところで、transform.Rotateで回転を加えるメリットって何なのでしょうか?
    検索すると、回転を加えるのにtransform.Rotateで行っている記事をよく見かけます。
    今回のlocalEulerAnglesの方法ならば、インスペクタの回転角の加減算に近い処理ができて、一周回ったときに必ず元に戻るので扱いやすいと思うんですが、
    transform.Rotateの場合は、インスペクタの回転角の加減算のような回転でもないし、一周回ったときに元に戻らずズレが生じる場合もあるので扱いづらさしか感じないのですが。
    試してみた所、transform.Rotateでx,y,zのどれか一つのプロパティだけで一周回したら、元の位置に戻るような挙動になりました(全てのパターンでそうなるのかはわかりませんが)。
    極論ですが、x,y,zのどれか一つのプロパティだけで回転する場合のみ、transform.Rotateで回転を加えるメリットがあるのかなと思いました。
    また質問で申し訳ないですが、transform.Rotateでx,y,zのどれか一つのプロパティだけで一周回した場合は必ず元の位置に戻ると言えますか?

    キャンセル

  • 2017/12/12 07:02

    インスペクタの回転角の加減算ですと親オブジェクトの座標系を意識しなければなりませんが、transform.Rotateならば「transformの現在のx、y、z軸を基準に回転」できるので、便利な場面が多いのだろうと思います。
    たとえば飛行機の姿勢を変えることを想像しますと、transform.Rotateでx軸周り回転させれば機首を上げ下げ、y軸なら機首を左右に、z軸ならローリング(https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0)となり、直感的ではないでしょうか。

    transform.Rotateで回したときに元の位置に戻るかどうかですが、これは回転軸周りの回転量が「360/回転回数」であるかどうかによるはずです。一つのプロパティを10°や20°、30°ずつ回す場合はこの条件に当てはまるので元の位置に戻ったと考えられます。

    先に試したtransform.Rotate(10, 10, 10);は回転軸ベクトルが(0.6444025, 0.5407179, 0.5407179)、回転角が16.78646°でした。ですので、回転角10°の場合を逆算すると、transform.Rotate(6.168753f, 5.725674f, 5.725674f);ならば、もっと直感的にはRotateの軸・角度指定版を使ってtransform.Rotate(new Vector3(0.6444025f, 0.5407179f, 0.5407179f), 10);とすれば36回の回転で元の位置に戻るはずです。

    キャンセル

  • 2017/12/12 11:00 編集

    ご回答ありがとうございます。
    なるほど、transform.Rotateは親オブジェクトに関係なく軸周りで回転させたい場合に直感的な回転ができて便利なのですね。

    >先に試したtransform.Rotate(10, 10, 10);は回転軸ベクトルが(0.6444025, 0.5407179,
    >0.5407179)、回転角が16.78646°でした。
    すみません、こちらの回転軸ベクトルと回転角はどのように算出されたのでしょうか?

    キャンセル

  • 2017/12/12 12:12

    transform.Rotate(10, 10, 10);での回転はtransform.localRotation *= Quaternion.Euler(10, 10, 10);と同等のようです。そこで、

    float angle;
    Vector3 axis;
    Quaternion.Euler(10, 10, 10).ToAngleAxis(out angle, out axis);
    Debug.LogFormat("{0:F7}, {1:F7}, {2:F7}, {3:F7}", angle, axis.x, axis.y, axis.z);

    で調べられるかと思います。
    もし手計算するとしたら、クォータニオンの定義をもとに逆計算することになるでしょうか。
    https://qiita.com/kenjihiranabe/items/945232fbde58fab45681#quaternion などがご参考になりそうです。

    キャンセル

  • 2017/12/13 01:53 編集

    ご回答ありがとうございます。
    transform.Rotateから、回転軸ベクトルと回転角を取得する方法がわかりました。

    すみません、理解力がなくて今頃気づいたのですが、
    インスペクタの回転角は、自身のオブジェクトの座標軸を基準とした回転角ではなく、
    親オブジェクトの座標軸を基準とした回転角なのですね。
    (ただし、親オブジェクトがないルートオブジェクトの場合は、ワールドの座標軸を基準とした回転角)
    なのでオブジェクトを傾けて、親オブジェクトの座標軸もしくはワールドの座標軸からずらした状態で
    Rotateで自身のオブジェクトの座標軸を基準に回転させると、
    インスペクタの回転角の加減算の回転ではなくなるのですね。
    なので、Rotateの引数の角度の値が、インスペクタの回転角の加減算の値と一致しなくなるということなのですね。
    この認識で合っていますか?

    キャンセル

  • 2017/12/13 05:13 編集

    ええ、そういうことになるでしょう。

    補足として、昨日コメントを拝見したときにlocalRotationからオイラー角がとれるか...?といった疑問をお持ちのご様子でした。ご解決済みかもしれませんが、実際のところlocalEulerAnglesが返しているのはlocalRotation.eulerAnglesのようですね。

    eulerAnglesが内部でやっているオイラー角を求める部分は、マネージドコードではないようで正確なところは分かりませんでしたが、「クォータニオンからオイラー角を求めてみる - Qiita」(https://qiita.com/edo_m18/items/5db35b60112e281f840e)で紹介されている方法とほとんど同じではないかと思います。
    記事の中に「これで無事、各値が求まった・・と思いきや、特殊なケースが存在します...」「そこで、適当にθy = 0と置くと...」というくだりがありますが、どうもUnityはθyの代わりにθzを0にしているらしい...?こと、cos(θx)が0だと判定するしきい値は±0.00000208くらいらしい...?ことや、求めたオイラー角を0°〜360°におさめる処理(どういう理由か、0.0001ラジアンだけマイナス側に振れるようになっているようですが)を加えているらしい...?といった多少の違いがあるようで、UnityのeulerAnglesと完全一致はしないかもしれませんが、向き自体は同等なはずですので、問題にはならないかと思います。

    キャンセル

  • 2017/12/13 22:41 編集

    ご回答ありがとうございます。
    ご確認ありがとうございます、理解できました。

    いえ、まだ解決してなかったのでご回答いただきありがとうございます。
    下記で検証して理解できました。
    //下記2行は同じ意味のコード。
    Debug.Log (transform.localEulerAngles); //インスペクタの回転角のVector3。
    Debug.Log (transform.localRotation.eulerAngles); //インスペクタの回転角のVector3。

    また、localRotation.eulerAnglesにはVector3でオイラー角を代入することはできないみたいですね。
    transform.localEulerAngles = new Vector3 (10, 20, 30); //設定できる。
    transform.localRotation.eulerAngles = new Vector3 (10, 20, 30); //エラー。
    //localRotation.eulerAnglesプロパティは読み取り専用なので(?)、
    //localRotationでオイラー角を設定する場合は、下記の方法しかない(?)。
    this.transform.localRotation = Quaternion.Euler(10, 20, 30); //設定できる。

    また、Calc()メソッドを検証してオイラー角がとれてくるのを確認しました。
    正直、理論的なことは全然わかりませんが、内部でやっていることのイメージがわかってよかったです。

    また、今までの内容を見返してるうちに気づいたのですが(常識的なことなのかもしれませんが)、
    オイラー角に回転を加える場合は足し算で、クォータニオンに回転を加える場合は掛け算なのですね。

    キャンセル

  • 2017/12/13 23:01

    そうですね。さらにQuaternionとVector3の掛け算なんてものも用意されていて、Vector3をQuaternionで回転させることもでき便利です。
    本当は単なる掛け算というよりも、*記号で回転操作を簡潔に書けるようにしている、と考えた方がいいかもしれません。
    お時間のある時にでも、先に挙げたhttps://qiita.com/kenjihiranabe/items/945232fbde58fab45681をご覧いただけますと、実際には3次元座標をクォータニオンに直したり、逆クォータニオンを逆方向から掛けたり...と、何やらややこしいことをしている様子がお分かりいただけるかと思います。

    キャンセル

  • 2017/12/14 01:35

    なるほど、QuaternionとVector3の掛け算、検索して記事を見つけました。
    http://tsubakit1.hateblo.jp/entry/2014/08/02/030919
    なるほど、ベクトルの掛け算(*)は、掛ける順序によって回転が変わるのですね。
    たくさんの質問にご回答いただきありがとうございました。
    ご提示いただいたURLも勉強していこうと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.14%

関連した質問

  • 解決済

    [Unity] MoveTowardsAngle関数の回転

    MoveTowardsAngle関数で、x軸の回転(左の球)だけ90度地点で止まります。 右の球のような動きで、x軸に360度の回転をさせたいです。どうしたらいいですか?

  • 解決済

    Unity ヒンジ 角度 C#

    Unityの2Dヒンジ、または3Dヒンジで2つのオブジェクト間の角度をC#で取得、値を代入するにはどうすればよろしいのでしょうか?

  • 受付中

    親オブジェクトが回転しても、子オブジェクトは回転させないようにしたい。

    Unityにて、FPSゲームを制作しているのですが 子オブジェクトの回転軸を固定させる方法はありませんか? https://gyazo.com/fbce44db53edecc4

  • 受付中

    カメラの操作用スクリプトについて

    unityでカメラをyを軸に回転させ、向いた方向を前として、wで前進、sで後進、aで左、dで右に動かすスクリプトを書きたいのですが、軸で回ることはできても、どうしてもワールドのx,

  • 解決済

    3Dゲームでバイオハザードと同じ様な操作を(自機に)したい。

    ・カメラの位置は自機の頭部の少し後ろ上に固定。 ・カメラのポジションはxとy軸のみ変更可能。 ・W,S,A,Dのそれぞれのキーで前進、後退、左移動、右移動。 上記の三点を行いた

  • 解決済

    カメラ視点をリセットするには?

    カメラの視点をリセットするにはどうすればいいのか教えていただきたいです。 キャラの向きとは別にカメラワークによる上下左右の確認をした後にそのカメラ視点を初期状態ローテーションを(0

  • 解決済

    Unityで回転制限をつけたいです。

    前提・実現したいこと 下記コードでAキー、Dキーを押している間それぞれY軸の-方向、Y軸の+方向に回転するよう書きましたが、90度回転したら回転できないようにする機能をつけたいです

  • 解決済

    Unity オブジェクトの座標を出力する方法

    今、Unityの勉強をしています。 現在のオブジェクトを回転させるプログラムを作成し、回転しているオブジェクトのRotationをエクセルに出力させています。 下記のコードでは、z

同じタグがついた質問を見る

  • Unity

    2601questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。