OpenGL 쉐이더 프로그래밍 - 3D 프로젝션

타입·2025년 9월 15일

컴퓨터 그래픽스

목록 보기
21/24

카메라 설정의 필요성

정규 뷰 볼륨 (Canonical View Volume)

OpenGL의 기본 카메라 설정
x,y,z 정규화: [-1, +1] x [-1, +1] x [-1, +1]
정규화 시 하드웨어 세팅 및 개발에 용이함
OpenGL로 개발 시 최종으로 정규 뷰 볼륨에 들어가도록 해야함
왼손 좌표계 사용

Projection Transform

View Frame을 Canonical View Volume으로 변환
([-1, +1] 공간 안에 들어가도록 변환)
촬영할 공간을 지정하여 클리핑
near clipping: 카메라에 가까이 있는 물체를 촬영에서 제외
far clipping: 카메라에서 너무 멀리 있는 물체를 촬영에서 제외

Projection Matrix Calculation

M_porj: Projection Transform 행렬
View Frame의 점 q_view를 Canonical View Volume으로 변환

  • 전체 Transform 과정
    qworld=Mmodelqmodelqview=Mviewqworldqproj=Mprojqview=MprojMviewMmodelqmodel\mathbf{q}_{world} = \mathbf{M}_{model} \, \mathbf{q}_{model} \\ \mathbf{q}_{view} = \mathbf{M}_{view} \, \mathbf{q}_{world} \\ \mathbf{q}_{proj} = \mathbf{M}_{proj} \, \mathbf{q}_{view} = \mathbf{M}_{proj} \, \mathbf{M}_{view} \, \mathbf{M}_{model} \, \mathbf{q}_{model}

평행 프로젝션, 투사 프로젝션

Parallel Projection

모든 빛이 필름에 평행하게 들어와 장면이 만들어진다고 가정

  • 직육면체 영역을 평행하게 Scaling
    계산에 용이함
    물체의 위치에 따른 크기의 변화가 없어보임
    공학/건축 설계도 사용에 장점 (Isometric, Cabinet 프로젝션 등)

Perspective Projection

실제 카메라와 같이 원근감을 생각하여 빛이 피라미드 형태로 뻗어간다고 가정

  • 점점 넓어지는 피라미드 영역
    계산이 복잡함
    원근감 표현 가능
    소실점 (1-point, 2-point, 3-point 프로젝션)

Orthographic Projection

Parallel Projection의 일종
xyz 좌표축에 평행하게 직육면체 영역 설정
해당 영역을 그대로 Scaling하여 Canonical View Volume에 대응시킴

x: left ~ right
y: bottom ~ top
z: -zNear ~ -zFar

[xmin,xmax]×[ymin,ymax]×[zmin,zmax][1,+1]×[1,+1]×[1,+1][x_{min}, x_{max}] \times [y_{min}, y_{max}] \times [z_{min}, z_{max}] → [-1, +1] \times [-1, +1] \times [-1, +1]

zNear, zFar 값의 설정

View Volume은 오른손 좌표계, Canonical View Volume은 왼손 좌표계
카메라를 기준으로 물체는 z축의 마이너스 값에 배치되어 있음
zNear와 zFar는 카메라로부터 거리를 나타내어 양수 값이므로 오른손 좌표계에선 z = -z_near, -z_far 평면으로 해석

(zmin=znear)>(zmax=zfar)(z_{min} = -z_{near}) > (z_{max} = -z_{far})

실제로는 z_min이 z_max보다 크지만 왼손 좌표계로 바뀌며 z축이 뒤집어져 정상적으로 매핑됨

2 Step Approach

  • 직육면체 중앙의 좌표
    (xmax+xmin2,ymax+ymin2,zmax+zmin2)\left( \frac{x_{max} + x_{min}}{2}, \frac{y_{max} + y_{min}}{2}, \frac{z_{max} + z_{min}}{2} \right)
  • 직육면체의 x축 길이
    xmaxxmin2\frac{x_{max} - x_{min}}{2}
  • Orthographic Projection
    1. 직육면체의 중앙을 원점으로 평행이동
    2. x,y,z 방향으로 각자 길이가 2가 되도록 크기변환
