【Unity】Unity開発者がつまずくQuaternionを徹底解説!回転の基礎と実践的な使い方

作成: 2025-12-10最終更新: 2026-07-13

Quaternionの基本概念とオイラー角との違いを解説。ジンバルロックの仕組み、eulerAngles直接操作の落とし穴、LookRotationやSlerpを使った実践的な回転制御まで、コード例付きで学べます。

Inspectorの回転欄はX・Y・Zの3つの数字なのに、スクリプトで transform.rotation を触ると突然 x, y, z, w の4つの値が現れる——Unityの回転まわりで最初につまずくポイントです。「回転なんてX, Y, Z軸の角度で十分では?」と思いきや、その直感的な表現には ジンバルロック という落とし穴が待っています。

この記事では、Unityの回転を支える Quaternion(クォータニオン) の役割とオイラー角との使い分け、初心者がやりがちな eulerAngles 直接操作の危険性、そして LookRotationSlerp を使った実践的な回転制御までを解説します。

Quaternionのイメージ。回転するキューブと、それを取り囲む回転軸のリング

この記事でわかること

  • 振り向き・追従カメラ・誘導弾——ゲーム開発でQuaternionが必要になる場面
  • Quaternionが「軸と回転量」で回転を表す仕組み(中身の数学は不要)
  • オイラー角との使い分けと、ジンバルロックが起きる理由
  • eulerAngles を毎フレーム読み書きすると回転が暴れる理由
  • Quaternion.LookRotationSlerp による実践的な回転制御

Sponsored

ゲーム開発のどこで必要になる?

先に結論から言うと、Quaternionは数学の教養ではなく、「回転を動かす」処理すべての土台です。たとえば、どれも定番のこんな場面で使います。

  • 敵がプレイヤーの方へじわっと振り向く: 向くべき方向をLookRotationで作り、Slerpで滑らかに回す
  • 追従カメラがキャラクターの背後に回り込む: カメラの向きを毎フレーム補間する
  • 誘導ミサイルが弧を描いて曲がる: 急には曲がれない誘導をRotateTowards(毎秒◯度まで)で作る
Quaternionの使いどころの実�例図。敵の振り向き、追従カメラの回り込み、誘導ミサイルの旋回という3つの定番場面

逆に言えば、Inspectorに数値を打ち込むだけ(回転を「置く」だけ)ならオイラー角の知識で足ります。回転を毎フレーム動かし始めた途端に、「カメラが突然裏返る」「振り向きがガクガクする」といった悩みが出てきて、Quaternionの理解が必要になります。

Quaternionとは何か?

Quaternionとは、回転を表現するための数学的な概念で、4つの要素(x, y, z, w)を持ちます。UnityではTransformコンポーネントのrotationプロパティがこの型で、Unityの回転はすべて内部的にQuaternionで管理されています

オイラー角が「X軸に◯度、Y軸に◯度、Z軸に◯度」と3つの軸回転の組み合わせで表現するのに対し、Quaternionは「ある1つの軸の周りに、どれだけ回転した状態か」を表現します。1回の回転として表すため軸同士が干渉せず、ジンバルロックが原理的に発生しません。

オイラー角とQuaternionの表現の違いの図。オイラー角はX・Y・Zの3つの軸回転を順番に組み合わせ、Quaternionは1つの回転軸とその周りの回転量で同じ姿勢を表す

4つの値の意味を理解する必要はありません。実際の開発では「Quaternionの中身は直接触らず、専用のメソッドで作って渡す」だけで十分です。

専門用語の補足

  • オイラー角 (Euler Angles): X軸(ピッチ)、Y軸(ヨー)、Z軸(ロール)それぞれの回転角度で表現する方法。Inspectorの回転欄はこれです。
  • ジンバルロック (Gimbal Lock): オイラー角で特定の回転(UnityではX軸が±90度)に達したとき、残り2つの軸の回転が同じ方向に重なってしまい、1つの回転の自由度を失う現象です。
