4. Scale, Rotation, Translation 변환 행렬
인프런 Rookiss C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈 게임 수학과 DirectX12을 듣고 리뷰한 내용입니다.
3차원 행렬
\[\overrightarrow{V}(x, y, z)\times \begin{pmatrix} m_{11}& m_{12} & m_{13} \\ m_{21} & m_{22} & m_{23} \\ m_{31} & m_{32} & m_{33} \end{pmatrix}\] \[X = xm_{11} + ym_{21} + zm_{31}\] \[Y = xm_{12} + ym_{22} + zm_{32}\] \[Z = xm_{13} + ym_{23} + zm_{33}\]이동을 하려고 할 때, $\overrightarrow{V}(x, y, z) + (3, 4, 5)$ 각 요소에 더하기만 하면 된다.
그런데 3차원 행렬 연산만으로 계산한다면 xyz의 값이 각 요소에 값에 영향은 주게 되어 이동 변환이 불가능해진다.
이 문제를 해결하기 위해서 동차좌표계를 활용한다.
동차좌표계
w는 항상 1이며, 연산을 돕기 위한 요소를 추가한 좌표계를 동차좌표계라고 한다.
\[(x, y, z, w)\times \begin{pmatrix} m_{11}& m_{12} & m_{13} & m_{14}\\ m_{21} & m_{22} & m_{23} & m_{24}\\ m_{31} & m_{32} & m_{33} & m_{34}\\ m_{41} & m_{42} & m_{43} & m_{44}\\ \end{pmatrix}\] \[X = xm_{11} + ym_{21} + zm_{31} + m_{41}\] \[Y = xm_{12} + ym_{22} + zm_{32} + m_{42}\] \[Z = xm_{13} + ym_{23} + zm_{33} + m_{43}\] \[W = xm_{14} + ym_{24} + zm_{34} + m_{44}\]$\overrightarrow{V}(x, y, z) + (3, 4, 5)$를 가능하도록 만들 수 있다.
Translation 변환 행렬
1. a, b, c 좌표로 이동.
- x,y,z의 값에 영향을 받지 않는 $m_{41}, m_{42}, m_{43}$에 각각 a, b, c를 할당해야 한다.
- 다른 요소들은 0으로 변경한다. x, y, z의 값이 계산에 영향을 주면 안되기 때문이다.
- 결과적으로, X = a, Y = b, Z = c로 벡터에 다음 행렬을 곱하면 벡터의 위치는 해당 위치로 이동하게 될 것이다.
2. Translation(부드러운 이동)
위 결과물은 특정 위치로 이동한다.
그러므로 부드러운 위치 이동보다는 특정 위치에 배치된다는 느낌이다.
위치의 이동을 부드럽게 처리하기 위해서는 나의 현재 위치에 해당 위치를 더하는 방식이 되어야 한다.
- x, y, z의 값을 살리기 위해서 m11, m22, m33의 위치에 있는 값을 1로 설정한다.
Scale 변환 행렬
- xa, yb, zc의 연산과정이 필요하다.
- m11, m22, m33에 각각 a, b, c를 곱하는 형식으로 구성한다.
- 나머지는 0, m44는 1로 지정한다.
다만, 중심좌표가 어디인지에 따라 스케일을 통해 오브젝트의 위치가 예상한 곳을 벗어날 수 있다. 따라서 보통 게임에서 사용하는 플레이어 캐릭터의 발 밑을 중심좌표로 하고 있다.
Rotation 변환 행렬.
1. Z축 기준 회전
1. 코사인 법칙을 통해 풀어낸다.
\[X = r\cdot\cos(\alpha + \theta)\] \[Y = r\cdot\sin(\alpha+ \theta)\]2. x, y는 다음 위 식으로 대체가능하다.
\[X = r\cdot\cos(\alpha)\cos(\theta) - r\cdot\sin(\alpha)\sin(\theta)\] \[Y = r\cdot\sin(\alpha)\cos(\theta) + r\cdot\cos(\alpha)\sin(\theta)\] \[x = r\cdot\cos(\alpha)\] \[y = r\cdot\sin(\alpha)\]3. 풀어내면 다음 식을 도출할 수 있다.
\[X = x\cdot\cos(\theta) - y\cdot\sin(\theta)\] \[Y = y\cdot\cos(\theta) + x\cdot\sin(\theta)\]4. 결과.
\[(x, y, z, w)\times \begin{pmatrix} m_{11}& m_{12} & m_{13} & m_{14}\\ m_{21} & m_{22} & m_{23} & m_{24}\\ m_{31} & m_{32} & m_{33} & m_{34}\\ m_{41} & m_{42} & m_{43} & m_{44}\\ \end{pmatrix} => \begin{pmatrix} \cos(\theta) & \sin(\theta) & 0 & 0\\ -\sin(\theta) & \cos(\theta) & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1\\ \end{pmatrix}\] \[X = xm_{11} + ym_{21} + zm_{31} + m_{41} => x\cdot\cos(\theta) - y\cdot\sin(\theta) + 0 + 0\] \[Y = xm_{12} + ym_{22} + zm_{32} + m_{42} => x\cdot\sin(\theta) + y\cdot\cos(\theta) + 0 + 0\] \[Z = xm_{13} + ym_{23} + zm_{33} + m_{43} => 0 + 0 + 1 + 0\] \[W = (0) + (0) + (0) + (1)\]스케일에서 어떤 기준 좌표인지에 따라 스케일이 달라지는 것을 알 수 있었다. 회전 역시 유사하게 기준 좌표을 어디로 하고 회전을 하느냐에 따라 다른 형태가 될 수 있다.
- 자전 : 자기 자신의 중심 좌표를 기점으로 회전
- 공전 : 외부의 기준 좌표를 기점으로 회전
짐벌락 현상
짐벌락 현상
- 회전 행렬 구성 방식
- 3D 공간에서 임의의 (x, y, z) 회전을 표현할 때, 보통 Z축, Y축, X축 회전 행렬을 개별적으로 구한 후, 정해진 순서(예: Z → Y → X)로 곱해서 하나의 복합 회전 행렬을 구성한다.
- 각 축에 대한 회전이 순차적으로 적용되며, 회전 순서에 따라 결과가 달라진다.
- 짐벌락 현상
- 정의
- 짐벌락은 Euler 각도로 회전을 표현할 때, 특정 회전(예를 들어 피치가 ±90°인 경우)에서 두 개의 회전축이 정렬되어, 원래의 3자유도 중 하나가 소실되는 현상
- 발생 원인
- 각 축의 회전 행렬을 정해진 순서로 곱할 때, 특정 각도(보통 피치가 90° 또는 -90°)에 도달하면, 한 축의 회전이 다른 축의 방향과 일치
- 이로 인해 원래 독립적으로 동작해야 하는 두 회전축이 하나의 축으로 합쳐지면서, 회전 자유도가 하나 줄어드는 문제가 발생
- 정리
임의의 (x, y, z) 회전을 구현하기 위해, 보통 Z, Y, X 축 회전 행렬을 차례대로 곱해 복합 회전 행렬을 만드는데, 이 과정에서 한 축의 회전(예를 들어 피치가 90°에 가까운 경우)으로 인해 다른 두 회전축(요와 롤)이 일치하게 되어 회전 자유도가 하나 줄어드는 현상이 발생하는데, 이것이 바로 짐벌락 현상이라고 한다.
SRT 행렬 결합법칙
행렬의 교환법칙은 성립하지 않는다. 다만 결합법칙은 가능하다.
이런 특징으로 Scale, Rotation, Translation 순서로 행렬을 곱한 값(교환법칙 X, 결합법칙 O)에 내가 변환하려는 벡터의 값을 곱하는 방식으로 진행해야만 한다.
- T->R : 좌표가 먼저 이동된 이후 회전을 하는 경우, 이동하기 전 위치를 중심으로 공전.
- R->S : 화전 후 스케일을 조절하면 회전으로 바뀐 기준 좌표를 중심으로 스케일이 늘어나면서 예상치 못한 결과 나올 수 있음.
https://learn.microsoft.com/en-us/windows/win32/direct3d9/transforms