4 minutes
❎ Direct3D 11 Graphics Pipeline - 8. 좌표계와 공간 좌표 변환
1. Coordinate Systems
DirectX는 왼손 좌표계 사용
왼손 좌표계
왼손 엄지, 검지, 중지를 폈을 때, 각각 X, Y, Z축을 할당한 양의 방향
또는 왼손으로 엄지 척👍할 때, 엄지를 제외한 네 손가락을 X축 -> Y축 순으로 거머쥔 후 엄지의 방향이 Z축 양의 방향
Unity(Y is up), Unreal(Z is up) 또한 왼손 좌표계를 사용
2. 공간 좌표 변환
$$ v' = v \cdot MVP $$Object Space(Local Space)
모델 자체의 좌표계로, 메시가 정의된 기준 좌표
원점(
(0, 0, 0))은 보통 모델의 중심
World Space
게임 세계 기준의 좌표계
Object Space 좌표에 World Matrix(Model Matrix)를 곱하여 변환(VS 책임)
View Space(Camera Space)
카메라를 기준으로 한 좌표계
카메라의 위치가 원점
DirextX 기준으로 카메라가 바라보는 방향은 +Z 방향(‘Y is up’ 기준)
World Space 좌표에 View Matrix를 곱하여 변환(VS 책임)
Clip Space
카메라에서 보이는 영역을 정규화된 볼륨(-w ~ w) 안으로 구겨넣은 좌표
부등식(\(-w \le x \le w\) 등)을 통해 Clipping을 쉽게 수행할 수 있도록 하기 위함
아직 Clipping 자체는 일어나지 않고, 원근감도 살아있지 않은 상태(이것들은 Rasterizer 책임)
View Space 좌표에 Projection Matrix를 곱하여 변환(VS 책임)
NDC(Normalized Device Coordinates)
화면 크기(해상도, 화면 비율)와는 독립적인 정규화 좌표계
좌표의 각 축이 (-1, 1) 범위의 정육면체 범위로 좁혀짐
- 단! DirextX에서는 NDC의 Z 범위가 -1 ~ 1이 아니라 0 ~ 1 범위임에 유의!
아직 픽셀 좌표는 아니며, 이 상태로 Rasterizer에서 처리
시각적으로는 오브젝트들이 정사각형 공간에 짜부라진 형태로 보임
Clip Space 좌표에 Perspective Division을 적용하여 변환
$$ (x_{\text{ndc}}, y_{\text{ndc}}, z_{\text{ndc}}) = (x / w, y / w, z / w) $$원근감이 실제로 적용되는 순간으로, 카메라에 가까우면 \(w\)가 작아 큰 값이 되고, 카메라에서 멀면 \(w\)가 커 작은 값으로 변환됨
Perspective Division은 Rasterizer의 고정 기능 단계
Viewport Space(Screen Space)
실제 픽셀의 좌표
NDC를 Viewport 설정에 따라 늘리는 Viewport Transform을 수행(Rasterizer 책임)
화면 자체는 2D지만, Depth Test 등을 위해 깊이 범위를 0 ~ 1로 유지
3. World Matrix
Object 좌표를 World(Model) 좌표로 변환하는 행렬
사용자가 물체를 어떻게 배치하고 싶은지에 따라 행렬의 형태가 크게 달라짐
크게 스케일, 회전, 이동 변환(아핀 변환)을 수행하며, 순서에 따라 \(M_{\mathrm{affine}} = S R T\) 순서(행 벡터 기준)로 곱하여 상수 버퍼로 Vertex Shader에 넘겨줌
- 전단 변환 또한 아핀 변환의 일종이지만, 이 경우 SRT 변환이 크게 영향을 받을 수 있어 많은 엔진들은 전단 변환을 허용하지 않음
4. View Matrix
World 좌표를 View(Camera) 좌표로 변환하는 행렬
게임 내에 배치된 정점들의 좌표들이 카메라를 원점으로 한 기준으로 바뀜
아래 설명에서는 카메라의 위치를 \(\mathrm{POS} = (t_x, t_y, t_z)\), 카메라가 바라보고 있는 방향을 \(\mathrm{EYE} = (f_x, f_y, f_z)\)로 가정
View Matrix를 구성하는 방법
카메라 이동(\(T\)): \(\begin{bmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 1 & 0 & 0 \\\\ 0 & 0 & 1 & 0 \\\\ -t_x & -t_y & -t_z & 1 \end{bmatrix}\)
- 카메라 기준에서는 월드 내 모든 오브젝트들이 카메라 위치만큼 역으로 이동한 것과 동일
카메라 회전(\(R\)): \(\begin{bmatrix} r_x & u_x & f_x & 0 \\\\ r_y & u_y & f_y & 0 \\\\ r_z & u_z & f_z & 0 \\\\ 0 & 0 & 0 & 1 \end{bmatrix}\)
카메라의 기저를 기반으로 생성
카메라의 방향 벡터를 기반으로 카메라의 기저를 생성하는 방법은 여기를 참조
- 단, DirectX에서는 행 기준으로 연산함에 유의
최종 View Matrix(\(V = RT\)): \(\begin{bmatrix} r_x & u_x & f_x & 0 \\\\ r_y & u_y & f_y & 0 \\\\ r_z & u_z & f_z & 0 \\\\ -r \cdot \mathrm{EYE} & -u \cdot \mathrm{EYE} & -f \cdot \mathrm{EYE} & 1 \end{bmatrix}\)
5. Projection Matrix
View(Camera) 좌표를 Clip 좌표로 변환하는 행렬
원근 효과 생성, View Frustum(Clipping할 범위) 정의의 역할
Projection Matrix(\(P\)): \(\begin{bmatrix} \frac{1}{\tan{(\mathrm{FOV_y})} \cdot \mathrm{aspect}} & 0 & 0 & 0 \\\\ 0 & \frac{1}{\tan{(\mathrm{FOV_y}})} & 0 & 0 \\\\ 0 & 0 & \frac{f}{f - n} & 1 \\\\ 0 & 0 & \frac{-n \cdot f}{f - n} & 0 \end{bmatrix}\)
\(FOV_y\)는 보통 사용자가 직접 지정(\(FOV_x\)는 \(FOV_y\)와 화면비로 결정됨)
\(\mathrm{aspect}\)는 화면비, \(f\), \(n\)은 카메라의 로컬 z 기저를 기준으로 각각 far plane, near plane까지의 거리