ジンバルロックの図。3つの回転リングのうちX軸が90度になると2つのリングが重なり、同じ方向の回転しかできなくなる

補足: ゲームでの典型例はFPSカメラです。オイラー角だけでカメラを制御すると、プレイヤーが真上(X=90度)を見た瞬間に「左右を向く操作」と「首をかしげる操作」が同じ回転になってしまい、視点が急にくるっと裏返るバグにつながります。UnityのTransformが内部でQuaternionを使っているのは、まさにこれを防ぐためです。

Sponsored

オイラー角とQuaternionの使い分け

Unityではtransform.eulerAnglesというプロパティを通じてオイラー角にアクセスできますが、これは内部のQuaternionからその都度逆算された値です。

特徴オイラー角 (transform.eulerAngles)Quaternion (transform.rotation)
表現3つの角度 (X, Y, Z)4つの要素 (x, y, z, w)
直感性高い(人間が理解しやすい)低い(中身は直接触らない)
問題点ジンバルロック/同じ回転に複数の表現がある数値の意味が直感的でない
用途Inspectorでの設定、角度の指定スクリプト内での計算、回転の補間

初心者が躓きやすいポイント:eulerAnglesの毎フレーム読み書き

eulerAnglesへの「代入」自体は問題なく動きます。危険なのは、毎フレーム読み取って加算するような使い方です。

// 危険なコード例: eulerAnglesを毎フレーム読み取って加算
void Update()
{
    Vector3 angles = transform.eulerAngles; // 内部のQuaternionから逆算された値
    angles.x += 30f * Time.deltaTime;
    transform.eulerAngles = angles;
}

同じ回転でもオイラー角の表現は一通りではありません(例:X=170, Y=0, Z=0X=10, Y=180, Z=180 は同じ姿勢)。逆算でどちらが返るかは保証されないため、読み取った値に加算し続けると、ある角度を境に回転が突然飛んだり震えたりします。

解決策: 角度で指定したいときは、加算元の角度を自分の変数で管理するか、Quaternion.Euler()で作った回転を掛け合わせます。

// 正しいコード例1: 角度を自分の変数で管理する
private float pitch = 0f;

void Update()
{
    pitch += 30f * Time.deltaTime;
    transform.rotation = Quaternion.Euler(pitch, 0f, 0f);
}
// 正しいコード例2: 回転の「差分」を掛け合わせる
void Update()
{
    // 現在の回転に「X軸に少し回す」回転を合成する
    transform.rotation *= Quaternion.Euler(30f * Time.deltaTime, 0f, 0f);
}

補足: Quaternion同士の * は「回転の合成」です。A * B は「Aの回転をしてから、さらにBの回転を加える」という意味になります(順番によって結果が変わる点に注意)。

Sponsored

実践的なQuaternionの使い方とコード例

Quaternionの真価は、特定の回転状態を生成したり、回転と回転の間を滑らかに補間したりする際に発揮されます。

1. 特定の方向を見る回転を生成する (Quaternion.LookRotation)

キャラクターを特定のターゲットの方向へ向かせたい場合、Quaternion.LookRotationが非常に便利です。

using UnityEngine;

public class LookAtTarget : MonoBehaviour
{
    public Transform target; // ターゲットのTransform

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

        // 1. ターゲットへの方向ベクトルを計算
        Vector3 direction = target.position - transform.position;

        // 2. その方向へ向くためのQuaternionを生成
        // 第二引数に上方向(Vector3.up)を指定することで、頭が傾かないようにします
        Quaternion targetRotation = Quaternion.LookRotation(direction, Vector3.up);

        // 3. 生成したQuaternionを現在の回転に適用
        transform.rotation = targetRotation;
    }
}

2. 滑らかな回転補間 (Quaternion.Slerp)

上のコードでは一瞬でターゲットの方を向いてしまいます。「じわっと振り向く」動きにするには、Quaternion.Slerp(球面線形補間)で現在の回転と目標の回転の間を補間します。

