개발하는 리프터 꽃게맨입니다.
[그래픽스] 짐벌락 없는 사원수 회전 본문
오일러 각을 이용해서 회전을 구현하면,
최전축이 서로 겹쳐서 하나의 축이 다른 두 축을 완전히 포함하게 되는 경우가 발생합니다.
이를 짐벌락 현상이라고 합니다.
이 경우 회전의 자유도가 제한되게 됩니다.
이에 대한 우수한 해결책은 사원수 (Quaternion) 회전 입니다.
사원수 개요
사원수는 실수부 1개와 허수부 3개로 이루어집니다.
허수 부호 i, j, k 는 모두 제곱하면 -1 을 만들어내는 허수는 맞으나
i, j, k 는 각각 다른 허수 체계를 사용합니다.
사원수라는 독특한 체계가 나오게된 배경은 복소평면을 3차원으로 확장시키고자하는 시도에서 비롯되었습니다.
실수부를 Right, 허수부 Up 으로 하여 복소수를 2차원 평면으로 표현할 수 있고, 이를 복소평면이라고 합니다.
윌리엄 로원 해밀턴은 복소수를 이용하여 3차원 공간을 표현하기 위해, 허수 i와는 j² = -1이 되는 허수 j를 도입했습니다.
그런데 j 를 추가하게 되면, 여러가지 공리를 만족하지 못하는 등 치명적인 문제가 발생하게되어
i, j, k 총 3개의 허수부를 사용하는 사원수 라는 체계가 등장하게 되었습니다.
사원수의 공리
새로운 수 체계가 도입될 때, 그 체계에서 자유로운 연산을 정의하기 위해서는 체의 공리들을 얼마만큼 만족하는지 살펴보는 것이 중요합니다.
체의 공리는 11가지입니다.
1. 덧셈에 대하여 닫혀있는가
2. 덧셈에 대하여 항등원이 존재하는가
3. 덧셈에 대하여 역원이 존재하는가
4. 덧셈에 대하여 교환법칙이 만족하는가
5. 덧셈에 대하여 결합법칙이 만족하는가
6. 곱셈에 대하여 닫혀있는가
7. 곱셈에 대하여 항등원이 존재하는가
8. 곱셈에 대하여 역원이 존재하는가
9. 곱셈에 대하여 교환법칙이 만족하는가
10. 곱셈에 대하여 결합법칙이 만족하는가
11. 덧셈과 곱셈에 대해서 분배법칙이 만족하는가
하나하나 확인해보겠습니다.
일단 나머지는 전개 해보면 다 나오는 것들이라서 넘어가고
곱셈의 항등원, 역원, 교환법칙만 살펴보도록 하겠습니다.
항등원이 존재합니다.
사원수 곱셈의 항등원은 1입니다.
사원수의 곱셈 교환 법칙을 보기전에 먼저
사원수를 순서쌍으로 나타내보겠습니다.
사원수는 크게 실수와 허수로 나뉘기 때문에
q = (a, v)
v = (b, c, d)
로 간단하게 나타낼 수 있습니다.
그렇다면 q1, q2를 곱해보겠습니다.
사원수 허수의 곱셈 성질을 이용하여 사원수 q1, q2를 곱해보면
식은 위와같이 정리됩니다.
앞서 말한 사원수의 순서쌍을 이용해서
사원수 곱을 정리해보면
스칼라 곱셈, 내적, 외적으로 사원수 곱셈을 정리할 수 있습니다.
그런데 허수부에는 교환법칙이 적용되지 않는 외적이 존재합니다.
즉, 사원수의 곱셈은 교환법칙을 만족하지 않습니다.
마지막으로 사원수의 곱셈 역원의 존재를 확인해보겠습니다.
실수 곱셈에서 역원을 구하는 것처럼 사원수의 곱셈 역원을 구하려고 하나... 분모에 사원수가 존재하는 경우는 정의되지 않기 때문에 이러한 방법으로는 역원의 존재를 확인할 수 없습니다.
그래서 켤레 사원수 개념을 사용합니다.
켤레 사원수는 허수 부분의 계수의 부호가 반대인 사원수를 의미합니다.
복소수와 켤레 복소수에 대응한다고 보면 되겠습니다.
사원수의 크기는 실수 계수들의 제곱의 합의 제곱근으로 정의됩니다.
즉, 이와같은 등식이 성립합니다.
켤레 사원수를 이용하면 사원수 곱셈의 역원이 존재성을 확인할 수 있습니다.
결과적으로 사원수는 곱셈의 교환법칙에만 유의하면 자유롭게 연산해도 상관없다! 라고 생각할 수 있습니다.
이러한 구조는 꼬인 체라고 합니다.
사원수와 회전 (1)
사원수는 4차원의 수 체계인데, 이것으로 어떻게 회전을 나타낼 수 있을까요?
먼저, 사원수를 이용하여 3차원 공간을 먼저 나타내봅시다.
사원수는 순서쌍으로 나타낼 시, 실수부와 허수부로 나눌 수 있습니다.
여기서 실수부가 0인 사원수를 순허수 사원수라고 부르며, 이런 특수한 사원수를 이용해서 3차원 공간의 벡터를 표현합니다.
이제 이 사원수를 회전시켜보겠습니다.
순허수 사원수에 특정 사원수를 곱해서, 회전된 순허수 사원수를 만든다고 해봅시다.
사원수 체계에서 회전을 담당하는 사원수를 회전 사원수라고 합니다.
특정 회전축 n 을 기준으로
P을 세타만큼 회전시키는 작업을 그림으로 나타내면 뒤와 같을 겁니다.
식을 조금 바꿔보겠습니다.
어떤 점 P를 회전하는 것은
점 P를 회전축과 평행한 성분과, 수직인 성분을 분해하여
수직 성분을 세타만큼 회전한 다음, 평행한 성분을 더해주는 것과 동일합니다.
그렇다면 수직성분을 세타만큼 회전시킨 벡터를 P'' 라고 할 때,
P''를 구해봅시다.
열심히 구해봤습니다.
결론적으로 이러한 등식이 나오는데,
이 식에서 회전 사원수를 구해보겠습니다.
이렇게 회전 사원수 q를 얻어낼 수 있습니다.
여기서 세타는 회전 각
n은 회전 축이 되겠습니다.
정리하자면 사원수 회전 공식은 다음과 같습니다.
이 식을 그대로 회전 공식에 이용하기는 힘듭니다.
벡터에서 수직성분과 수평성분을 뽑아내기도 힘들구요.
이 식을 간략화하기 위해서는 오일러 공식이 필요합니다.
오일러 공식과 사원수
수열중에 위와같은 꼴을 멱급수라고 합니다.
이중 x0 = 0 일 경우 아래와 같이 간단하게 정리할 수 있습니다.
어떤 함수 f(x)가 에서 무한 번 미분이 가능하고, 멱급수가 수렴한다면 이 함수는 멱급수와 대응될 수 있습니다.
f(x)를 무한 번 미분하면 위와같이 전개됩니다.
여기서 만약 x = 0 이라면 어떻게 될까요?
계수 an와 f(x)에 대한 관계식이 나오게 됩니다.
계수 an은 함수 f(x)의 도함수를 통해 위와같이 표현할 수 있습니다.
따라서 함수 f(x)는 위와 같은 형태로 정리할 수 있습니다.
이러한 방식으로 특정 함수를 멱급수로 표현하는 것을 테일러 전개라고 말하며
x0 = 0 에서 테일러 전개를 하는 경우, 이를 매클로린 급수라고 말합니다.
특정 함수 f(x)를 멱급수에 대응시키기 위해서는, f(x)는 특정 점에서 무한번 미분이 가능해야하고,
멱급수는 해당 점에서 수렴해야만 합니다.
무한 번 미분이 가능한 세 가지 함수를 매클로린 급수로 표현해보겠습니다.
전개를 하면 위와 같습니다.
참고로 멱급수의 수렴성도 판단해야 하는데, 스킵하겠습니다. (수렴합니다.)
어쨌든, 세 함수 모두 매클로린 급수로 표현할 수 있습니다.
cos과 sin를 더해보면, 그 꼴이 e 지수함수와 매우 유사해집니다.
만약, 제곱했을 때 -1 이 되는 수가 있다면
cos, sin, e지수함수 간의 관계식을 세울 수 있을 것 같습니다.
제곱했을 때 -1 이 되는 수는 허수 i입니다.
꼴이 더 유사해졌습니다.
잘 보면, 홀수 항에만 허수 i가 붙어있는 것을 볼 수 있습니다.
홀수 항은 sinx 의 항이기 때문에
sin에 i를 곱해주면, 위와같이 정리할 수 있습니다.
여기서 x 대신 세타를 대입하면
오일러 공식이 나오게 됩니다.
그런데 여기서 굳이 i가 아니더라도
거듭제곱했을 때 허수 i와 성질이 동일하다면
다른 수로도 오일러 공식을 정리할 수도 있습니다.
허수 i를 대체할 수 있는 것은 크기가 1인 순허수 사원수입니다.
즉, 위와 같이 사원수 체계에서도 오일러 공식을 정리할 수 있습니다.
앞서 정리했듯 회전 사원수는 위와같습니다.
회전축에 해당하는 사원수 n도, 크기가 1인 순허수 사원수입니다.
그러므로, 회전축 사원수를 이용하여
오일러 공식과 회전 사원수간의 관계식을 만들 수 있습니다.
이제 사원수의 회전을 지수함수로 나타낼 수 있게 되었습니다.
사원수와 회전 (2)
이제 오일러 공식과 회전 사원수 간의 관계도 찾았으니 다음과 같이 회전을 나타내봅시다.
이제, 오일러 공식을 이용해서 사원수 회전을 간단하게 나타내봅시다.
사원수 회전은 최종적으로 오일러 공식으로 간략하게 정리할 수 있습니다.
이제 오일러 공식을 사원수로 고쳐보겠습니다.
최종 사원수 회전 공식에서 사용되는 자연 지수함수는
위와같은 사원수와 켤레 사원수로 나타낼 수 있습니다.
그러므로 회전 공식은 사원수로 표현할 수 있으며
간략하게 위와같이 사원수를 나타낸다고 할 때,
위와 같이, 간단하게 회전 결과를 벡터의 외적, 스칼라 곱셈으로 나타낼 수 있습니다.
보기 쉽게 최종적인 회전 공식을 정리하면 위와 같습니다.
사원수 구조
사원수 덧셈, 사원수 곱셈, 벡터 회전 함수를 담고있는
사원수 구조체입니다.
사원수와 오일러 각 사이의 변환
이제 내부 회전 변환 로직을 사원수로 변경해보겠습니다. 하지만 사원수를 사용해 회전을 수행하는 것은 직관적이지 않을 수 있습니다. 왜냐하면 회전을 위해서는 회전축과 회전각이라는 두 가지 요소를 정해야 하기 때문입니다.
이러한 방식보다는 오일러 각을 사용해 회전을 수행하는 것이 더 직관적일 수 있습니다. 그러나 오일러 각 사용시 짐벌락 문제가 발생합니다.
오일러 각과 사원수 사이의 변환을 할 수 있다면, 이러한 문제를 해결하면서도 직관적인 회전 구현이 가능할 것입니다.
1) 오일러 각 -> 사원수 변환
오일러 각은 x축, y축, z축을 회전축으로 하여 각각을 회전시킨다음 모두 조합하는 식으로 동작합니다.
그러므로 오일러각과 동일한 회전 축으로 3개의 회전 사원수를 구한 뒤 조합하면 오일러 각을 사원수로 변환할 수 있을겁니다.
요, 피치, 롤에서 사용하는 각을 알파, 베타, 감마라고 할 때
요, 피치, 롤에 해당하는 회전 사원수는 다음과 같고
제 렌더러에서는 롤, 피치, 요 순서로 회전을 수행하므로
요 * 피치 * 롤을 구하면 다음과 같습니다.
그러면 사원수 구조체에 오일러 각을 받아주는 생성자를 만들어보겠습니다.
2) 사원수 -> 오일러 각 변환
이건 사원수 관련 문서에 나와있길래 따라했습니다.
식은 제 렌더러에 맞게 조금 고쳐줬습니다.
사원수와 회전행렬 사이의 변환
결국 렌더링은 하기위해서는 회전 시스템을 회전행렬 형태로 바꿔야만 합니다.
1) 사원수 -> 회전행렬
회전행렬은 로컬 축을 회전시킨 결과를 기반으로 만들 수 있습니다.
그렇다면
vx = (1, 0, 0)
vy = (0, 1, 0)
vz = (0, 0, 1)
을 회전시켜주면 되겠죠.
제 렌더러는 열기준 벡터를 사용하므로
회전된 로컬 축 벡터를 열에 끼워넣어서 회전행렬을 완성하면 되겠습니다.
회전 매커니즘 완성
이제 쿼터니언 구조체를 변환 클래스에 넣어줍니다.
쿼터니언 방식으로 회전을 시킬수도 있고
오일러 각 방식으로 회전시킬수도 있습니다.
이러면 직관적인 회전과 임의의 축에 대한 회전 둘 다 수행할 수 있습니다.
아래는 쿼터니언을 통해서 만들어낸 회전 시스템 결과입니다.
'컴퓨터 그래픽스' 카테고리의 다른 글
직접 만든 그래픽 엔진으로 여러가지 출력 (1) | 2024.09.05 |
---|---|
[그래픽스] 구형 선형 보간으로 회전 보간 (0) | 2024.08.27 |
[그래픽스] 삼각형 클리핑 (1) | 2024.08.19 |
[그래픽스] 가시부피와 절단 (0) | 2024.08.15 |
[그래픽스] 깊이 구현 (0) | 2024.08.14 |