Canonical View Volume이 정의되는 좌표계
x, y, z: [-1, +1], [-1, +1], [-1, +1]
Window 설정용 integer 좌표계
window size =
마지막 출력을 NDC를 거쳐 WC로 보내는 이유는 정규화된 구간에 그려진 물체를 모든 윈도우 사이즈에 대응 가능하기 때문
정확한 크기의 렌더링 후 해상도에 따라 매핑관계만 정의해주면 됨
NDC의 좌표를 대응되는 WC의 좌표로 계산이 필요함
마지막에 0.0을 더해주는 이유는 뷰포트 설정 시 다른 값이 올 수도 있기 때문, 윈도우 전체에 출력할 땐 무시해도 됨
Viewport: OpenGL 출력 영역
보통은 window 전체를 쓰지만,
window 내의 일부 직사각형 영역으로 설정 가능
Canonical View Volume의 좌표들을 window의 뷰포트 내의 좌표로 변환

z-buffer의 일부 구간만 사용하는 것도 가능
void drawFunc(void) {
...
// clear in gray color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 뷰포트 세팅 1
glViewport(0, 0, WIN_W, WIN_H);
...
glDrawArrays(GL_TRIANGLES, 0, 18); // 피라미드
...
glDrawArrays(GL_TRIANGLES, 0, 36); // 큐브
// 미니맵 위치 및 크기 설정
GLint map_x = (GLint)(WIN_W * 0.70F);
GLint map_y = (GLint)(WIN_H * 0.05F);
GLsizei map_w = (GLsizei)(WIN_W * 0.25F);
GLsizei map_h = (GLsizei)(WIN_H * 0.25F);
// 뷰포트 세팅 2
glViewport(map_x, map_y, map_w, map_h);
glDrawArrays(GL_TRIANGLES, 0, 36); // 큐브
...
}
우측 하단에 미니맵으로 큐브가 그려지는 것을 확인
Viewport: NDC 전체 영역이 mapping 되는 직사각형 영역 설정
Scissor Box: window 좌표계 내에서 OpenGL 출력이 허용되는 직사각형 영역 설정
Viewport와 Scissor Box가 서로 겹치는 영역에 화면이 업데이트
void drawFunc(GLFWwindow* window) {
...
// 윈도우 사이즈를 가져옴
glClearColor(0.5F, 0.5F, 0.5F, 1.0F);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int win_w, win_h;
// Screen Coordinates 사용 (원점이 좌상단)
glfwGetWindowSize(window, &win_w, &win_h);
glViewport(0, 0, win_w, win_h);
...
GLint map_x = (GLint)(win_w * 0.70F);
GLint map_y = (GLint)(win_h * 0.05F);
GLsizei map_w = (GLsizei)(win_w * 0.25F);
GLsizei map_h = (GLsizei)(win_h * 0.25F);
glViewport(map_x, map_y, map_w, map_h);
// Scissor Box 활성화
glEnable(GL_SCISSOR_TEST);
glScissor(map_x, map_y, map_w, map_h);
glClearColor(0.5F, 0.5F, 1.0F, 1.0F);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 36); // 36 vertices
// Scissor Box 비활성화
glScissor(0, 0, win_w, win_h);
glDisable(GL_SCISSOR_TEST);
...
}
Scissor Box가 적용된 미니맵 영역만 glClear()가 적용되어 배경색이 바뀐 것을 확인
Viewport의 Aspect Ratio(종횡비)는 유지하고 윈도우에 여백을 표현
aspect ratio = width / height
void drawFunc(GLFWwindow* window) {
...
int win_w, win_h;
glfwGetWindowSize(window, &win_w, &win_h);
GLint vp_x, vp_y;
GLsizei vp_w, vp_h;
// aspect ratio: 320 / 240 = 1.333
GLfloat aspect = (GLfloat)WIN_W / (GLfloat)WIN_H;
// vp_w : vp_h = WIN_W : WIN_H
if (win_w < win_h * aspect) { // portrait case
vp_w = win_w;
vp_h = (GLsizei)(win_w / aspect);
vp_x = 0;
vp_y = (win_h - vp_h) / 2;
}
else { // landscape case
vp_h = win_h;
vp_w = (GLsizei)(win_h * aspect);
vp_y = 0;
vp_x = (win_w - vp_w) / 2;
}
// 종횡비대로 뷰포트 설정
glViewport(vp_x, vp_y, vp_w, vp_h);
glEnable(GL_SCISSOR_TEST);
glScissor(vp_x, vp_y, vp_w, vp_h);
glClearColor(0.6F, 0.6F, 0.6F, 1.0F);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glScissor(0, 0, win_w, win_h); // turn-off scissor test, double check
glDisable(GL_SCISSOR_TEST);
...
// 미니맵도 위치를 이동시킴
GLint map_x = vp_x + (GLint)(vp_w * 0.70F);
GLint map_y = vp_y + (GLint)(vp_h * 0.05F);
GLsizei map_w = (GLsizei)(vp_w * 0.25F);
GLsizei map_h = (GLsizei)(vp_h * 0.25F);
glViewport(map_x, map_y, map_w, map_h);
glEnable(GL_SCISSOR_TEST);
glScissor(map_x, map_y, map_w, map_h);
glClearColor(0.5F, 0.5F, 1.0F, 1.0F);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 36); // 36 vertices
glScissor(0, 0, win_w, win_h);
glDisable(GL_SCISSOR_TEST);
...
}
윈도우 사이즈를 변경시켜도 뷰포트의 종횡비가 유지되어 중앙에 위치하는 것을 확인