* 정의

먼저 짐벌(Gimbal)이란 물체가 축을 기준으로 회전할 수 있도록 허용해주는 피벗 지지대이다.
3차원 공간의 한 물체가 자유도를 잃고 2차원 안에서만 회전할 수 있을 때 이를 짐벌락(Gimbal lock)이라고 부른다.
// 여기서 자유도란 독립적으로 달라질 수 있는 시스템의 매개 변수이다.
짐벌락은 오일러 각에서 두 축이 평행해지면 발생한다. 2차원 안에서만 회전할 수 있다고 표현한 이유는 두 축이 평행해져서 원래 존재하던 한 축에 대한 회전을 사용하지 못하기 때문이다.
* 발생 원리
3D 좌표에서 3개의 축을 기준으로 회전하는 방식을 사용하면 회전간 종속성이 생기게 된다.
예를 들어 Unity의 오일러 각을 사용했을 때 회전 순서는 Z <- X <- Y 로 적용된다. Y축으로 회전할 때 X, Z축에 영향을 주고, X축으로 회전할 때 Z축에 영향을 준다는 뜻이다.


여기서 중간에 있는 X축으로 회전할 때 Z축에만 영향을 주게 되어 그림과 같이 Z축이 Y축과 겹쳐질 수 있다.
간단히 확인하기 위해 Unity에서 X축으로 90도 회전한 뒤 Z축과 Y축으로 각각 회전시켜본다.
먼저 간단하게 사람형(?) 객체를 만들었다.

코드는 다음과 같이 간단히 구현하였다. 플래그로 한쪽은 Y축으로 회전, 한쪽은 Z축으로 회전하도록 설정하였다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotationTest : MonoBehaviour
{
private float rotationSpeed = 10;
private Vector3 targetEulerAngles;
public bool reverse = false;
public bool rotationByYAxis = false;
void Start()
{
targetEulerAngles = new Vector3(90, 0, 0);
transform.rotation = Quaternion.Euler(targetEulerAngles);
}
void Update()
{
float deltaTime = Time.deltaTime;
if(true == reverse)
{
deltaTime = -deltaTime;
}
if(true == rotationByYAxis)
{
targetEulerAngles.y += deltaTime * rotationSpeed;
}
else
{
targetEulerAngles.z += deltaTime * rotationSpeed;
}
transform.rotation = Quaternion.Euler(targetEulerAngles);
}
}
결과를 보면 하나는 시계방향 하나는 반시계 방향으로 도는 것을 확인할 수 있다. Unity는 왼손 좌표계이기 때문에 왼손 법칙을 사용하여 X축으로 90도 회전하면 Z축은 땅방향을 가리키게 된다.(Y축은 X축의 영향을 받지 않는다.) Y축은 원래 하늘 방향이었기 때문에 두 축에 대한 회전은 같은 면에서 발생하지만 방향이 반대로 나타나게 된다.


이와 같은 결과는 어떤한 회전 종속성을 가지고 있더라도 중간에 있는 축을 회전하면 축이 겹치는 짐벌락 현상이 발생할 수 있다.

* 대안
- yaw, roll 짐벌 사이의 큰 각도를 유지하기 위해 모터에 의해 능동적으로 돌아가는 4번째 짐벌을 사용하여 극복할 수 있다.
- 짐벌락이 감지되었을 때 하나 이상의 짐벌을 임의의 위치로 회전시키고 리셋시킨다. (축 재정렬)
- 사원수(쿼터니언) 기법을 사용한다.
* 참고 자료
https://www.youtube.com/watch?v=zc8b2Jo7mno