U
15 / 22 · 11 分
FAQ

回転:オイラー角、Quaternion、触っていいのはどちらか

短い答え

オブジェクトを回転させるとは? Quaternion とは?

欲しい角度が決まっていれば Quaternion.Euler(x, y, z)、何かを向かせたいなら Quaternion.LookRotation に RotateTowards や Slerp を合わせます。transform.rotation に直接足し算は禁止——角度ではない 4 つの数だからです。

位置もスケールも、そこに足し算できる三つの数字です。回転は Inspector で三つの数字に見えるものの、実際はそうではありません。誰もが同じ道で気づきます:transform.rotation を変数にコピーし、y に 1 を足して書き戻すと、物体が言葉にできない挙動を見せるのです(C# は transform.rotation.y += 1 を一行で許してくれません——この property はコピーを返すだけです)。

Inspector に見えているのは、実際に格納されているものではない

Unity は回転を Quaternion として保存します。x、y、z、w の四つの数字が組み合わさって、一つの軸とその周りの回転量を表すものです。四つのいずれも度数法の角度ではありません。Inspector は表示のためにこれを身近な三つの Euler 角へ変換し、入力した値はその逆に読み直しています。

角度が決まっている回転を設定する

Quaternion.Euler — degrees in, Quaternion out
// Face 90° to the right, level, no roll.
transform.rotation = Quaternion.Euler(0f, 90f, 0f);

// Local rotation instead: relative to the parent, not to the world.
transform.localRotation = Quaternion.Euler(0f, 90f, 0f);

// Add 90° to whatever it is now. Quaternions multiply, they do not add.
transform.rotation *= Quaternion.Euler(0f, 90f, 0f);

何かの方を向いて回転する

実際に出番が多いのはこのケースです:敵はプレイヤーの方を向く、タレットは目標を追う、キャラは歩いている向きに体を変える。手順は二つだけ——欲しい回転を計算し、そこから毎フレーム少しずつ近づけることです。

FaceTarget.cs
using UnityEngine;

public class FaceTarget : MonoBehaviour
{
    public Transform target;
    public float turnSpeed = 360f;   // degrees per second

    void Update()
    {
        if (target == null) return;

        Vector3 to = target.position - transform.position;

        // Flatten it, or the enemy tips forward to look down at a short player.
        to.y = 0f;

        // LookRotation complains about a zero vector: standing exactly on the target.
        if (to.sqrMagnitude < 0.0001f) return;

        Quaternion wanted = Quaternion.LookRotation(to);
        transform.rotation = Quaternion.RotateTowards(
            transform.rotation, wanted, turnSpeed * Time.deltaTime);
    }
}

RotateTowards か Slerp か

  • RotateTowards は毎秒何度かで一定に回り、ちゃんと到達します。回る速さそのものが設計の一部である場合——すぐには振り向けないタレットなど——にはこちらを。

  • Slerp は近づくほど減速し、最後まで届かず、速さも残りの角度に左右されます。カメラなど、機械的ではなく柔らかく感じさせたいものに合っています。

  • Slerp を Slerp(a, b, speed * Time.deltaTime) と書くとフレームレートに依存します。修正法は位置の場合と同じで、1f - Mathf.Exp(-speed * Time.deltaTime) です。

何かを回し続ける

transform.Rotate — the one case where you do not touch rotation directly
// Around its own up axis: a coin spinning on the spot.
transform.Rotate(Vector3.up * 90f * Time.deltaTime, Space.Self);

// Around the world's up axis: orbiting behaviour, unaffected by tilt.
transform.Rotate(Vector3.up * 90f * Time.deltaTime, Space.World);

Gimbal lock と、自分の角度を持つべき理由

Euler 角は回転を、順に適用される三つの回りで表します。真ん中の回りが 90° に達すると、一番目と三番目が同じ軸の周りを回ることになり、自由度が一つ消えます。これが gimbal lock です。実際、一人称視点のカメラが真上を向いた瞬間に暴れる原因は、だいたいこれです。

The pattern that avoids all of it: keep the angle yourself
using UnityEngine;

public class MouseLook : MonoBehaviour
{
    public float sensitivity = 2f;

    // Your own numbers, in degrees, never read back from the transform.
    float yaw, pitch;

    void Update()
    {
        yaw   += Input.GetAxis("Mouse X") * sensitivity;
        pitch -= Input.GetAxis("Mouse Y") * sensitivity;

        // Clamping works because pitch is a plain float you control.
        pitch = Mathf.Clamp(pitch, -80f, 80f);

        transform.rotation = Quaternion.Euler(pitch, yaw, 0f);
    }
}

これを作るレッスン

三人称の旋回カメラ

この記事はそれだけで完結するレシピです。コースでは同じものを、5 つのタブを貫くひとつのプロジェクトの一部として作ります — カメラと入力 のレッスン 02。