DirectX/[Inflearn_rookiss] Part2: DirectX12

22. Quaternion - 개념과 사용 방법

헛둘이 2023. 2. 1. 14:08

- 사원수라고도 부르며, Vector4와 같이 float4개로 이루어진 단위 

- 행렬에 비해 빠르고, 메모리를 적게 차지한다

- 그리고 짐벌락 현상을 막을 수 있다.

 

쿼터니언 q는 xi + yj + zk + w로 이루어져 있으며,

xi + yj + zk를 허수부, w를 실수부로 표현한다.

i, j, k는 서로 다른 공간에 존재하며, 아래와 같은 식을 만족한다.

 

i² = j² = k² = -1

ij = -ji = k

jk = -kj = i

ki = -ik = j 

 

각 요소의 제곱은 -1이지만 각각 요소에 대한 곱은 다른 차원으로 이동된다.

 

xi + yj + zk + w 로 이루어진 구성은 Vector4에서 x, y, z, w의 구성과 비슷함을 알 수 있다.

따라서 3차원 벡터 v(x, y, z)를 4차원 벡터 v(x, y, z, 0)로 변경하여 쿼터니언과의 연산을 진행할 수 있다.

 

선행 지식

쿼터니언의 곱

q₁ = x₁i + y₁j + z₁k + w₁ = (v₁, s₁)
q₂ = x₂i + y₂j + z₂k + w₂ = (v₂, s₂)

q₁*q₂ = 
(x₁w₂ + y₁z₂ - z₁y₂ + w₁x₂)i +
(y₁w₂ + z₁x₂ + w₁y₂ - x₁z₂)j + 
(z₁w₂ + w₁z₂ + x₁y₂ - y₁x₂)k +
(w₁w₂ - x₁x₂ - y₁y₂ - z₁z₂)

 

이 식을 정리하면 아래와 같다.

q₁q₂ = (v₁ x v₂ + s₁v₂ + s₂v₁, s₁s₂ - v₁·v₂)

 

벡터의 삼중곱

a x b x c = b( a · c ) - c( a · b )


변환된 벡터 v'을 구해보자

 

벡터 v (v, 0)을 변환한 벡터 v'은 다음과 같이 계산된다.

 

v' = qvq* (q*는 q의 켤례, 허수부에 -를 붙인 수)

이 식은 다음과 같이 전개된다.

 

v' = qvq* = (u, w)(v, 0)(-u, w)

 

쿼터니언의 곱으로 (v, 0)(-u, w)부터 연산

v' = (u, w)(-v x u + wv, v·u)

 

나머지도 이어서 연산하면 아래와 같이 전개된다.

 

 

실수부

w · v · u - u · ( -v x u + wv) = u · ( v x u ) = 0

 

두 벡터의 외적은 각각 벡터에 수직인 벡터가 나오는데,

그 벡터와 외적한 요소인 벡터를 내적하면 당연히 수직이므로 90도가 나와서 내적의 결과는 0이 된다.

 

 

허수부

-u x v x u + w · u x v + w ( -v x u + wv ) + ( v · u ) · u

= -v( u · u ) + u( u · v ) + w · u x v - w · v x u + w²v + ( v · u ) · u 

= w²+ 2w( u x v ) + 2u( u · v ) - v( u · u )

= (w² - u · u)v + 2u( u · v ) + 2w( u x v )

 

따라서

v' = ( (w² - u · u)v + 2u( u · v ) + 2w( u x v ), 0 ) 으로 계산된다. 

 

 


그래서 어떻게 적용하지?

 

이 좌표는 (r cos𝜽 , r sin𝜽)로 이루어져 있다.

위에서 구한 식을 좌표에 대입할 수 있을까?

좌표의 x 성분을 실수부를 나타내는 w로 두고, y 성분을 허수부를 나타내는 u로 두면 가능하다!

 

그런데 u는 3차원 요소를 가졌는데 이걸 어떻게 한 축으로 압축하지?

u는 u의 크기에 u를 가리키는 방향으로 분해하여 u를 표현할 수 있다.

u = s * n

(s는 u의 크기이며, n은 u의 방향벡터)

s는 피타고라스의 정리를 통해 구할 수 있다.

 

이 방식으로 계산된 식에 치환하면

(w² - u · u)v + 2u( u · v ) + 2w( u x v )

= ((c² - s²)v + 2((s)·n·v) (s)n + 2c(s)(n x v)

= (c² - s²)v + 2s²(n·vn + 2·c·s(n x v)

 

이렇게 치환이 가능하다.

이 식에 삼각함수의 합공식을 추가하면?

- cos²𝜽 - sin²𝜽 = cos(2𝜽)- 2cos𝜽sin𝜽 = sin(2𝜽)- cos(2𝜽) = 1 - 2sin²𝜽

 

= cos(2𝜽)v + (1 - cos(2𝜽))(n · v) · n + sin(2𝜽) · (n x v)

 

어? 그런데 이 공식 로드리게스 합 공식과 유사하다....

v' = v cos𝜽 + (v · a)a (1 - cos𝜽) + (a x v)sinα

 

 

결론적으로, 이 쿼터니언을 사용하는 방법은 아래와 같다

우리가 α축을 기준으로 어떤 벡터 v𝜽만큼 이동시키고 싶다면

q = ( sin(𝜽/2)α, cos(𝜽/2) ) 이렇게 쿼터니언을 세팅해준 뒤,

v' = qvq*를 통해 회전시킬 수 있다.