프로그래밍/C/C++2010.03.27 12:53


#include 

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
GLdouble aspectW;
GLdouble aspectH;
static int rotate = 0;
void reshape(int width, int height){
	aspectW = (GLdouble)width / (GLdouble)WINDOW_WIDTH;
	aspectH = (GLdouble)height / (GLdouble)WINDOW_HEIGHT;
}void DrawScene()
{	
	glColor3f(1.0, 1.0, 1.0);
	glPushMatrix();		
	glRotatef((GLfloat)rotate, 0.0, 1.0, 0.0);	
	glTranslatef(0.0, 0.0, 0.0);	
	glutWireTeapot(1.0);
	glPopMatrix();
}
void display()
{	
	glClear (GL_COLOR_BUFFER_BIT);
	glColor3f (1.0, 1.0, 1.0);
	glViewport(0, 0, WINDOW_WIDTH/2, WINDOW_HEIGHT/2);	
	// 좌하	glPushMatrix();	
	gluLookAt(0.0, 0.0, 1.0,   0.0, 0.0, 0.0,   0.0, 1.0, 0.0);
	DrawScene();
	glPopMatrix();
	glViewport(WINDOW_WIDTH/2, 0, WINDOW_WIDTH/2, WINDOW_HEIGHT/2);		
	// 우하	glPushMatrix();	
	gluLookAt(1.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 1.0, 0.0);	
	DrawScene();	
	glPopMatrix();
	glViewport(0, WINDOW_HEIGHT/2, WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
	// 좌상	glPushMatrix();	
	gluLookAt(0.0, 1.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 1.0);	
	DrawScene();	
	glPopMatrix();
	glViewport(WINDOW_WIDTH/2, WINDOW_HEIGHT/2, WINDOW_WIDTH/2, WINDOW_HEIGHT/2);	
	// 우상	glMatrixMode(GL_PROJECTION);
	glPushMatrix();	
	glLoadIdentity();		
	gluPerspective(30, 1.0, 8.0, 100.0);		
	glMatrixMode(GL_MODELVIEW);		
	glPushMatrix();		
	gluLookAt(6.0, 6.0, 6.0,   0.0, 0.0, 0.0,   0.0, 1.0, 0.0);	
	DrawScene();	
	glPopMatrix();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();	
	glFlush();
	glutSwapBuffers();
}
void Init() {
	glClearColor (0.0, 0.0, 0.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();	
	glOrtho(-2.0, 2.0, -2.0, 2.0, 0.5, 5.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
void idle(){
	rotate++;
	glutPostRedisplay();
}

int main(int argc, char** argv){
	glutInit(&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);	
	glutInitWindowSize (WINDOW_WIDTH, WINDOW_HEIGHT);
	glutInitWindowPosition (100, 100);
	glutCreateWindow ("4Viewport - teapot");
	Init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);	
	glutIdleFunc(idle);
	glutMainLoop();
	return 0;
}


 뷰포트란 윈도우 안에 설정한 작은 창을 말한다. MFC에서 자식윈도우를 생각해도 좋으나 3DMAX나 기타 툴을 보면 화면이 분활되어 각각 다른 시점으로 물체를 보는걸 본 적이 있을것이다.


void glViewport(GLint X, GLint Y, GLsizei width, GLsizei height); // 31 line


 앞의 X, Y는 glViewport를 그려주는 왼쪽 아래 좌표를 말하며, 뒤의 width, height는 뷰포트의 크기를 지정해준다.

 GLUT함수는 화면 좌표계의 기준을 좌상단으로 잡지만 GL함수는 윈도우의 좌하단을 (0,0)으로 기준한다는 점에 유의해야한다.


 콜백 함수는 윈도우에 어떤 동작을 할때 일어난다. 예를 들어 디스플레이 콜백 함수는


1. 처음 윈도우를 열때
2. 윈도위 위치를 옮길때
3. 윈도우 크기를 조절할 때
4. 앞 윈도우에 가려저 안보이던 뒤 윈도우가 활성화되어 앞으로 드러날 때
5. glutPostRedisplay(); 함수에 의해 이벤트 큐에 Flag이 게시될 


 일때 자동으로 호출한다. 그 외 키보드 콜백, 마우스 콜백, 메뉴 콜백, 아이들Idle 콜백 등이 있다.


 다른 여러가지는 이름을 들으면 대충 어떤건지 머리속에 떠오르지만 아이들Idle 콜백은 좀 애매할것이다. glutMainLoop() 을 이용해 프로그램을 무한 이벤트 루프로 가져간다.


void glutIdleFunc(idle); // 95 line


 idle 함수 안에선 rotate변수를 계속 증가시켰고, 이는 glRotatef((GLfloat)rotate, 0.0, 1.0, 0.0); 에서 증가된 rotate값 덕분에 회전 할 수 있게 된다. 참고로,


void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); // 20 line


에서 y가 1이기 때문에 y축을 기준으로 회전하고 있다.


 여기 까지 하면 회전하는 주전자를 4개의 시점으로 볼 수 있을것이다. 그런데 모델의 애니메이션에 가장 중요한 한 가지가 빠져 있다. 바로 버퍼이다. 쉽게 말해서 그림을 그려준후 이를 화면에 뿌리는데 두 작업간의 속도에 차이가 나서 화면에 잔상이 남게 된다.  다시 말해서 GPU가 프레임 버퍼에 쓰는 작업은 비디오 컨트롤러가 프레임 버퍼를 읽어가는 속도에 비해 훨씬 느리다. 화면에 이미지를 뿌릴때는 왼쪽 위부터 한줄씩 채워가기 때문에 애니메이션이 마치 물결치는 모습으로 보이게 될 것이다.


 이를 해결하기 위해 더블 버퍼를 사용한다. 즉, 버퍼를 두개 만들어서 A버퍼가 화면을 뿌릴때 다음 장면을 B버퍼에 저장하는 것이다.


void glutInitDisplayMode(unsigned int mode); // 88 line
void glutSwapBuffers(void); // 63 line


 전자의 함수에서 (GLUT_SINGLE | ..) 로 되 있는것을, (GLUT_DOUBLE | ..) 로 바꾸어 주면 되고 후자의 함수는 glFlush(); 이후에 사용하면 된다.

Posted by Yria

댓글을 달아 주세요