using UnityEngine;

public class SmoothRotation : MonoBehaviour
{
    public Transform target;
    public float rotationSpeed = 5.0f; // 振り向きの速さ

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

        // 1. ターゲットへ向くための目標Quaternionを計算
        Vector3 direction = target.position - transform.position;
        Quaternion targetRotation = Quaternion.LookRotation(direction);

        // 2. 現在の回転と目標の回転の間をSlerpで補間
        // 毎フレーム目標へ一定割合ずつ近づくため、最後はゆっくりの自然な振り向きになる
        transform.rotation = Quaternion.Slerp(
            transform.rotation, // 現在の回転
            targetRotation,     // 目標の回転
            Time.deltaTime * rotationSpeed // 補間率
        );
    }
}
LookRotationとSlerpによる振り向きの実例図。敵キャラクターがプレイヤーの方向をLookRotationで割り出し、Slerpで弧を描いて滑らかに向き直る

LerpとSlerpの違い

Vector3.Lerp(線形補間)を回転に使うと、途中の角速度が不均一になり不自然になることがあります。Quaternion.Slerpは球面上の弧に沿って補間するため、回転として常に自然です。回転の補間にはSlerpを使いましょう。補間関数の使い分けは LerpとSlerpの記事 で詳しく解説しています。

実践:砲塔が水平にだけ敵を追い、砲身だけ上下を向く

仕上げに、ここまでの道具を全部使う定番ギミックを完成させます。タワーディフェンスの砲台、TPSの固定機銃、宇宙STGの自動タレット——どれも共通する要件は「 台座は水平にだけ旋回し、砲身だけが上下を向く 」ことです。LookRotationに方向を丸ごと渡すだけでは、敵が高台に登った瞬間に台座ごと仰け反ってしまいます。

Hierarchyの組み方(回転を役割ごとの階層に分けるのがコツです):

Turret(このスクリプトを付ける)
└─ BasePivot(台座。Y軸だけ回る)
   └─ BarrelPivot(砲身の付け根。ローカルX軸だけ回る)
      └─ 砲身メッシュ(Z+が砲口の向き)
// ファイル名: TurretController.cs
using UnityEngine;

public class TurretController : MonoBehaviour
{
    public Transform target;        // 追う相手(プレイヤーなど)
    public Transform basePivot;     // 台座(Y軸だけ回る)
    public Transform barrelPivot;   // 砲身(ローカルX軸だけ回る)
    public float turnSpeed = 90f;   // 旋回速度(度/秒)

    void Update()
    {
        if (target == null) return; // 対象消失時は静かに待機(毎フレーム警告を出さない)

        Vector3 toTarget = target.position - basePivot.position;

        // --- 台座: 高さ成分を捨てた「水平方向」だけを追う ---
        Vector3 flatDirection = new Vector3(toTarget.x, 0f, toTarget.z);

        // 敵が真上や同位置に来ると方向が作れない。長さ0をLookRotationに渡さない
        if (flatDirection.sqrMagnitude > 0.0001f)
        {
            Quaternion baseGoal = Quaternion.LookRotation(flatDirection);
            basePivot.rotation = Quaternion.RotateTowards(
                basePivot.rotation, baseGoal, turnSpeed * Time.deltaTime);

            // --- 砲身: 上下(ピッチ)だけを向く ---
            // 水平距離と高低差から仰角を計算する。上を向くほどローカルXはマイナス
            float pitch = -Mathf.Atan2(toTarget.y, flatDirection.magnitude) * Mathf.Rad2Deg;
            Quaternion barrelGoal = Quaternion.Euler(pitch, 0f, 0f);
            barrelPivot.localRotation = Quaternion.RotateTowards(
                barrelPivot.localRotation, barrelGoal, turnSpeed * Time.deltaTime);
        }
    }
}

