쿼터니언을 모르면 게임 프로그래밍 하지 마라
나는 게임 프로그래밍을 배우면서 한 번의 진짜 충격을 받았다. 캐릭터가 움직일 때마다 회전이 제대로 되지 않는 버그를 마주했다. 코드를 몇 번이나 점검했다. 로직도 맞았다. 버그도 없어 보였다. 그런데 캐릭터의 움직임은 이상하게 꼬여 있었다. 축이 잠기는 현상, 즉 짐벌락을 경험한 것이다. 나중에 쿼터니언을 적용하는 순간 모든 게 해결됐다. 마법 같은 경험이었다.
짐벌락, 게임 개발자가 가장 두려워하는 버그
짐벌락은 게임에서 매우 구체적인 형태로 나타난다. 캐릭터가 카메라를 따라 회전할 때, 특정 각도에서 한 축의 자유도가 사라지는 현상이다. 예를 들어 카메라를 위아래로 움직일 때는 멀쩡하던 좌우 회전이, 어느 순간 먹통이 되는 경험을 게임에서 해본 사람이 있을 것이다.
처음엔 입력 처리 코드의 문제인 줄 알았다. 조이스틱 입력값을 검사했다. 벡터 계산도 다시 확인했다. 하지만 문제는 다른 곳에 있었다. 바로 오일러 각이라는 회전 표현 방식 자체에 있었다. 이걸 깨닫는 데까지 꼬박 이틀이 걸렸다.
오일러 각은 직관적이지만 치명적 약점이 있다
게임 프로그래밍을 배울 때 가장 먼저 배우는 회전 표현이 오일러 각이다. X, Y, Z축을 중심으로 각도를 지정하는 방식이다. 직관적이고 이해하기 쉬워서 초보자도 쉽게 다룰 수 있다. 회전 순서가 명확하고, 시각적으로 이해하기도 좋다.
하지만 게임 공간은 3차원으로 보이지만 실제로는 4차원으로 운영된다. 이득우의 ‘게임수학의 이해’ 영상에서도 설명하듯이, 단순한 각도 세 개로 회전을 표현하려니 어디선가 무리가 생기는 것이다. 두 축이 같은 방향을 가리키는 순간, 그 사이의 회전 자유도가 완전히 사라진다. 바로 짐벌락이 생기는 순간이다.
이는 수학적인 문제이지, 코드 버그가 아니다.
보간에서의 문제점이 가장 심각했다
내가 마주한 짐벌락은 특히 보간에서 심했다. 캐릭터가 한 각도에서 다른 각도로 부드럽게 회전하도록 선형 보간을 사용했는데, 중간값이 예상과 완전히 다른 경로를 따랐다. 출발점과 도착점은 맞는데 중간 과정이 이상했다.
예를 들어 A 각도에서 B 각도로 부드럽게 회전해야 하는데, 예상과 완전히 다른 방향으로 비틀려 가다가 마지막에야 목표점에 도달하는 식이었다. 카메라가 갑자기 튀어나왔다가 다시 돌아오는 형태의 움직임이었다. 게임을 플레이하는 입장에서는 매우 어색하고 불편했다.
오일러 각의 근본적인 특성 때문이었다. X, Y, Z 세 각도를 각각 독립적으로 보간하면, 3차원 회전 공간에서 최단 경로를 보장하지 않는다. 게임 수학에서는 물체의 이동과 회전을 분리해서 관리하는데, 회전만큼은 더 정교한 방식이 필요했던 것이다.
쿼터니언이 정답인 이유
쿼터니언은 4개의 숫자 (x, y, z, w)로 회전을 표현한다. 처음 배울 때는 이게 뭐 하는 건지 이해가 안 간다. 복소수와도 다르고, 벡터와도 다르고, 행렬과도 다르다.

하지만 수학적으로 보면, 쿼터니언은 3차원 회전을 4차원 공간에서 자연스럽게 표현할 수 있도록 설계되었다. 구체적으로 보면, 모든 단위 쿼터니언은 4차원 구(sphere) 위의 한 점이다. 이 4차원 구 위의 각 점이 하나의 회전을 나타낸다.

내가 경험한 두 가지 문제를 모두 완벽하게 해결한다.
첫째, 짐벌락이 발생하지 않는다. 쿼터니언은 어떤 각도에서든 세 축의 자유도를 유지한다. 캐릭터가 어떤 방향으로 회전하든 항상 세 축을 동시에 제어할 수 있다.
둘째, 보간이 자연스럽다. 두 쿼터니언을 구면 선형 보간(SLERP)으로 보간하면 회전 공간에서 최단 경로를 따라간다. 회전이 부드럽고 예측 가능하다.

