(사실 이해했는지 모르겠다. 어렴풋이 느껴질 뿐... 그래도 그 느낌을 정리한다.)
0. 이거는 진짜로 이해했다고 말할 수 없다.
- 일단 이 quaternion 챕터 내용은 복소수에서 기하학적 해석으로 회전으로 개념을 확장하고, 복소수의 확장 + 일반적인 버번인 사원수도 그 회전의 개념을 적용시킨다.
- 사원수와 선형대수의 벡터 공간에서 연산을 이용하여, 임의의 축(axis)에 대해 벡터(점)를 세타(θ)만큼 회전시키는 식이 선형 변환(linear transform)이 선형 변환임을 알아내고,
- 그것을 행렬로 또 다른 선형 변환과 함께 사용할 수 있다는 것에 관한 내용인데...
- 솔직히 말해서... 공식으로 몇 번 유도해 보고, 써보고 결과를 눈으로 보니까 이해했다기보다는 그냥 익숙해진 느낌이다...
선형 변환 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)
- 어렸을 때 학교에서 써왔던 벡터 내적이니 외적이니 허수니 뭐니... 몸이나 눈에는 익숙하지만,
- 그것들의 엄밀한(?) 정의 그것이 어디에 쓰였고 개념이 왜 생겨났는지에 대한 이해가 없으니... 그냥 믿음으로 사용할 뿐이다.
- 아무튼 우리가 이렇게 벡터니, 행렬 같은 성분이 여러 개인 숫자들을 사용했던 이유는, 여러 변수를 한 번에 계산하는 것도 있지만, 여러 변수를 정해진 규칙대로 한번에 계산할 수 있기 때문이다.
(사원수의 규칙은... 교재를 보던가, 웹을 찾아서 보기로 하자. 여기에 쓰기에는 너무 많다.)
1. Quaternion (사원수)
- 고등학교 때 배웠던 복소수의 확장 버전이라고 할 수도 있고... 아니면 그냥 애초에 여러 개(4개)의 성분을 가진 벡터 느낌으로 가도 되고, 벡터부 + 실수부로 나뉜 친구일 수도 있고...
- 사원수는 (i, j, k, w)로 4개의 성분으로 이루어진 벡터고, 앞에 i, j, k를 허수 벡터부 뒤 w는 실수부다.
- 이렇게 만든 이유는? 3차원으로 뭐가 잘 안 되었기 때문이다... 아래 링크를 타고 들어가 보자.
- 사원수 - 역사 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)
(이 사람 진짜 천재인 것 같다)
- 아무튼 차원을 하나 늘리고 축의 개념을 추가함으로 이걸 가능케 한 것이다.
- 애초부터 사원수를 설계하기를... 3차원에 존재하는 점들이 벡터 공간 내에서 서로 나눌 수 있고 (사원수는 나눌 수는 없고 역을 정의한다) , 곱할 수 있고, 크기(스칼라)가 존재하며, 켤레수(conjugate)나 이런저런 연산 법칙(결합, 교환, 분배 등)이 존재하도록 한 것이다.
(i, j, k, w) 일 때 (i, j, k는 허수 벡터부, w는 실수부)
i^2 = j^2 = k^2 = ijk = -1
2. 회전과 쿼터니언
- 쿼터니언도 복소수(cosθ + i * sinθ )와 마찬가지로, 크기(norm)가 1이라면, Polar form(극형식)으로 나타낼 수 있다.
(의미는 아마도 각 축에 대한 편각을 나타내는 게 아닐까?)
- 단위 사원수 (u, w)을 극형식으로 나타내면
(sinθ * n, cos θ) = ( sinθ * nx, sinθ * ny, sinθ * nz, cosθ)
- 임의의 축 n을 중심으로, 벡터 v 가 몇 도 θ 회전하는지에 관한 식은 얼추 구할 수 있다.
- v'를 θ로 나타내면,
R(n, v) = cosθ v + (1- cosθ) (n . v) n + sinθ (n x v)
(대충 내적, 외적, 삼각함수를 이용하면 된다.)
- 이제 이걸 쉐이더에서 깔끔하게 사용하기 위해 행렬로 표현을 해야 한다. 이걸 하는 친구가 사원수이다.
- 실수부가 없는 pure-quaternion으로 나타내는 어떤 점 p와, 크기가 1인 사원수로 나타내는 어떤 축 q를 설정한다.
q = (u, w) / p = (v, 0)
- 점사원수 앞뒤로 축사원수를 그냥 곱셈과 켤레 곱을 해준다. 이걸 죽 정리하면 실수부가 없는 점 사원수가 결과로 나온다.
qpq* = (u,w)(v, 0)(-u, w)
= (u, w)(wv - v Xu, v . u)
실수부 :
w(v . u) - u . (wv - v x u)
= w(v . u) - u . wv + u . (v x u)
= w(v . u) - w(v . u)
= 0
벡터부 :
w(wv - v x u) + (v . n)u + u x (wv - v x u)
= w^2v - wv x u + (u . v)u + u x wv + u x (u x v)
= w^2v + u x wv + (u . v)u + u x wv + u x (u x v)
= w^2v + 2(u x wv) + (u . v)u + u x (u x v)
= w^2v + 2(u x wv) + (v . u)u + (u . v)u - (u . v)v // 삼중곱 공식
= (w^2 - u . u)v + 2w(u x v) + 2(u . u)v
= (w^2 - u . u)v + 2(u . v)u + 2w(u x v)
결론 :
qpq* = ((w^2 - u . u)v + 2(u . v)u + 2w(u x v), 0)
- 이렇게 실수부가 0인 순수 사원수(벡터)가 나온다.
qpq* = ((w^2 - u . u)v + 2(u . v)u + 2w(u x v), 0)
(켤레 사원수를 앞 뒤로 곱해주는 생각은... 벡터 방향 관계없이 같은 위치 혹은 회전을 보장하기 위해서 그렇게 한 걸까?)
- 사원수 qr가 크기가 1이라고 했으니, 극형식으로 표기해 보자.
q = (u, w) = (sin θ n, cos θ)
- 이걸 다시 대입하면
qpq* = ( cos θ ^ 2 - sin θ ^2) v + 2sin θ * (n . v) sin θ n + 2 cos θ sin θ (n x v)
- 나오고, 이걸 배각공식으로 더 간단하게 정리하면
qpq* = cos 2θ * v + (1 - cos 2θ) (n . v) n + sin 2θ (n x v)
- 위에 알록달록한 그림 아래에 있는 식과 비슷하다.
- 그래서 우리가 일반적으로 사원수로 회전 연산자를 표현할 때 다음과 같이 한다.
quat = (sin (θ / 2) *n , cos(θ / 2))
3. 사원수 회전을 아직 행렬로 안 바꿨다.
- 다시 여기서 시작한다.
qpq* = (w^2 - u . u)v + 2(u . v)u + 2w(u x v) // 실수부는 생략
q = (q1, q2, q3, q4)라고 하면, q는 단위 사원수라고 했으니 q1^2 + q2^2 + q3^2 + q4^2 = 1이다.
- 이걸 이용해서 q의 성분들로 v에 적용시킬 행렬을 나타내 보는 것이다.
- 첫 항은 요런 식으로
- 두 번째는 요런 식으로
- 세 번째는 요런 식으로
- 다 더하면?
- 다음과 같이 나온다.
- 이게 바로 사원수를 통해 회전을 시켜주는 행렬이다.
- 행렬을 다시 사원수 회전 연산자로 바꾸는 방법은... 그냥 거꾸로 하면 되고, 내용의 핵심이 아니기 때문에 스킵한다.
(물론 쉽지 않지만... 다른데 찾아보면 나오기 때문에 괜찮다. ㄹㅇㅋㅋ)
4. 구면 선형 보간과 단위구 개념
- 사원수도 성분이 4개인 벡터이고, 그쪽 세계(?)에서는 이 친구도 좌표로 존재할 수 있고, 또 그 쪽 세계(?)의 단위 구(unit sphere) 위에 존재할 수 있다고 한다. 사원수끼리 내적도 가능하다.
- 여기서 사용하는 사원수의 내적값은 두 사원수의 거리가 얼마나 가까운지를 대략적으로 판별하는 데에 쓰인다.
- 애니메이션은 keyframe으로 이루어지고, key frame 사이에 있는 값을 보간해서 부드럽게 사용해야 하는데,
- quat 회전을 보간하는 방법을 알아야 이것이 가능할 것이다.
- 이를 가능케 하는 것이 구면 선형 보간이다.
- 단위원 위의 사원수 a에서 θ 만큼 벌어져 있는 사원수 b로 움직이는 사원수 p를 t에 따라 나타내는 건데..
- 그 유도 방법은 교재에 있으니 나중에 찾아보자 ㅋㅋㅋㅋㅋ
(word로 행렬 쓰기가 쉽지 않다)
- 아무튼 구면 선형 보간 (spherical linear interpolation, slerp)의 공식은
t는 [0, 1], slerp(a, b, t) =sin((1 - t) θ) a + sin(t θ) b / sin θ
5. 추가 내용 간략하게 정리
- 회전 연산자의 합성 : 잘 합성이 되도록 정의가 되어 있다.
- 구면 선형 보간을 할 때 θ값이 너무 작으면 오류가 생길 수 있으니 그냥 선형 보간으로 한다.
- 회전 사원수 성질을 보면
- (sin (θ / 2) *n , cos(θ / 2)) 와 (- sin ((2pi - θ) / 2) *n , cos((2pi - θ) / 2))가 같은 결과를 가진다.
- 차이점은 도는 방향이다. 만약 애니메이션 보건을 구면 선형 보간으로 했을 때
- slerp(a, b, t)와 slerp(a, -b, t)는 회전을 하는 방향이 다른 것이다.
- 이럴 때는 | a - b |의 크기와 | a - (- b) |의 크기를 비교해서 더 작은 쪽이 가까운 쪽이다.
(비례는 아니더라도, 사잇각이 크면 현의 길이가 긴 것을 이용하는 것이다.)
6. 연습 문제
(클릭하면 커집니다.)
연습 문제 1
- 복소수 연산을 연습하는 문제다.
a. (3 + 2i) + (-1 + i) = (2 + 3i) b. (3 + 2i) - (-1 + i) = (4 + i) c. (3 + 2i)(-1 + i) = (-5 + i) d. 4(-1 + i) = -4 + 4i
e. (3 + 2i) / (-1 + i) = ((3 + 2i) (-1 - i)) / ((-1 + i)(-1 - i)) = (-1 - 5i) / 2
f. (3 + 2i)* = (3 - 2i) g. |3 + 2i| = root(3 ^ 2 + 2 ^2) = sqrt(13)
연습 문제 2
- 복소수 (-1, 3)를 극형식으로 표현하는 것이다.
- 일단 단위 복소수로 만든다. (-1 /root(10), 3 / root(10))
- θ = arcsin(3 / root(10))
- (- cos θ, sin θ)
연습 문제 3
- 벡터 (2, 1)을 복소수 곱셈으로 30도 회전시키는 것이다.
- 회전 복소수 = (cos30°, sin30°) = root(3)/2 + i/2
- (2 + i) (root(3) + i) / 2 = (2 root(3) - 1 + (2 + root(3)) i)
연습 문제 4
- 복소수 나눗셈의 정의를 이용해서 (a + bi) / (a + bi) = 1 임을 증명해라
- (a + bi) / (a + bi) = (a + bi) (a - bi) / (a+bi)(a -bi) = a^2 + b^2 / a^2 + b^2 = 1
연습 문제 5
- z = a + bi 일 때, |z|^2 = zz* 임을 보여라
- |z| = root(a^2 + b^2)
- zz* = (a + bi)(a - bi) = a^2 + b^2 = |z|^2
연습 문제 6
- 2x2 행렬인 M이 회전 행렬일 때만, detM = 1이고, invM = transposeM이라는 것을 증명하라는 문제다.
(어떤 조건일 때, 2가지를 동시에 만족하는 것을 증명하는 것이니깐... 대우 + 모순으로 시도해 보자)
- ad - bc != 1 이거나 invM != transposeM 이면, 회전 행렬이 아님을 증명하는 느낌으로
i) 일단 ad - bc = (1과 0이 아닌 어떤 k) 이고 invM = transposeM 일 때 가능한지 보자
- k는 0과 1이 아닌 무언가라고 했는데, 오른쪽 식을 만족 하려면 M은 영행렬이 되어야 한다. 그런데 영행렬의 행렬식은 0 이므로 이는 모순이 된다.
- 일단은 행렬식이 1인 것은 invM = transposeM이기 위한 필요조건이다.
ii) ad - bc = 1이고 invM != transposeM 이어도 가능한지 보자.
- 이러면 a^2 + b^2와 c^2 + d^2가 1이 되면 안 되는데... ac + bd가 0이 되면 안 되는데... 모순이다.
- 따라서 - ad - bc != 1 이거나 invM != transposeM 이면, 회전 행렬이 아니다.
- 그 대우인 회전 행렬이면 ab - bc = 1 이고, invM = transposeM이라는 명제는 참이다.
연습 문제 7
- 사원수 연산을 연습해 보라는 것이다. p = (1, 2, 3, 4) , q = (2, -1, 1, -2)
a. (1, 2, 3, 4) + (2, -1, 1, -2) = (3, 1, 4, 2)
b. (1, 2, 3, 4) - (2, -1, 1, -2) = (-1, 3, 2, 6)
c. (1, 2, 3, 4,) (2, -1, 1, -2) = ( -2 (1, 2, 3) + 4 ( 2, -1, 1) + (1, 2, 3) x (2, -1, 1) , - 2 * 4 - (1, 2, 3) . (2, -1, 1))
= ((6, -8, -2) + (5, 5, -5), -8 - (2 - 2 + 3)) = (11, -3, 7, -11)
d. p* = (-1, -2, -3, 4)
e. q* = (-2, 1, -1, -2)
f. p*p = (-1, -2, -3, 4) (1, 2, 3, 4) = (4(-1, -2, -3) + 4(1, 2, 3) + (-1, -2, -3) x (1, 2, 3), 16 - (-1, -2, -3) . (1, 2, 3))
= (0, 0, 0, 16 + 1 + 4+ 9) = (0, 0, 0, 29)
g. |p| = root(1^2 + 2^2 + 3^2 + 4^2) = root(29)
h. |q| = root(2^2 + (-1)^2 + 1^2 + (-2)^2) = root(10)
i. p inv = p* / (|p|^2) = (-1 / 29 , -2 / 29 , -3 / 29 , 4 / 29 )
j. q inv = q* / (|q|^2) = (2 / 10, -1 / 10, 1 / 10, -2 / 10)
연습 문제 8
- 단위 사원수 q = (1 / 2, 1 / 2, 0, 1 / root(2))를 극좌표로 표현하는 문제다.
- 1 / root(2) 는 cos45°이니깐
- sin45° n = (1/2, 1/2, 0) 이고, n = (1 / root(2), 1 / root(2) / 0) 이다.
- q = (sin45 ° (1 / root(2), 1 / root(2), 0), cos45°)
연습 문제 9
- 단위 사원수 q = (root(3) / 2, 0, 0, - 1 / 2)를 극좌표로 표현하는 문제다.
- 보통 극좌표로 표현할 때 θ는 [0, Pi]으로 제한을 건다. 그 안에서 cos θ = -1/2일 때 θ의 값은 2pi / 3 = 120 °이다.
- sin120 ° 는 root(3) / 2이니깐, q = (sin120 ° (1, 0, 0), cos120 ° )
연습 문제 10
- 축 (1, 1, 1)에 대해 45 ° 회전을 나타내는 단위 사원수를 구하라는 것이다.
- 축을 단위로 만들고 n = (1 / root(3) , 1 / root(3), 1 / root(3)) 그냥 공식에 넣는다.
- q = (sin45 ° n, cos 45 °)
연습 문제 11
- 똑같이 축 (0, 0, -1)에 대해 60 ° 회전을 나타내는 단위 사원수를 구하는 문제다.
- 이것도 냅다 공식에 넣는다. n = (0, 0, -1)
- q = (sin60 ° n, cos60 °)
연습 문제 12
- 두 사원수를 가지고 slerp 공식을 사용해 보고, 그 결과가 단위 사원수인지 확인하는 문제이다.
- p = (1/2, 0, 0, root(3) / 2), q = (root(3) / 2, 0, 0, 1/2), t = 1/2
- 일단 p와 q는 단위 사원수이다. 두 개의 내적으로 사잇각을 구하자.
- p . q = |p||q|cos θ = root(3) / 2 , θ는 [0, Pi] 이니까 θ는 아마도 30 ° = Pi / 6일 것이다.
- slerp 공식에 냅다 넣으면
slerp(a, b, 1/2), (θ = 30° = Pi / 6)
= (sin15° a + sin15° b) / sin30°
= 2sin15°(a + b) = 2sin15°(root(3)/2 + 1/2, 0, 0, root(3)/2 + 1/2)
- 인데... 삼각함수에 조예가 없으니 그냥 냅다 울프렘 알파로 계산했다.
연습 문제 13
- 사원수 (x, y, ,z, w)를 xi + yj + zk +w으로 표현하는 걸 증명하는 건데...
- 정의 자체여서 뭘 증명하라는 건지 모르겠다.
- i = (1, 0, 0), j = (0, 1, 0), k = (0,1,0)
- xi + yj + zk + w = x(1, 0, 0) + y(0, 1, 0) + z(0, 0, 1) + w
연습 문제 14
- qq* = q*q = q1^2 + q2^2 + q3^2 + q4^2 = |u|^2 + q4^2 을 증명하라는 문제다.
- 정의된 연산 자체를 몇 번 해보면 나오는 것이기에 스킵하겠다.
연습 문제 15
- 순사원수 p = (u, 0)와 q = (v, 0)가 있을 때, pq = (p x q, - p.q)임을 보이는 문제다.
- ...이것도 정의된 사원수 곱셈을 해보면 그대로 나오기 때문에 넘어가겠다.
연습 문제 16
- 사원수 성질을 증명하라는 문제다.
- p = (m, a), q = (n, b) 이라고 하자. (m, n 허수 벡터부, a, b 실수부)
a. (pq)* = q*p*
- (pq)* = ((m, a)(n, b))* = (an + bm + m x n, ab - m.n)* = (-an - bm - m x n, ab - m.n)
- q*p* = (-n, b)(-m, a) = (-bm - an + n x m, ab - m.n) = (-an - bm - m x n, ab - m.n) = (pq)*
b. (p + q)* = p* + q*
- (p + q)* = (m + n , a + b)* = (- m - n, a + b)
- p* + q* = (-m, b) + (-n, b) = (-m - n, a + b) = (p + q)*
c. 실수 s에 대해 (sq)* = sq*
- (sq)* = (sm, sa)* = (-sm, sa)
- sq* = s(-m, a) = (-sm, sa) = (sq)*
d. |pq| = |p||q|
- |pq|^2 = (pq)(pq)* = pqq*p* = p|q|^2p* = |p|^2|q|^2 = |p||q|^2
연습 문제 17
- slerp(a, b, t) = (sin((1 - t) θ)a + sin(t θ)b) / sin θ = cos(t θ) 임을 대수적(?) 증명하라는 문제다.
(모르겠다 넘어간다 ㅋㅋㅋㅋㅋ 대수적 증명이 뭔지도 모르겠다ㅋㅋㅋ )
연습 문제 18
- a, b, c가 3차원 벡터일 때 다음을 증명하는 것이다.
- 벡터 삼중곱 증명을 하는 문제다.
i) a x (b x c) = (a . c)b - (a . b)c
ii) (a x b) x c = - (c . b)a + (c . a)b
(검색하면 바로 나오기 때문에.... 그걸 보고 하도록 하겠다 ㄹㅇㅋㅋ)
7. 메모용
- 사원수를 느끼는(?) 데 도움을 주는 영상 https://youtu.be/zjMuIxRvygQ?si=7fEdQaafdfQQ6BIj
- 결국은 DirectXMath에서 제공하는 함수들을 사용할 것이다. 그 함수들을 사용하는데, 왜 이걸 사용하는지 내부적으로 어떻게 작동하는지를 이해하기 위한 챕터였다고 생각하련다.
책 : DirectX 12를 이용한 3D 게임 프로그래밍 입문
'Programming > D3D12' 카테고리의 다른 글
[일기장] 무작정 FBX SDK 사용해보기 (삽질 + Mesh) (0) | 2024.04.30 |
---|---|
[책공부] 캐릭터 애니메이션 chap 23 (연습 문제 X) (0) | 2024.03.25 |
[책공부] Ambient Occlusion + chap 21 연습 문제 (0) | 2024.03.08 |
[책공부] Shadow Mapping + chap 20 연습 문제 (0) | 2024.03.04 |
[책공부] Normal Mapping + chap 19 연습 문제 (0) | 2024.02.27 |