왜 투영 행렬이 필요한가?
- 우리가 다루는 3D 공간의 정보는 모니터라는 2D 평면에 시각적으로 표시되어야 합니다.
- 이때 3D 공간의 점(Vertex) 들을 2D 화면으로 변환(투영) 해주는 작업이 필요합니다.
- 이 변환을 수행하는 수학적 도구가 바로 투영 행렬(Projection Matrix) 입니다.
투영 행렬의 구조
[ 1/(aspect) * scale 0 0 0 ]
[ 0 scale 0 0 ]
[ 0 0 f/(f - n) 1 ]
[ 0 0 -n*f/(f - n) 0 ]
- 이 행렬은 3D 공간의 점을 카메라 시점(View Space) 에서 NDC 공간(정규화된 장치 좌표) 으로 변환합니다.
- 여기서 aspect, scale, n, f는 각각 다음을 의미합니다:
투영 행렬 요소 설명
NDC 공간(정규화된 장치 좌표)
- GPU가 화면에 그리기 직전 사용하는 좌표계로, 모든 좌표가 -1에서 +1 사이로 정규화되어 있습니다.
- X축: 왼쪽 -1 ~ 오른쪽 +1
- Y축: 아래 -1 ~ 위 +1
- Z축: 0 ~ 1 (깊이값)
Aspect (종횡비)
- 화면의 가로/세로 비율입니다:
- WINCX / WINCY
- x축 비율 조절에 영향을 주며, 수평 시야의 폭을 결정합니다.
Scale (시야각에 따른 스케일)
- 카메라의 시야각(FOV, Field of View)에 따라 결정됩니다:
- 1 / tan(FOV * 0.5)
- y축 비율을 직접 조절하며, 결과적으로 x축도 영향을 받습니다.
n, f (Near, Far Plane)
- n: 카메라에서 가장 가까운 깊이
- f: 카메라에서 가장 먼 깊이
- 이 두 값은 z축의 깊이값을 정규화(NDC로 보정) 하는 데 사용됩니다.
M11 (1행 1열): x축 크기 결정
행렬 예시
- WINCX = 800, WINCY = 600 → Aspect = 4 / 3
- FOV = 90도 = π / 2 → Scale = 1 / tan(π / 4) = 1
- 결과: M11 = (3 / 4) * 1 = 0.75
→ x축 크기 비율은 0.75배
M22 (2행 2열): y축 크기 결정
예시
- FOV = 90도 = π / 2 → tan(π / 4) = 1
- 결과: M22 = 1 / 1 = 1
→ y축 크기 비율은 1배
M34 (3행 4열): 동차 좌표 w 생성
- 값: 1
- 이 요소는 투영 과정 후 동차 좌표의 w 값을 설정해줍니다.
- 이로 인해 최종적으로 (x, y, z) 좌표들이 w로 나뉘며, 원근감(Perspective) 이 표현됩니다.
동차 좌표(Homogeneous Coordinates)와 투영
- 3D 공간의 점: (x, y, z, w=1)
- 투영 행렬 적용 후: (x’, y’, z’, w’ = z)
- x’ = x * (1 / Aspect * Scale), y’ = y * Scale, z’ = z(f/(f - n) + -n*f/(f - n)), w’ = z
- 최종 2D 화면 좌표로의 변환:
왜 나누기(w')를 해야 할까?
- w'는 View 공간 상에서의 깊이(z값)입니다.
- 이 값을 통해 가까운 객체는 크게, 먼 객체는 작게 보이도록 원근감을 적용합니다.
- 결과적으로 (x'/z, y'/z, z'/z)가 되어 NDC 공간의 2D 투영 좌표가 완성됩니다.
Q1. 왜 FOV가 90도일 때 크기 비율이 1인 이유.
- Scale = 1 / tan(FOV / 2)
- FOV = 90도 → tan(45도) = 1
- 따라서 y축 비율 = 1배가 됩니다.
- x축에는 종횡비를 나눠주는 이유는, 현재 모니터는 대부분 가로가 더 긴 직사각형입니다.
- 때문에 x축 스케일은 다음과 같이 조정되어야 합니다.
- y축은 정사각형 기준으로 맞췄으므로, 가로 방향 스케일을 줄여주어야 정사각형이 찌그러지지 않습니다.
Q2. 왜 z 나누기를 해야 하나요?
- DX에서 (Vector와 Vertex를 구별할 때 4번째 좌표인 w 값을 이용 하여 구별합니다.
- 이때 w≠0 이면 Vertex, w=0이면 방향 벡터로 취급됩니다 (DX의 규칙).
- 원근 투영 행렬을 곱한 결과는 동차 좌표계로 표현된 4D 벡터 (x’,y’,z’,w’) 가 나옵니다.
- 화면에 그리기 위해서는 정규화된 3D 좌표로 바꾸어야 합니다. 이를 위해 동차 좌표를 비동차화 합니다.
- 이 나눗셈은 2D 평면에서의 원근 투영을 완성하는 마지막 단계입니다.
끝으로..
부족하지만 제가 이해한 부분을 정리한거라.
특정 부분이 틀렸거나, 조금 더 깔끔한 설명이 가능하시다면 피드백 댓글로 남겨주시면 감사하겠습니다.
'게임 프로그래밍' 카테고리의 다른 글
동차 좌표 (0) | 2025.04.20 |
---|---|
몬스터 행동 패턴 구현 정리 (2D) (0) | 2025.04.03 |