게임 수학 16장 : 사원수(4차원 수로 설계한 3차원 회전)
16장에서는 앞서 14장에서 배운 2차원 복소 평면을 확장하여 4차원의 수 체계인 사원수에 대해 배우게 된다.
사원수는 3차원 가상 공간에서의 물체의 회전 표현에 주로 사용되며, 오일러 회전의 짐벌락 현상을 극복하기 위한 주요 도구로서 사용된다.
사원수는 각 요소들이 모두 독립적인 스칼라들로 구성되어 있으며, 복소수보다 한 차원 높은 수 체계를 형성한다.
사원수(Quaternion)
사원수는 복소수와 동일하게 허수를 사용하지만, 다른점은 세개의 허수와 하나의 실수로 구성된 수 체계이다.
Quaternion H = a + ix + jy + kz (i, j, k는 허수)
여기서 Q가 아닌 H를 사용하는 Q라는 문자를 이미 유리수 집합에서 사용하고 있기 때문에 사원수 집합은 H로 표기한다.
사원수 요소의 특징
- i^2 = j^2 = k^2 = -1
- 서로 다른 두 요소를 곱하면 나머지 한 요소와 같다. (ij = k, jk = i, ki = j)
- 비가환적이다. (ji=−k, kj=−i, ik=−j)
- 세 요소를 모두 곱하면 -1이다. (ijk = -1)
보면 사원수는 디게 특이한 특징을 가지고 있다.
첫번째 특징은 허수와 같다고 볼 수 있지만, 두 번째 특징으로 인해 허수와의 차이를 찾아낼 수 있다.
각 요소들이 독립적으로 구성되어 있기 때문에, 일반적인 수학적 특징과는 조금 다른, 방향성을 갖는 순환적 곱셈 구조를 갖는다.
이런 순환적 곱셈 구조는 복소수가 체의 공간에 존재하는것과는 반대로 사원수가 체의 공간에서 곱셈에 대한 교환법칙을 성립하지 못하도록 만들기 때문에 유사체라는 공간에 존재하는 수라는 것을 알 수 있고, 곱셈할 때 순서에 주의해야 한다는 것을 우리에게 알려준다.
사원수의 곱셈(해밀턴 곱)
사원수는 4개의 실수 성분 (a,b,c,d)으로 구성되며, 두 사원수의 곱을 계산할 때에는 각 성분 간의 모든 조합이 고려되므로 총 16개의 곱셈 항이 생성된다.
이 항들은 i,j,k의 곱셈 규칙을 따라 정리되며, 최종적으로 하나의 사원수 형태인 a+bi+cj+dk로 축약된다.
두 사원수 q와 p의 곱은 다음과 같이 전개된다.
파란색은 보면 요소의 곱이 반대인게 있으니까 항상 주의해야 한다.
사원수의 크기(Norm)
| q | = root(a^2 + b^2 + c^2 + d^2)
단위 사원수
크기가 1인 사원수
방향 벡터와 유사하게 순수한 회전을 표현하는데 사용된다.
켤레 사원수 (q*)
한 사원수의 허수부(bi + cj + dk)의 부호를 뒤집은 사원수
사원수 q(a + (bi + cj + dk))의 켤레 사원수(q*)는 (a - (bi + cj + dk))
순허수 사원수(Pure imaginary quaternion)
실수부가 0인 사원수
사원수와 벡터
사원수는 4차원 공간에 존재하는 수이기 때문에 3차원 공간의 존재인 우리들의 인지 능력을 벗어나 제대로 파악할 수 없다.
그래서 사원수를 관찰할 때에는 실수부 1개 차원과 허수 3개 요소로 이루어진 3차원의 허수부 1개로 분리하여 3차원공간에서의 성질을 관찰하는 것을 기본으로 한다.
여기서 실수 성분(스칼라부)은 회전의 크기를 의미하고, 허수 성분(벡터부)은 각 회전의 축과 방향을 의미한다.
사원수의 곱셈은 벡터의 내적과 외적을 이용해 깔끔하게 표현할 수 있다.
Dot(q1, q2) = (w1 * w2 - Dot(v1->, v2->), w1 * v2-> + w2 * v1-> + Cross(v1, v2))
만약 두 개의 순허수의 곱셈을 전개한다면 다음과 같이 스칼라 값이 모두 0이 되어 깔끔하게 떨어진다.
Dot(q1, q2) = (Dot(-v1->, v2->), Cross(v1, v2))
사원수의 회전
앞서 15장에서 복소수와 오일러 공식의 연관성에 대해서 배웠다.
그런데 만약 허수 i와 동일하게 크기가 1이고 제곱했을 때 결과가 -1임을 만족하는 수가 존재한다면 사원수 또한 오일러 공식을 만족한다는 것을 알 수 있다.
그것이 바로 순허수인 단위 사원수이다.
단위 사원수는 크기가 1인 사원수인데, 만약 사원수가 순허수임을 만족한다면 스칼라부의 값은 항상 0임이 보장되기에
q^2 = -1, | root(q^2) | = 1 라는 조건이 항상 성립하게 된다.
이전에 진행했던 순허수의 곱셈의 전개 식을 생각해 본다면 다음과 같이 볼 수 있다.
Root(0 + |n->|^2) = 1
여기서 실수부 0을 제거한다면 |n->| = Dot(n->, n->) = 1이라는 수식이 성립하게 되니
Dot(n->, n->) = (Dot(-n->, n->), Cross( n->, n->))가 된다.
그런데 (Dot(-n->, n->) = -1이니 Cross( n->, n->)는 항상 영벡터여야 한다. (-1, 0->)
최종적으로 다음과 같이 사원수의 회전을 자연상수의 지수함수로 표현하는 것이 가능해지고,
단위 복소수와 형태가 유사해 진다.
이것을 회전 사원수라고 부르는데, 4차원 공간에서 회전축 n->를 중심으로 회전 변환하는 성질을 갖는다.
3차원 공간에서의 회전
순허수 사원수는 벡터에 대응하는 개념이기에 그냥 냅따 회전 행렬로 적용하면 될 것 같지만, 앞서 보았듯이 사원수는 교환법칙이 성립되지 않기 때문에 연산 순서에 항상 유의해야 한다.
그래서 항상 원본 벡터의 왼쪽에 회전 사원수를 배치하여 곱셈을 적용한다.
문제가 또 있다. 바로 회전 연산의 결과로 순허수 사원수가 아닌 사원수의 구성 4요소를 모두 사용하는 일반사원수가 회전곱의 결과로 튀어나온다는 것이다.
이것은 선형성을 심각하게 훼손시키는 결과이기에 아핀 결합식과 같이 특수한 경우에만 성립되는 회전 수식을 발견해야 한다는 것을 시사한다.
우리는 이것에 대한 해답을 이전 11장에서 배웠던 로드리게스 축-각 회전식에서 발견할 수 있다.
1. 우선 다음과 같이 V->를 n-> 축에 대해 수직 성분과 수평 성분으로 분해한다.
2. 수평 성분을 각 θ만큼 회전이동 시킨 후 수직 성분을 더해 벡터 v'을 구한다면 실수부 값의 변경 없이 항상 순허수만이 변경되는 회전변환을 구할 수 있다.
회전 변환을 오일러 공식을 통해 표현하면 다음과 같다.
여기서 VII->는 수평 성분이니 스칼라 값이라고 보고, 두번째 항인 수직성분의 회전 사원수와 벡터의 곱셈을 전개해 본다면
교환법칙이 성립하지는 않지만 다음과 같은 수식이 성립함을 알 수 있고,
또한 수평 성분( VII-> )를 회전 사원수와 곱셈 전개를 하자면 수평 성분에 대해서는교환법칙이 성립함을 알 수 있다.
만약 회전 사원수의 각을 둘로 쪼개 전개한다면 다음과 같다.
여기서 뒤에 부분을 켤레 사원수로 바꾸면 수식의 결과가 항상 항등원인 1로 대응되므로 3차원 공간에서의 회전 변환이 성립함을 보장하게 되는 회전식이 된다.
실수부는 내적과 외적으로 전개했을 때 그 값이 항상 0이 나온다.
허수부는 전개했을 때 최종적으로 다음과 같이 정리된다.
회전 사원수와 회전사원수의 곱은 두 각을 합한 사원수에 대응한다.
사원수의 활용
- Matrix
- 오일러 각(Rotator)
- Quaternion
오일러 각에서 사원수로의 변환
오일러 각에서 회전을 표현하기 위해 각 축 요소를 롤, 피치, 요 회전으로 구성하였는데, 사원수로 표현하면 각각 다음 요소들에 대응된다.
이 세 회전 요소들을 파이프라인에 따라 회전변환을 적용하면 오일러 각에 대응하는 사원수가 만들어진다.
사원수를 오일러 각으로 변환하기
사원수로부터 오일러 각을 구하려면 사원수를 잘 조합해 단일 각에 대한 삼각함수가 나오도록 식을 설정해 주어야 한다.
전개식이 어려워 스킵하지만 예를 들어 대충 설명 하자면 롤에 해당하는 회전 변환 값을 구하려면 tanθroll을 구하고,
roll = atan2(2(wz + xy) / (1 - 2(z**2 + x**2)))
- 단위 사원수 (∣q∣=1 )
- 회전 순서에 따라 공식을 바꿔야 합니다.
- arcsin 함수의 범위로 인해 pitch(θ)에서 gimbal lock 문제가 발생할 수 있다. arcsin ∈ [−π/2,π/2]
사원수 -> 회전 변환행렬
회전 변환행렬은 로컬 축으로 구성되어 있기 때문에 사원수의 벡터부의 각 요소들의 값을 구하면 쉽게 구할 수 있다.
각요소들의 기저 벡터를 통해 계산하면 쉽다 (1, 0, 0), (0, 1, 0), (0, 0, 1)
회전 변환행렬 -> 사원수
회전 변환행렬에서 사원수를 구하는 방법은 오일러 각에서 그러했던 것 처럼 행렬의 요소를 조합해서 사원수의 벡터부의 각 요소들을 개별적으로 구해내야 한다.
이것은 정방행렬의 대각 성분의 합을 더하는 것에서 해답을 찾을 수 있다. 이것을 트레이스(Trace)라고 부른다.
t = 3 - 4(x^2 + y^2 + z^2)
여기서 양 변에 1씩 더하면 t+1 = 4w^2 = 4-4(x^2 + y^2 + z^2)로 수식을 단순화 할 수 있다.
여기서 만약 T값이 -1보다 작거나 같으면 4w^2의 값이 0보다 작거나 같아져 해가 존재하지 않게 된다. 그래서 벡터부의 각 성분 중 가장 큰 대각 성분을 기준으로 삼아 다른 값을 추정해야 한다.
켄 슈메이크 알고리즘
위에서 언급된 예외 상황을 고려하여 회전 변환행렬로부터 사원수를 구하는 알고리즘이다.
- w를 제외한 x, y, z중 가장 큰 요소를 파악하여 가장 큰 값을 먼저 계산한다.
- 이후 나머지 두 요소는 아래의 그림을 통해 요소를 파악하고 값을 계산한다.
- 세 요소의 값을 모두 구했다면 최종적으로 w값을 얻는다.

3차원 회전 행렬의 장단점 비교표
행렬 | 오일러 각 | 사원수 | |
저장 공간 | 크다 3 * 3 |
가장 작다 3 |
작다 4 |
짐벌락 현상 | X | O | X |
회전 보간 | 불가능 | 한 기저 축에 대해서만 보간 가능 | 임의의 축에 대해 보간 가능 |
직관성 | 직관적이지 않음 | 가장 직관적 | 4차원 수라서 직관적이지 않음 |
사원수의 보간법 / 구면 선형 보간(Slerp)
사원수는 선형 보간하면 쉽고 빠르게 보간값을 구할 수 있다.
하지만 사원수는 회전 변환에 사용되는 수 체계이기 때문에 선형보간으로 값을 구한다면 왜곡이 생기고 만다. 그래서 사원수를 회전에 사용하려면 정규화 과정을 거쳐야 한다.
그림을 자세히 보다 보면 사원수의 보간이란 회전 변환의 적용 비율을 조정하여 일정하게 조금씩 회전변환을 수행하는 것이라는 것을 알 수 있다.
이제 좌표를 실제로 구한다면 사원수 보간 좌표는 벡터로 바꿀 수 있다.
그런데 우리는 아직 x->에 직교하는 y->(축에 대 정보)의 값을 모르고 있으므로 u->와 삼각함수를 활용해 구할 수 있다.
※ 좌표 변환된 v->는 x->에 해당하는 1차원정보이므로 다른 축 정보(y좌표)가 필요하다.
최종적으로 계산되는 v->의 값은 다음과 같다
이것을 구면 선형 보간(Slerp)이라 부른다.
구면 보간시 유의할 점
구면 보간시 유의할 점이 하나 있다. 바로 우리가 해야할 변환이 회전변환이라는 것이다.
회전 변환은 항상 360º를 기준으로 주기를 가지고 있으며, 반대 방향으로도 회전 변환을 진행할 수 있기 때문에 표현 방법이 2가지라는 것이다.
일반적으로 회전 변환의 진행 방향을 정해주지 않았다면 긴 경로와 짧은 경로 두 가지 경로가 도출되는데, 짧은 경로를 선택하여 보간을 진행 한다.
짧은 경로를 파악하는 방법은 사원수에 저장되어 있는 절반의 각을 사용하여 파악할 수 있다.
긴 경로는 보통 180º 이상의 사잇각을 갖는다. 이 것의 반은 90º이므로, 내적을 통해 직교성과 거리의 크기를 통해 파악할 수 있다.
모든 예제 코드의 소스파일은
GitHub - onlybooks/gamemath: <이득우의 게임 수학> 공식 깃허브 페이지
GitHub - onlybooks/gamemath: <이득우의 게임 수학> 공식 깃허브 페이지
<이득우의 게임 수학> 공식 깃허브 페이지. Contribute to onlybooks/gamemath development by creating an account on GitHub.
github.com
또한 제 개인 깃허브 레포지토리 에 있습니다.
Workspace/C++/GameMath at main · cyphen156/Workspace · GitHub
Workspace/C++/GameMath at main · cyphen156/Workspace
Studying . Contribute to cyphen156/Workspace development by creating an account on GitHub.
github.com
※ 이득우 교수님의 인프런 게임수학강의를 참고하여 작성되었습니다.