내가 코드를 고치고 테스트했을 때 정말 그랬다. 같은 장면이 완전히 다르게 보였다. 캐릭터의 움직임이 자연스러워졌다.
벡터를 쿼터니언으로 회전시키는 방법
게임에서 쿼터니언을 실제로 쓸 때는 벡터를 회전시켜야 한다. 벡터 v를 쿼터니언 q로 회전시키는 공식은 다음과 같다.

역쿼터니언은 단위 쿼터니언의 경우 q⁻¹ = q̄ (w, -x, -y, -z)이다. 이 공식은 쿼터니언이 4차원 구 위의 점이라는 특성을 활용한 것이다.
게임에서 회전하면 무조건 쿼터니언
지금 내 규칙은 간단하다. 게임에서 회전이 필요하면 무조건 쿼터니언을 쓴다. 처음엔 오일러 각으로 직관적으로 이해하고 싶은 마음이 생기지만, 나중에 짐벌락에 걸릴 바에는 차라리 처음부터 쿼터니언을 쓰는 게 낫다.
나중에 리팩토링할 때의 고통이 얼마나 큰지 알았기 때문이다. 대부분의 게임 엔진도 내부적으로는 쿼터니언을 사용한다. 유니티도, 언리얼도, 고도도 모두 그렇다. 이들 엔진이 그렇게 설계한 이유는 수많은 개발자의 경험이 증명했기 때문이다.
배운 게임 수학에서 모든 물체는 4차원 공간에서 관리된다고 했다. 쿼터니언도 정확히 그 철학 위에 설계된 것이다. 3차원으로 보이는 게임 월드에서 4차원 공간의 특성을 온전히 활용하는 방식이다.
작은 프로젝트라도 피할 수 없는 선택
기술적으로는 쿼터니언 없이 게임을 완성할 수도 있다. 하지만 현실적으로는 피해야 한다. 작은 프로젝트라도 3D 회전이 조금만 복잡해지면 언젠가는 짐벌락을 마주한다. 그때 코드를 뜯어고쳐야 한다.
나처럼 며칠을 원인 불명의 버그로 고생하고 싶지 않다면, 게임 프로젝트를 시작할 때부터 쿼터니언을 학습하고 사용하는 게 투자다. 초반 학습 비용이 조금 더 들지만, 나중에 절약할 수 있는 시간과 스트레스가 훨씬 크다.
자주 묻는 질문
Q. 오일러 각으로는 정말 안 될까?
작은 프로젝트나 특정 상황에서는 오일러 각만으로도 가능할 수 있다. 예를 들어 UI 회전이나 간단한 2D 회전이라면 문제가 없다. 하지만 3D 캐릭터 회전, 카메라 제어, 보간이 필요한 순간 문제가 생긴다. 프로페셔널한 게임 개발이라면 처음부터 쿼터니언을 쓰는 게 맞다.
Q. 쿼터니언을 배우는 데 얼마나 걸릴까?
기본 개념은 며칠이면 이해할 수 있다. 하지만 직관적으로 사용하려면 몇 주 정도 여러 프로젝트에서 써봐야 한다. 처음엔 어렵지만, 사용할수록 자연스러워진다. 게임 엔진의 쿼터니언 함수들을 자주 쓸수록 빨리 익숙해진다.
Q. 어디서 쿼터니언을 배울 수 있을까?
게임 엔진의 공식 문서가 가장 빠르다. 유니티와 언리얼 모두 쿼터니언에 대한 상세 가이드를 제공한다. 게임 수학 유튜브 강의들도 도움이 된다. 실제 게임 프로젝트에서 쓰면서 배우는 것이 가장 효과적이다.
Q. 쿼터니언 말고 다른 방법도 있나?
회전 행렬(Rotation Matrix)이라는 방법도 있다. 하지만 메모리를 더 많이 사용하고, 계산도 복잡하다. 쿼터니언은 효율성과 계산량 모두에서 가장 좋은 선택이다. 대부분의 게임 엔진이 내부적으로 쿼터니언을 사용하는 이유가 바로 이것이다.
Q. 게임 엔진을 쓰면 쿼터니언을 직접 다룰 필요가 없지 않나?
네, 엔진이 대부분 처리한다. 하지만 회전의 원리를 모르면 예상치 못한 버그가 발생했을 때 해결할 수 없다. 기초를 아는 것이 트러블슈팅의 첫걸음이다. 특히 복잡한 카메라 제어나 애니메이션 보간을 구현할 때는 쿼터니언의 동작 원리를 이해하는 게 필수다.
