Euler Transforms
물체의 회전에 대해 다룬 적이 있다. 지금까지는 오일러 각(지금까지 사용했던 일반적인 각도)을 이용한 변환을 다루었다. 아래의 그림처럼 x, y, z축을 골고루 이용하면 물체에 임의의 방향을 줄 수 있다. 이렇게 주축 중심 회전을 결합해서 임의의 방향을 제공하는 것을 Euler transform이라고 한다.
위 그림에서는 x축으로 45도, y축으로 60도, z축으로 -45도 회전한 물체를 보았다. 하지만 아래 그림처럼 회전의 순서에 따라 결과값이 다르게 나타난다.
Keyframe Animation in 2D
여기까지 오일러 각도를 이용한 회전을 기억하고 있자. 이젠 지금까지와 다른 주제에 대해서 생각해보고자 한다. 지금까지 우리가 다룬 animation은 하나의 결과 장면이다.
실제 애니메이션을 만들기 위해서는 초당 20~60 프레임이 필요하다. 최근 게이밍 모니터의 경우 120hz~240hz까지도 표현을 하기 때문에 점점 이러한 기준은 올라가고 있다. 즉, 1초당 수십 수백개의 scene을 뿌려줘야 한다. 그렇다면 모든 frame을 하나하나 다 작업해야할까?
정답은 No 다.
모든 장면을 다 작업하는것이 이론적으로는 가능할지 몰라도 매우 복잡한 작업이고 어렵다. 영화와 같은 작업에서라면 그나마 생각해봄직 하더라도 그렇게 하지도 않고 특히나 게임과 같은 실시간 그래픽 처리에서는 불가능에 가깝다.
그렇다면 이러한 한계를 극복하기 위해서는 어떻게 해야할까? 우리는 특정 keyframe만 정의하고 이를 interpolation(보간)하는 방식으로 해결할 수 있다.
위는 이러한 방식으로 2개 키프레임(t0 과 t1)을 이용해 총 5개의 장면을 나타낸 것이다. 점점 다른 위치로 옮겨지며 방향도 바뀐다. keyframe 0에서의 좌표가 p0이고 keyfram 1에서의 좌표가 p1이라고 하자. 그럼 그 사이에서의 위치는 어떻게 표현할까?
바로 linear interpolation으로 표현한다. 중간 이미지들을 interpolate함으로서 구현하였다. 이동한 점(p(t))과 초기 각도(세타(t))로 keyframe 데이터들이 보간돼서 중간 프레임의 영상들을 만든다.
Keyframe Animation in 3D
이제 이를 3차원에서 응용해보자. Keyframe Animation은 같은 방식으로 보간된다.
Rx(90도), Rz(-90도), Translation 하면 위와 같은 결과가 나온다. 이걸 그래프로 나타낸 것이 오른쪽 그래프이다. orientation(Rotation), position(Translation)
keyframe0 -> keyframe1 : 모든 오일러 각은 0, x좌표 증가
keyframe1 -> keyframe2 : x축으로 90도 회전, z축으로 -90도 회전, y좌표 감소
2D와 마찬가지로 선형 보간을 통해 중간 프레임의 애니메이션을 만들 수 있다. 시간에 따라 변화하는 모든 데이터는 보간 대상이 된다.
위 과정의 중요한 점을 요약해보자.
- 물체의 방향은 회전이 결정한다.
- 그 회전은 Euler Transform이 담당한다.
- Euler Transform은 3개의 각도로 표현된다.
- 그 3개의 각도가 Key data를 형성하고, 이들이 중간 프레임에서 보간된다.
- 보간된 세타 x, y, z가 나오면 행렬 3개를 만들 수 있고, 이를 결합하면 3x3 행렬을 만들고, 이를 물체에 적용하면 중간 프레임의 회전된 물체가 나온다.
Euler Angles의 문제점
frame 0인 (a)와 frame1인 (b)는 각 축에 대해서 회전을 했을 때의 예이다. 근데 자세히 보면 보간된 중간 프레임인 (c) 문제가 생긴다는 것을 알 수 있다. 물체가 중간 프레임이 yz 평면에서 벗어나 있다. 정상적으로 보간되었다면 yz평면 내에서 움직여야 하는데 c는 그렇지 않다.
Quaternion
이러한 문제점을 해결하기 위해 새로운 각도 표현인 Quaternion을 도입한다. Quaternion은 복소수(허수 단위)를 확장한 것으로 qx,qy, qz, qw의 항으로 표현되는데, 아래 식에서 qw는 실수항 나머지는 허수항이다. i, j, k가 허수 단위이다. 즉, Quaternion은 4개의 원소를 갖는 4차원 벡터이다.
4차원 벡터이기 때문에 쿼터니언이라고 한다.
허수는 교환 법칙이 성립이 안된다.
p와 q 를 곱해보자.
두개의 쿼터니언을 곱하면 총 16개의 곱셈 조합이 나온다.
4개의 i, 4개의 j, 4개의 k, 그리고 4개의 실수의 구성요소가 나온다.
이렇게 쿼터니언을 정의하고 3차원 회전에 적용해보자.
2D Rotation through Quaternion
오일러 각을 이용한 2차원 회전은 cos(theta), sin(theta)으로 표현된 행렬을 좌표 (x,y)에 곱하는 것으로 표현하였다.
쿼터니언을 이용한 회전은 cos(theta)+sin(theta)i 로 표현되고 p x q로 회전을 계산한다.
위와 같이 실수부와 허수부가 만들어진다. 놀랍게도 실수부는 오일러각으로 표현된 x'와 같고 허수부는 y'와 같다.
3D Rotation through Quaternion
이제 3차원에서 쿼터니언을 이용한 회전(u를 중심으로 p를 theta만큼 회전한 경우)을 살펴보자.
쿼터니언은 4개의 원소를 가지는 4차원 벡터인데, 처음 3개의 원소를 p로 설정한다. p가 허수부를 결정하고, 실수부는 그냥 0을 집어 넣으면 된다.
회전 중심 축인 u를 자기 자신으로 나눠서 u 로 표기한다. 그리고 회전을 아래와 같이 또 다른 쿼터니언 q 로 표현한다.
그러면 qpq*를 이용해 연산할 수있다.(q*는 q의 켤래복소수)
2차원에서는 회전 대상 벡터를 p로 표현하고 회전은 q로 표현해서 p와 q를 곱했는데,
3차원에서는 회전 대상 벡터를 p로 표현하고 회전은 q로 표현해서 p의 왼쪽에 곱하고, 오른쪽에는 켤레 쿼터니언인 q*을 곱한다.
그럼 이 결과가 4온스로 나오고, 허수부만 뽑으면 그것이 바로 회전된 벡터 p'를 나타낸다.
x,y,z를 축으로만 회전 행렬을 표현할 수 있었는데 이제 쿼터니언을 이용함으로써 임의의 축(u)으로 회전을 할 수가 있게 되었다.
즉, 짐벌락(회전축이 겹침으로서 한개의 차원이 소실되는 문제)와 보간에서의 문제를 해결할 수 있게 되었다.
Interpolation of Quaternions
이제 keyframe 0에 p라는 쿼터니언이 있고 keyframe 1에 q라는 쿼터니언이 있다고 할 때, 중간 프레임에서 어떻게 보간을 하는지 보자.
(1-t)와 t를 사용하긴 하지만 좀더 복잡하다.
위와 같은 방식을 통해 쿼터니언으로 각도를 보간할 수 있게 되었다. 이를 spherical linear interpolation(slerp)이라고 한다. 다만 아직 해결해야할 한가지 문제가 남아있다. 우리는 지금까지 모든 변형을 matrix의 곱을 통해 진행했다. 하지만 쿼터니언은 4차원 벡터이므로 쿼터니언을 이용한 변형을 행렬로 표현해야 기존에 진행했던 모든 과정들을 그대로 사용할 수 있다.
Quaternion and Matrix
위와 같은 식으로 행렬과 쿼터니언은 언제든 바꿀 수 있다. 쿼터니언 회전(qx,qy,qz,qw)을 행렬로 바꾸는 식의 증명은 비교적 간단하다.
위에서 보았던 pq를 다시 생각해보자.
이를 행렬로 보면 다음과 같이 표현할 수 있다.
pq 는 (qx qy qz qw)의 선형 조합이기도 하므로 다음과 같이 표현될 수 있다.
이를 이용해 qpq*를 표현하면 다음과 같다.
이를 곱하면 하나의 4x4 행렬이 되는데 이때 쿼터니언의 성질을 이용하면 위 식으로 고쳐쓸 수 있게 된다.
이제 모든 회전에 대해서 쿼터니언을 이용한 방식으로 사용하고자 한다.
실제로 unity등의 game engine에서도 모든 회전에 대해 쿼터니언을 이용하여 구현한다.
Ref.
Introduction to Computer Graphics with OpenGL ES (J. Han)
'☘️ Computer Graphics > Fundamental' 카테고리의 다른 글
CG - Screen space Object Manipulation (0) | 2022.07.22 |
---|---|
CG - Output Merger (0) | 2022.07.20 |
CG - Lighting (0) | 2022.07.19 |
CG - Image Texturing (0) | 2022.07.18 |
CG - Rasterizer (0) | 2022.07.16 |