Mproj=ST=[2xmaxxmin00002ymaxymin00002zmaxzmin00001][100xmax+xmin2010ymax+ymin2001zfar+znear20001]=[2xmaxxmin00xmax+xminxmaxxmin02ymaxymin0ymax+yminymaxymin002zmaxzminzmax+zminzmaxzmin0001]M_{proj} = ST = \begin{bmatrix} \frac{2}{x_{max}-x_{min}} & 0 & 0 & 0 \\ 0 & \frac{2}{y_{max}-y_{min}} & 0 & 0 \\ 0 & 0 & \frac{2}{z_{max}-z_{min}} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -\frac{x_{max}+x_{min}}{2} \\ 0 & 1 & 0 & -\frac{y_{max}+y_{min}}{2} \\ 0 & 0 & 1 & -\frac{z_{far}+z_{near}}{2} \\ 0 & 0 & 0 & 1 \end{bmatrix} \\ = \begin{bmatrix} \frac{2}{x_{max}-x_{min}} & 0 & 0 & -\frac{x_{max}+x_{min}}{x_{max}-x_{min}} \\ 0 & \frac{2}{y_{max}-y_{min}} & 0 & -\frac{y_{max}+y_{min}}{y_{max}-y_{min}} \\ 0 & 0 & \frac{2}{z_{max}-z_{min}} & -\frac{z_{max}+z_{min}}{z_{max}-z_{min}} \\ 0 & 0 & 0 & 1 \end{bmatrix}

직사각형 윈도우 프로그램

윈도우의 종횡비에 맞춰서 View Volume 설정 필요
최종 비율이 어떻게 나올지 모르므로 Canonical View Volume을 미리 비율에 맞추는 건 불가능

기존 프로그램에선 윈도우의 사이즈 변경 시 물체의 비율이 유지되지 않음
M_proj에서 비율을 보정해야함

  • 좌표계 계산
    화면비를 4:3으로 할 때 직사각형 범위
    x: -1 ~ +1
    y: -0.75 ~ +0.75
    z: -1 ~ -3 (zNear: +1, zFar: +3)

  • vertex shader 프로그램
    z-negate는 필요 없음, Projection Transform에서 함께 처리함

    qproj=MprojMviewMmodelqmodel\mathbf{q}_{proj} = \mathbf{M}_{proj} \, \mathbf{M}_{view} \, \mathbf{M}_{model} \, \mathbf{q}_{model}
#version 330 core

in vec4 aPos; // vertex position: attribute
in vec4 aColor; // vertex color: attribute
out vec4 vColor; // varying color: varying
uniform mat4 uModel; // model matrix: uniform
uniform mat4 uView; // view matrix: uniform
uniform mat4 uProj; // projection matrix: uniform

void main(void) {
	gl_Position = uProj * uView * uModel * aPos; // transformation
	vColor = aColor;
}

MVP: Model - View - Projection

  • updateFunc() 함수
void updateFunc(void) {
	...
	// viewing transform, (0,0,2)를 바라봄
	matView = glm::lookAtRH(
	              glm::vec3( 0.0F, 0.0F, 2.0F ),
	              glm::vec3( 0.0F, 0.0F, 0.0F ),
	              glm::vec3( 0.0F, 1.0F, 0.0F )
	          );
	// projection matrix, 4:3 화면비 적용
	matProj = glm::orthoRH(
	              -1.0F, +1.0F,
	              -0.75F, +0.75F,
	              +1.0F, +3.0F // 좌표가 아닌 Distance 값
	          );
}

640x480 크기의 4:3 화면 비율에서 물체의 비율이 정상적으로 유지되어 출력하는 것을 확인

profile
주니어 언리얼 프로그래머

0개의 댓글