Viewport 나누어 사용하기

가끔 가다보면 화면을 둘로 나누어 사용하고 싶은 경우가 있다. MFC 같으면 Split window
를 만들어서 할 수도 있지만 귀차니즘이 발동하면 이런 것도 하기 싫어진다. 게다가 윈도가
분리되는 경우 렌더링 컨텍스트를 사용하고 나서 꼭 release 해 주어야 한다. ( 그렇다고
이 작업이 어려운 것은 아니다… .-_-;;;;)
여기서는 간단히 뷰포트를 나누어 멀티뷰나 화면 구석에 메뉴를 그리고 싶다거나 할 때 사
용할 수 있는 팁을 설명하도록 하겠다.
OpenGL에서 뷰포트 셋팅은 glViewport(x, y, w, h) 함수로 하게 된다. 명심할 것은 첫 번
째와 두 번째 인자는 뷰포트의 시작점을, 다음의 두 인자 w와 h는 글자 그대로 사용할 뷰
포트의 폭과 높이를 나타낸다. X와 y 값은 음수가 될 수도 있으며, 뷰포트의 좌측 하단 (오
픈지엘 윈도우의 좌측하단)에 오게 될 점의 좌표이다. 즉, 뷰포트의 시작점이 된다.
뷰포트를 설정한다고 하는 것은 쉽게 말해서 오픈지엘이 생성한 윈도우에서 “여기부터 저
기까지의 영역에만 그림을 그리겠다” 라고 말하는 것과 같다.

glViewport(0, 0, viewport1_x, viewport1_y) ; 첫 번째 뷰포트 설정
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glOrtho(……..) ; 클리핑 볼륨 설정.
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
(… 첫 번째에 들어갈 그림을 그려준다…….)
glViewport(…….) ; 두 번째 뷰포트 설정
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glOrtho(0,100,0,500,-50,50) ; 두번째 뷰포트의 클리핑 볼륨 설정.
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
(…..두 번째 뷰포트에 들어갈 그림을 그려준다….)

따라서 첫번째 뷰포트에 그려줄 루틴을 부르기 전에 첫 번째 뷰포트를 설정해주고, 두 번
째 그림을 그려주기 전에 두 번째 뷰포트를 그려주면 된다.
이 때, 각 뷰포트의 설정은 RenderScene() 함수 내부에서 해 주어야 한다.

예제 프로그램 실행 화면

그럼 첫번째 뷰포트는 일반적인 프로그램들의 예제를 보면 모두 glViewport(0,0,w,h)와 같
은 방법으로 사용하는데 두 번째는 어떻게 해야할까 ?
첫 번째 뷰포트가 w1, h1의 폭과 너비를 가진다면 두 번째 뷰포트의 시작점은 (w1, 0)
가 된다. 폭은 당연히 window_size_x – w1, 높이는 h1 으로 동일할 것이므로
glViewport(w1, 0, window_size_x – w1, h1) ;
와 같이 설정해 줄 수 있을 것이다.
실제로 나누어 쓰는 방법은 간단하기 그지 없지만 약간의 실수로 인해 화면이 표시가 안되
는 경우도 있다. 약간의 실수라 함은 다음과 같다.
일반적으로 뷰포트 및 클리핑 볼륨 설정은 프로그램 초기화시에 한 번 해주면 이후에는 다
시 할 필요가 없다. 그래서 만일 Init() 이라는 함수에서 첫 번째 뷰포트를 설정하고 다음에
RenderScene() 함수에서 두번째 뷰포트를 설정하게 되면 RenderScene()이 한 번 호출된
다음에는 뷰포트 및 클리핑 볼륨이 두번째 것으로 설정이 되어 있는 상태이므로 당연히 제
대로 된 화면이 나올리 만무하다.
(실제로 저도 이 실수 때문에 한참 동안 삽질만 했습니다. .. -_-;;;;;)

<Example source code>

예제 프로그램에서는 각 뷰포트의 폭과 높이를 변수로 정하여 윈도우가 리사이즈 되는 경우
뷰포트의 크기가 조절되도록 하였다. 윈도우를 리사이즈 하지 않고 정해진 크기에서만 사용
한다면 변수로 할당할 필요는 없다.