ポイントは2つ。 台座に渡す方向からは高さ成分を捨てるyを0にする)ことと、 砲身は台座の子としてlocalRotationのX軸だけを動かす ことです。台座が回れば砲身も一緒に水平旋回するので、砲身は「上下」という自分の仕事だけに集中できます。回転速度をRotateTowards(毎秒◯度)で制限しているため、敵が背後に回り込んでも砲塔は「間に合わずに撃ち遅れる」というゲーム的に美味しい隙が生まれます。

砲塔の回転分離の図。台座はY軸の水平旋回だけを担当し、砲身はローカルX軸の上下だけを担当する。高台の敵には砲身だけが仰角を取る

わざと壊して、直す

この砲塔は、Quaternionの定番事故を全部体験できる教材でもあります。

  1. 高さまで台座に渡す: flatDirectionの代わりにtoTargetをそのまま台座のLookRotationへ渡すと、敵が高台に登った瞬間、台座ごと仰け反って砲塔全体が傾きます。「水平は台座・上下は砲身」の分業が崩れる失敗です
  2. 長さ0の方向を渡す: if (flatDirection.sqrMagnitude > 0.0001f)のガードを外して敵を砲塔の真上に移動させると、Consoleに「Look rotation viewing vector is zero」の警告が毎フレーム洪水のように出ます
  3. オイラー角を直接補間して遠回りする: 台座の旋回をMathf.Lerp(currentY, goalY, t)のような角度の補間で書くと、350度→10度のとき本来20度で済む旋回を330度分逆回りします。QuaternionのRotateTowards/Slerp常に最短経路 を通るので、この問題自体が消えます
  4. ローカルとワールドを混ぜる: 砲身の上下をbarrelPivot.localRotationではなくbarrelPivot.rotation(ワールド)に代入すると、台座が回った瞬間に砲身があらぬ方向を向きます。 親子構造の中の回転はlocalRotation ——「親から見てどれだけ回っているか」で管理するのが原則です

仕上げに、敵を砲塔のまわりでぐるぐる走らせて眺めてみてください。台座は水平に旋回するだけ、敵が高台に登れば砲身だけがすっと持ち上がる——この2つの動きが見えれば分業は成功です。敵を真上に置いてもConsoleが静かなら、ガードもきちんと仕事をしています。

Sponsored

おまけ:先に知っておくと良いこと

Quaternionの基本を押さえたら、次はこのあたりが役立ちます。

  • 補間の使い分けを深める: 「なぜ目標に近づくと減速するのか」「等速で回すには RotateTowards」といった補間の実践は LerpとSlerpの記事 で詳しく扱っています。
  • 物理オブジェクトの回転は Rigidbody 経由で: Rigidbodyが付いたオブジェクトを transform.rotation で回すと物理演算と衝突します。rb.MoveRotation(targetRotation) を使うのが正解です。Rigidbodyの記事 が参考になります。
  • 手軽に回すだけなら transform.Rotate(): 毎フレーム一定量回すだけの用途なら、transform.Rotate(0f, 30f * Time.deltaTime, 0f) という簡易APIもあります。内部でQuaternionの合成をやってくれています。

まとめ

本記事では、Unity開発における回転制御の要であるQuaternionについて解説しました。

  • Quaternionは「1つの軸とその周りの回転量」で回転を表し、ジンバルロックを回避できます。Unityの回転の内部表現はすべてQuaternionです。
  • オイラー角はInspectorや角度指定に便利ですが、毎フレームの読み取り+加算は回転が暴れる原因になります。角度は自分の変数で管理しましょう。
  • 角度から回転を作るときは Quaternion.Euler()、方向から作るときは Quaternion.LookRotation() を使います。
  • 滑らかに振り向かせたいときは Quaternion.Slerp()、等速で回したいときは Quaternion.RotateTowards() です。
  • Quaternion同士の * は回転の合成です。中身の4つの値を直接触る必要はありません。

「作るのはEuler/LookRotation、補間はSlerp、合成は*」——この3点セットを覚えれば、Quaternionはもう怖くありません。