게임 수학의 골칫거리 - 쿼터니언(Quaternion) 쉽게 이해하기

오일러 각의 한계인 짐벌 락(Gimbal Lock) 현상을 해결하기 위해 게임 엔진에서 사용되는 쿼터니언(사원수)의 개념을 직관적으로 설명합니다.

3D 게임 프로그래밍을 시작하면 누구나 한 번쯤 회전(Rotation)을 제어하다가 멘붕에 빠지게 됩니다. 오브젝트의 각도를 조금 돌렸을 뿐인데 축이 꼬여 이상하게 돌아가거나 아예 특정 축의 회전이 먹통이 되는 현상을 겪게 되죠.

이것이 바로 짐벌 락(Gimbal Lock)이며, 이를 피하기 위해 게임 엔진이 채택한 구원자가 바로 쿼터니언(사원수, Quaternion)입니다.


1. 오일러 각(Euler Angles)과 짐벌 락의 비밀

우리가 일상에서 흔히 사용하는 (X, Y, Z) 회전은 오일러 각 방식입니다.

  • Pitch (X축 회전)
  • Yaw (Y축 회전)
  • Roll (Z축 회전)

오일러 각은 매우 직관적이지만 치명적인 단점이 있습니다. 세 축이 순차적으로 계산된다는 점입니다.

예를 들어, 오브젝트를 Y축으로 90도 돌리면 X축과 Z축이 완전히 겹치게 됩니다. 이 순간 원래 가져야 할 3차원의 자유도 중 1차원의 회전 자유도를 잃어버리는 현상을 짐벌 락이라고 부릅니다.


2. 쿼터니언(사원수)이란 무엇인가?

사원수는 수학적으로 4차원 복소수 공간에 존재하며, 다음과 같이 표현됩니다.

q=w+xi+yj+zkq = w + xi + yj + zk

이를 3D 회전에 매핑하기 위해 “어떤 축(Vector3)을 기준으로 몇 도(Angle)만큼 회전할 것인가?”로 바꾸어 이해하면 훨씬 쉽습니다.

  • (x, y, z): 회전의 회전축 방향 벡터
  • w: 회전 각도 정보 (cos(θ/2)cos(\theta/2))

쿼터니언은 축들의 순서에 구애받지 않고 단 한 번에 회전을 행렬로 연산하기 때문에 짐벌 락 현상이 근본적으로 일어나지 않으며, 회전 사이의 보간이 매우 매끄럽다는 장점이 있습니다.


3. 유니티에서의 쿼터니언 실전 팁

우리가 복잡한 복소수 수학 공식을 전부 외울 필요는 없습니다. 엔진의 빌트인 API를 올바르게 사용하는 법만 알면 충분합니다.

1) 오일러 각도를 쿼터니언으로 변환하기

직관적인 각도 Vector3 값을 엔진용 회전값으로 바꿀 때 씁니다.

Vector3 eulerRotation = new Vector3(0, 90, 0);
Quaternion targetRotation = Quaternion.Euler(eulerRotation);

2) 특정 방향을 바라보게 하기

몬스터가 플레이어를 쳐다보게 만들 때 최적입니다.

Vector3 direction = player.position - monster.position;
Quaternion lookRotation = Quaternion.LookRotation(direction);
monster.rotation = lookRotation;

3) 부드러운 회전 보간 (Slerp)

선형 보간(Lerp)과 달리 구면 선형 보간(Slerp)을 사용하여 일정한 속도로 아주 부드럽게 회전시킵니다.

// 현재 회전에서 타겟 회전까지 프레임마다 부드럽게 보간
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * turnSpeed);

⚠️ 절대 하지 말아야 할 행동

쿼터니언의 개별 성분(q.x, q.y, q.z, q.w)을 직접 하드코딩해서 수정하면 안 됩니다. 정규화가 깨져 물체가 화면에서 사려지거나 에러가 납니다. 꼭 수정해야 한다면 곱 연산(q1 * q2)을 통해 회전을 누적하는 방식을 취하세요.

#게임수학#3D#유니티#쿼터니언
< Back to Logs