#include <windows.h>
#include <gl/gl.h>
#include <gl/glut.h>
float angle = 0 ;
// 아래의 변수들은 뷰포트의 폭을 저장할 변수들.
// 명심하자, 점의 좌표가 아니라 뷰포트의 가로 세로의 폭이다.
float viewport1_x ,viewport1_y ;
float viewport2_x, viewport2_y ;
// 렌더링 함수. 여기서 각 뷰포트 설정과 클리핑 볼륨 설정이 이루어진다.
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
////////////////////////////////////////////////////////////////
// 첫번째 뷰포트 설정. 일반적인 설정과 같다.
////////////////////////////////////////////////////////////////
glViewport(0, 0, viewport1_x, viewport1_y) ;
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glOrtho(-7,7,-7,7,-7,7) ; // 클리핑 볼륨 설정.
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
// 구와 좌표축을 그려준다. 역시 일반적인 부분.. -_-;;
glRotatef(angle, 0,1,0) ;
glBegin(GL_LINES) ;
glColor3f(1,0,0) ;
glVertex3f(0,0,0) ;
glVertex3f(10,0,0) ;
glColor3f(0,1,0) ;
glVertex3f(0,10,0) ;
glVertex3f(0,0,0) ;
glColor3f(0,0,1) ;
glVertex3f(0,0,10) ;
glVertex3f(0,0,0) ;
glEnd() ;
glColor3f(1,0,0) ;
glutSolidSphere(4,12,12) ;
///////////////////////////////////////
// 두번째 뷰포트의 설정을 한다.
// 첫번째와 거의 같다.
////////////////////////////////////////
glViewport(viewport1_x, 0, viewport2_x, viewport2_y) ;
// 첫번째 뷰포트가 끝난 곳에서 다음 뷰포트가 시작하기 때문에
// 처음 두개의 인자는 viewport1_x, 0 이 된다.
// 세 번째와 네 번째는 역시 폭과 높이를 입력.
// 나머지는 평범한 부분이다.
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glOrtho(0,100,0,500,-50,50) ; //클리핑 볼륨 설정.
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
glColor3f(1,2,0) ;
glBegin(GL_QUADS) ; // 클리핑 볼륨의 x-y 크기와 동일하게 그려주었으므로
glVertex2f(0,0) ; // xy 평면에 가득찬 사각형이 그려질 것이다.
glVertex2f(100,0) ;
glVertex2f(100,500) ;
glVertex2f(0,500) ;
glEnd() ;
glutSwapBuffers() ; // 버퍼를 비워준다.
}
void idle()
{
angle += 0.51 ;
if (angle >= 360)
angle = 0 ;
RenderScene() ;
}
void SetLighting()
{
glClearColor(0,0,0,0) ;
glEnable(GL_LIGHTING) ;
glEnable(GL_LIGHT0) ;
float specularLight[] = {0.7,0.7,0.7} ;
float diffuseLight[] = {0.7, 0.7, 0.7} ;
float ambientLight[] = {0.7, 0.7, 0.7} ;
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight) ;
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight) ;
glEnable(GL_COLOR_MATERIAL) ;
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) ;
glMaterialfv(GL_FRONT, GL_SPECULAR, specularLight) ;
glMaterialf(GL_FRONT, GL_SHININESS, 128) ;
}
void Reshape(int x, int y)
{
if (y==0)
y = 1 ;
viewport1_x = 0.8 * x ; // 첫 번째 뷰포트의 폭을 설정 윈도우 폭의 80%.
viewport1_y = y ; // 높이는 윈도우 높이와 같다.
viewport2_x = x - viewport1_x ; //두 번째 뷰포트의 폭은 나머지 부분이 된다.
viewport2_y = y ; // 역시 높이는 동일하다.
// 아래의 주석 처리된 부분은 보통 Reshape 함수 또는 MFC의 OnSize 에서
// 처리하는 부분이다. 그러나 지금은 RenderScene 에서 해주기 때문에
// 여기서는 윈도가 리사이즈 되는 경우 각 뷰포트의 폭을 비율에 맞게
// 재할당 하는 일만 해주면 된다.
/* glViewport(0,0,x,y) ;
glViewport(0,0,400,y) ;
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
glOrtho(-7,7,-7,7,-7,7) ;
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
*/
}
int main()
{
glutInitWindowSize(600,500) ;
glutInitDisplayMode(GLUT_RGB| GLUT_DOUBLE) ;
glutInitWindowPosition(50,50) ;
glutCreateWindow("LIGHTING TEST") ;
glutDisplayFunc(RenderScene) ;
glutReshapeFunc(Reshape) ;
glutIdleFunc(idle) ;
SetLighting() ;
glEnable(GL_DEPTH_TEST) ;
glutMainLoop() ;
return 0 ;
}

본 문서의 배포는 자유이며, 상업적인 목적으로 사용하는 것을 금합니다.
(상업적으로 사용할 꺼리나 있었더냐 …. ㅡㅡ;;)
작성자 : 샤이니레드 in 왕십리 OpenGL
e-mail : mail2lww@hanmail.net
날 짜 : 2003/01/09/목요일

'Programming > OpenGL, DirectX' 카테고리의 다른 글

ARToolKit 설치 및 실행하기  (0) 2011.03.28
DirextX 9.0 설정 in Visual Studio 6.0  (0) 2010.09.20
Posted by duki 두기

블로그 이미지
개인적인 잡다한 기록 공간입니다
duki 두기

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함