↪️

【Unity】ジンバルロックの理解と回避方法

2024/12/16に公開

この記事では、ジンバルロックの仕組みや影響について解説しています。


ジンバルロックとは?

ジンバルロックは、オイラー角で回転を管理する際に、座標系の2つの回転軸が同一平面上に重なり、回転の自由度が1つ失われる現象です。これは、オイラー角の回転順序が原因で発生します。

  1. Unityでは、X → Y → Zの順番で回転します
  2. X軸を90°回転させた場合、Y軸とZ軸が同一平面に配置されます。
  3. この結果、Y軸とZ軸回転が同じ方向に作用し、意図した回転ができなくなります。

ジンバルロックの仕組み

  1. オイラー角の回転順序

    Unityでは、オイラー角を使った回転では「X → Y → Z」の順で回転が適用されます。累積した回転の影響で、各軸の方向が変わり、ジンバルロックとして現れます。

  2. X軸を90°回転するとどうなるか?

    • Y軸がZ軸に一致。
    • Z軸がY軸に一致。
    • この結果、Y軸とZ軸が同一平面上に重なり、互いに区別がつかなくなるため、回転の自由度が1つ失われます。これがジンバルロックの状態です。



サンプルコード:ジンバルロックの検証

以下のコードを使用すると、ジンバルロックの問題を視覚的に確認できます。


public class GimbalLockTester : MonoBehaviour
{

    [SerializeField] private Transform _target;
    [SerializeField] private float _rotationSpeed = 50f;

    private Vector3 _currentEulerAngles;

    private void Start()
    {
        if (_target != null)
        {
            _currentEulerAngles = _target.eulerAngles;
        }
    }

    private void Update()
    {
        if (_target == null) return;

        //初期化
        if (Input.GetKey(KeyCode.Space))
        {
            _currentEulerAngles = new Vector3(0, 0, 0);
        }

        // X軸回転(上下)
        if (Input.GetKey(KeyCode.UpArrow))
        {
            _currentEulerAngles.x += _rotationSpeed * Time.deltaTime;
        }
        if (Input.GetKey(KeyCode.DownArrow))
        {
            _currentEulerAngles.x -= _rotationSpeed * Time.deltaTime;
        }

        // Y軸回転(左右)
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            _currentEulerAngles.y += _rotationSpeed * Time.deltaTime;
        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            _currentEulerAngles.y -= _rotationSpeed * Time.deltaTime;
        }

        // Z軸回転(前後)
        if (Input.GetKey(KeyCode.Z))
        {
            _currentEulerAngles.z += _rotationSpeed * Time.deltaTime;
        }
        if (Input.GetKey(KeyCode.X))
        {
            _currentEulerAngles.z -= _rotationSpeed * Time.deltaTime;
        }

        // 回転を適用
        _target.eulerAngles = _currentEulerAngles;

        // デバッグ情報
        Debug.Log($"Euler Angles: {_currentEulerAngles}");
    }

}

動作手順

  1. 上記スクリプトをアタッチし、_targetにそのオブジェクトを設定。
  2. 以下のキーを押して回転操作を試します:
    • 矢印キー上/下: X軸回転
    • 矢印キー左/右: Y軸回転
    • Z/X: Z軸回転

結果

  1. X軸を90°回転後、Y軸を回転しようとすると、ローカルZ軸が一緒に回転し、操作が意図しない方向に影響を及ぼします。
  2. これがジンバルロックの現象です。

まとめ

ジンバルロックは、オイラー角の特性によって発生する問題で、3D回転の管理が意図通りに動作しなくなる現象です。Quaternionを使用することで、この問題を回避し、スムーズな回転処理を実現できます。

  • ジンバルロックの発生状況: ローカルY軸とZ軸が同一平面上に重なると発生。
  • 回避策: Quaternionを使い、累積的な回転計算を行う。

参考サイト

Discussion