LoginSignup
7
5

More than 1 year has passed since last update.

[Unity]Quaternionの回転、左が先か?右が先か?

Last updated at Posted at 2021-10-20
// X軸で90度回転
var rot1 = Quaternion.AngleAxis(90, new Vector3(1, 0, 0));
// Y軸で90度回転
var rot2 = Quaternion.AngleAxis(90, new Vector3(0, 1, 0));

// Quaternionの回転、左が先か?右が先か?
var rot = rot1 * rot2;

左が先説

Quaternionの掛け算についてUnity公式には以下の記述があります。

lhs と rhs の回転を組合わせます。

lhs * rhs の積の値で回転させることは、lhs を最初に、それから rhs というように 2 つの回転を順番に行うことと同じです。つまり、回転は、非可換性で、lhs * rhs は rhs * lhs と異なる回転を表すということに気を付けてください。
https://docs.unity3d.com/ja/2019.4/ScriptReference/Quaternion-operator_multiply.html より

// https://docs.unity3d.com/ja/2019.4/ScriptReference/Quaternion-operator_multiply.html より

using UnityEngine;
using System.Collections;

public class Example2 : MonoBehaviour
{
    float rotateSpeed = 90;

    // Applies a rotation of 90 degrees per second around the Y axis
    void Update()
    {
        float angle = rotateSpeed * Time.deltaTime;
        transform.rotation *= Quaternion.AngleAxis(angle, Vector3.up);
    }
}

ここには計算順は 左が先、右が後 ということ、回転は非可換で逆にはできないということが記載されています。
しかし計算順は本当に 左が先、右が後 なのでしょうか。

右が先説

以下のようにX軸で90度回転してからY軸で90度回転させるにはどうしたらいいでしょうか。

x-y.gif

これを実現するためのコードを書くとこのようになります。
(アニメーションはしません)

// X軸で90度回転
var rot1 = Quaternion.AngleAxis(90, new Vector3(1, 0, 0));
// Y軸で90度回転
var rot2 = Quaternion.AngleAxis(90, new Vector3(0, 1, 0));

// X軸で90度回転してからY軸で90度回転
transform.localRotation = rot2 * rot1;

これを見ると右(X軸で90度回転)が先で左(Y軸で90度回転)が後のようです。

どちらが正しいか

どちらも正しい と言えます。
左が先説と右が先説では考え方が違います。

左が先説の場合は回転で 回転軸も同時に回転する と考えます。
前述の例で説明します。

// X軸で90度回転
var rot1 = Quaternion.AngleAxis(90, new Vector3(1, 0, 0));
// Y軸で90度回転
var rot2 = Quaternion.AngleAxis(90, new Vector3(0, 1, 0));

transform.localRotation = rot2 * rot1;

左から回転すると考える場合、まずオブジェクトをY軸で90度回転します。
この時、回転軸も回転するのでX軸が-Z軸になります。
そしてこの回転後のX軸を基準に90度回転します。

y-x.gif

右から左の場合は 回転軸は変わらず常に固定 と考えます。

どちらから回転を掛ければいいのか

オブジェクトを回転させたい場合、どちらから回転を掛ければいいでしょうか。
答えは 何を実現したいか によって変わります。
既に回転されたオブジェクトを 元々の回転軸で回転させたい 場合はオブジェクトの回転を左、掛けたい回転を右にしましょう。

void Start()
{
    // Z軸で30度回転しておく
    transform.localRotation = Quaternion.AngleAxis(30, new Vector3(0, 0, 1));
}

void Update()
{
    var rotateSpeed = 90;
    var angle = rotateSpeed * Time.deltaTime;
    // 元々のY軸で回転
    var rot = Quaternion.AngleAxis(angle, Vector3.up);
    transform.localRotation = transform.localRotation * rot;
}

right.gif

既に回転されたオブジェクトを 固定の回転軸で回転させたい 場合は掛けたい回転を左、オブジェクトの回転を右にしましょう。

void Start()
{
    // Z軸で30度回転しておく
    transform.localRotation = Quaternion.AngleAxis(30, new Vector3(0, 0, 1));
}

void Update()
{
    var rotateSpeed = 90;
    var angle = rotateSpeed * Time.deltaTime;
    // 固定のY軸で90度回転
    var rot = Quaternion.AngleAxis(angle, Vector3.up);
    transform.localRotation = rot * transform.localRotation;
}

left.gif

まとめ

どちらが先か、という問題については考え方次第で どちらにも解釈できる ということが分かりました。
ただしQuaternionによる回転が 任意の軸の周りでの回転 を表現していることを考えると右から左の方が自然に見えます。

var pos = new Vector3(0, 0, 1);
var xRot = Quaternion.AngleAxis(90, new Vector3(1, 0, 0));
var yRot = Quaternion.AngleAxis(90, new Vector3(0, 1, 0));

// X軸で90度回転する
var pos2 = xRot * pos;
// Y軸で90度回転する
var pos3 = yRot * pos2;

// X軸で90度回転させてからY軸で90度回転する
// 右から左の順
var pos4 = yRot * xRot * pos;

// pos3とpos4は等しい

参考

Quaternionによる3次元の回転変換
クォータニオン (Quaternion) を総整理! ~ 三次元物体の回転と姿勢を鮮やかに扱う ~
Quaternion を完全に理解した | VirtualCast Blog

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5