경북대 '컴퓨터그래픽스' 강의 백낙훈 교수님의 강의를 듣고 복습하기 위한 게시글입니다.
게시글의 내용은 강의 또는 구글링을 통해 공부하였습니다.
이미지 자료는 출처를 밝히거나 직접 그려 사용하였습니다
Projection 종류에는 두가지가 있다.
- parallel projection
2. perspective projection
parallel projection 같은 경우 ortho graphic으로 이전에 한번 다루었다.
오늘은 perspective projection에 대해 작성할 것이다.
parallel projection의 경우 직육면체 영역을 평행하게 scaling하기 때문에 계산이 쉬운 대신 원근감이 없다.
perspective projection의 경우 점점 넓어지는 피라미드 영역을 설정한다.
계산이 복잡해진 대신에 원금감 표현이 가능하다.
perspective projection에는 두가지 방법이 있다.
- view frustum
- FOV ( field of view )
- view frustum
- FOV ( field of view )
먼저 View Frustum Approach이다.
frustum은 한국말로 절두체로
머리쪽이 잘린 피라미드 형체이다.
clipped pyramid라 불리기도 한다.
이렇게 바라본다.
피라미드 모양대로라면
camera ~ far plane 까지일텐데 왜 저런 모양을 사용하느냐.
perspective든 parallel이든 near ~ far를 설정하는 이유는
어떤 물체가 너무 카메라에 가까이 있는 것도 일종의 에러라고 처리한다.
현실 세계의 예를 들면 카메라를 들고 찍고 있는데 손, 카메라 등이 camera ~ far plane까지 다 안찍히는 거 처럼.
또는 렌즈를 손가락으로 잡고있다던지 이런 경우는 옳지 않은 이미지가 된다.
또 너무 멀리 있는 경우는 너무 작아서 그리는게 의미가 없는 경우가 있다.
이래서 near - far 설정을 해야하고,
frustum 같은 view volume이 생기게 된다.

frustum( X min, X max, Y min, Y max, Z near, Z far);
( 왼쪽 위의 방향성을 보면 +z 가 아니라 -z이다)
원점에서 -z축을 바라보는 view frsutum 설정에는
near plane 기준으로 설정한다.
pararell과 다르게 x의 범위가 뒤로 갈수록 넒어진다.
그래서 기본적인 이 방법은 계산이 복잡해서 단순화할 필요가 있다.
위 방법에서 문제를 단순화하기 위해 대칭을 도입하여
Symmetric View Frustum이 나온다.
대칭 뷰 절두체이다.
이 방법은 view frustum이 z축에 대칭이라고 '가정'하는 것이다.
그렇게 되면 z축에 대칭이니까
Xmin = -Xmax, Ymin = -Ymax가 된다.

frustum( -X max, X max, -Y max, Y max, Z near, Z far);
위frustum을 화면에 출력하기 위해 두가지 과정이 있는데
첫번째 과정은 normalized frustum이다.
Znear 평면 기준으로 정사각형이 되는 대칭 피라미드로 mapping한다.
near plane은 Znear기준으로, far plane은 Zfar기준으로
frustum의 직사각형 평면을 정사각형으로 scaling한다.
이때 RHS 를 LHS로 뒤집어준다.

normalized에서 좌표계, z를 뒤집는 거는 순서는 상관없으나
현재는 이 과정에서 진행한다.
두번째 과정은 canonical view volume으로 변환한다.
첫번째 과정의 변환을 거치고 위에서 바라보고 있다고 가정해보자.

위 그림과 같이 frustum형태로 바라보고 있을 것이다.
이것을 정규 뷰 볼륨을 바꿔주려면
범위가 넓은 곳(ex, Zfar 의 x범위)은 더 많이 줄어들고,
좁은 곳(ex, Znear의 x범위)은 오히려 늘리거나 혹은 조금 줄어드는 scaling이될 것이다.

그럼 오른쪽 canoical 볼륨에서는
앞쪽은 적게 줄어들거나 혹은 늘어나서 크게 보이고
뒤쪽은 앞쪽보다 더 많이 줄어들어 작게 보이는 현상이 되어
원근감을 표현할 수 있다.

위와 같이 놓인 물체를 바라보려고한다.
함수를 사용해보자
glm::mat4 glm::frustumRH(GLfloat left, right, bottom, top, zNear, zFar);
* ortho 처럼 RH, LH를 제공하고 역시 z값들은 양수여야한다.
matView = glm::lookAtRH(
glm::vec3(0.0F, 0.0F, 1.0F),
glm::vec3(0.0F, 0.0F, 0.0F),
glm::vec3(0.0F, 1.0F, 0.0F)
);
// projection matrix
const GLfloat zoom = 0.5F;
matProj = glm::frustumRH(
-1.0F * zoom, +1.0F * zoom,
-1.0F * zoom, +1.0F * zoom,
+0.5F, +3.0F
);

원근감이 생겨 확실히 ortho 방식보다는 생동감(?)이 느껴진다.

오른쪽 위에서 내려다본 상황이다.
얼짱각도도 가능하게 되었다.
- view frustum
- FOV ( field of view )
두번째로 FOV이다.
FOV는 현재 카메라를 기준으로 대칭적으로 θ 만큼의 각도를 보겠다고 정의하는 것이다.
각도만 정의하면 되니까 좀 더 직관적이다.
하지만 각도를 가지고 다시 view frustum을 계산해야하므로
계산이 조금 더 많아진다.

어떻게 구하는지 보자.
***
tan(θ/2) = Ymax / (-Znear)
Ymax = -Znear * tan(θ/2)
비례 관계 : window width = W, hieght = H
W/H = Xmax / Ymax
Xmax = (W/H) * Ymax
Ymin, Xmin은 대칭으로 계산한다.
***
위와 같이 구할 수 있으므로 각도만 있으면 view frustum이 정의된다.
함수를 사용해보자
glm::mat4 glm::perspectiveRH(GL float fovy, aspect, zNear, zFar);
* fovy : the field of view angle, in the y direction. (radian)
aspect : the aspect ratio, width/height(화면 비율)
zNear, zFar 값은 역시 양수를 입력하면 된다.
앞서 진행했던 얼짱각도 코드에 perspective부분만 수정했다.
float fovy = ((GLfloat)M_PI / 180.0F) * 60.0F; // 60 degree
const GLfloat aspect = (GLfloat)WIN_W / (GLfloat)WIN_H;
matProj = glm::perspectiveRH(
fovy,
aspect,
+0.5F, +5.0F
);

해당 이미지는 fovy 가 60도이고

해당 fovy 는 80도이다.
각도가 클수록 더 많은 화면을 담는다는 뜻이니까
더 멀리서 보게되고,
각도가 작을수록 적은 화면을 담는게 되니까 가까이서 보게된다.
'컴터 > OpenGL' 카테고리의 다른 글
| [OpenGL] Phong Reflection Model (0) | 2023.06.10 |
|---|---|
| [OpenGL] Shading (0) | 2023.06.10 |
| [OpenGL] Look-At, Orthographic Projection (2) | 2023.06.10 |
| [OpenGL] VBO(Vertex Buffer Objects) (2) | 2023.06.10 |
| [OpenGL] Back face Culling (0) | 2023.06.10 |

