본문 바로가기

Info

Info - GLUT

1. 시작하면서
이 문서는 GLUT에 대한 이해를 돕기 위해 작성되었으며 각 설명에 대한 참고 문헌은 다음과 같습니다.

+ The OpenGL Utility Toolkit Programming Interface Specification – version 3
 이 문서는 http://reality.sgi.com/mjk/spec3/spec3.html에 HTML형태로 참조할 수 있습니다
+ OpenGL Programming Guide 2nd Edition – (Appendix D) Basics of GLUT

이 내용보다 더 자세한 내용(예를 들어 GLUT으로 Full-Screen을 구현하고자 하시는 분 들 등등)을 원하시는 분들은http://www.opengl.org/Documentation/GLUT.html을 방문하셔서 참고자료를 읽어보시면 됩니다.

앞으로 설명하는 방향은 C문법을 알고 있고, DirectX등의 그래픽 관련 API를 전혀 써보지 않은 것으로 간주하고 설명하도록 하겠습니다. Windows API에 대한 프로그램 경험이 있으신 분은 그냥 가볍게 읽어주셔도 좋습니다. ^^;

많은 부분이 부족하지만 나름대로 많은 것을 전하기 위해 노력했습니다. 학업에 도움되시길 빌겠습니다.

2. 정리에 앞서서
먼저, GLUT에서 각 Event(마우스 입력, 키보드 입력, 화면갱신등등)처리는 모두 Callback Function이란 형태로 처리한다는 것을 염두에 두셔야 합니다. Callback Function이란 C에서 설명하는 Function Pointer를 활용하는 방법으로, 실제로 일정형태의 함수를 Pointer형태로 선언해놓은 후 사용자가 이를 지정하지 않으면(즉, Pointer가 NULL이면) 실행하지 않거나 미리 지정해놓은 Routine을 실행시켜주는 형태의 프로그램 방식을 말합니다. 예를 들면, 
void buttonProc(int button, int state, int x, int y) {
if (button != GLUT_LEFT_BUTTON)
return;
switch (state) {
case GLUT_DOWN: …
case GLUT_UP: …
break;
}
}
사용자는 위와 같은 형태로 함수를 만들어주면 됩니다. 위의 예는 마우스 제어부분의 한 형태를 보여주는 것인데, ButtonProc 와 같이 함수명은 아무렇게나 정해주어도 상관 없지만, 작성자가 지켜주어야 할 부분은 그 뒤에 따라오는 함수인자의 형태를 맞추어주어야 합니다. 이 Callback 함수를 GLUT으로 하여금 사용하도록 등록하는 함수가 glutMouseFunc인데 선언을 잠깐 엿보면,

void glutMouseFunc(void(*func)(int button, int state, int x, int y))

와 같은데, 위에서 보여준 예제의 함수와 인자 형태가 같은 것을 알 수 있습니다.
위의 함수를 GLUT의 Mouse제어 Event함수로 등록하려면,

glutMouseFunc(buttonProc);

이렇게 간단히 써주면 됩니다. 물론 Win32 API에 익숙하신 분들은 (특히 C로) 위 과정이 번거롭게 보일 수도 있습니다만, 실제로 고칠 부분이 직접 작성한 작성자의 함수들로 한정되는 장점이 있습니다. 원래 Windows 프로그래밍이 상당히 외울 것 많고 번거롭습니다. ^^;

여기서는 GLUT_DOWN등의 glut.h에 정의된 macro 선언 등은 생략하도록 하겠습니다. 모든 선언들이 직관적으로 되어있고, (예: GLUT_DOWN – 커서키 중 아래 화살표키 입력) glut.h를 한번 정도 주의 깊게 읽어보시면 어느 정도 알 수 있기 때문에 여기서는 가급적 설명을 생략하고, GLUT의 주요 함수들에 대해서만 설명하도록 하겠습니다.

3. Visual C++상의 설정방법
우선 GLUT DLL들과 Header File, Library File등은 Windows에는 기본적으로 설치되어있지 않기 때문에 따로 설치해주어야만 합니다. 이 설치화일들은 http://reality.sgi.com/mjk/glut3/glutdlls37beta.zip에서 Download 받으실 수 있습니다.

우선 받은 파일의 압축내용을 풀어보면, 다음과 같은 내용의 파일들이 있습니다. 각 파일을 각 설명에 맞추어 복사합니다.

glut.h : Visual C++의 설치디렉토리의 /include/gl 디렉토리에 복사합니다.
glut.lib 및 glut32.lib : Visual C++의 설치디렉토리의 /lib 디렉토리에 복사합니다.
glut.dll 및 glut32.dll : windows의 system 디렉토리에 복사합니다.

더 쉽게 설명하자면, Windows의 find기능으로 gl.h, opengl32.dll, gl.lib의 위치를 각각 찾아서 해당 디렉토리에 각각 copy하면 정확합니다. 현재 사용하는 Windows의 버전이 98 혹은 NT라면 ~32로 끝나는 것만 복사하면 됩니다. (나머지는 windows 3.1용입니다.)

복사작업이 끝나면 이제 GLUT를 사용할 수 있습니다. 우선 항상 명심하여야 할 것이 3가지 있습니다.
1. Visual C++상에서 신규 프로젝트를 만들 때, 항상 ‘Win32 Console Application’템플릿을 선택하여 생성하여야합니다.
2. 항상 ProjectSettings메뉴를 열어 Link항목에 Object/Library Modules항목에 OpenGL32.lib, glu32.lib, glut32.lib들이 추가되어 있는지 확인하여 주십시오. 없으면 적어주셔야합니다. (,(컴마)문자는 쓰실 필요없습니다. 이전에 어떤 분이 쓰셔서 Link Error를 내시더군요. ^^)
3. 이제부터 항상 GLUT와 관련된 C Source 파일안 상단에 
#include <gl gl.h="" style="padding: 0px; margin: 0px; color: rgb(51, 51, 51); font-family: Gulim; font-size: 13px; line-height: 22px; background-color: rgb(255, 255, 255);">
#include <gl glut.h="" style="padding: 0px; margin: 0px;">
가 들어있는지 확인하여주십시오. 없으면 추가시켜 주십시오.

보통 Link Error가 발생하는 이유 중 대표적인 것 하나가 2번을 빼먹기 때문입니다. 설령 Unix예제를 접하게 된다 할지라도 Make파일을 잘 읽어보시고 신규 프로젝트를 만든 후 위 과정을 확인하면서 소스화일과 header파일을 등록하면 무리없이 Compile하실 수 있습니다.

4. Window의 생성과 초기화
OpenGL은 기본적으로 주어진 Windows영역의 모든 그리는 권한을 다 가진 것으로 가정합니다. 하지만, 기본적인 개념정도는 이해하고 있어야 OpenGL의 초기화에 대한 이해를 할 수 있습니다. (Event와 Message가 뭐지하면 안됩니다. ^^;) 구체적인 설명은 따로 Visual C++관련 서적을 구입하셔서 공부를 해주시기 바랍니다. 

밑에 나열한 것은 Windows의 생성과 초기화에 쓰이는 GLUT함수들입니다.
void glutInit(int argc, char **argv) : (Unix운영체계에서만 쓰입니다) 어떤 다른 GLUT함수를 부르기 전에 반드시 가장 먼저 호출해야하는 함수입니다. 즉, GLUT Library의 내부설정등을 초기화합니다. 인자의 argc, argv는 main()함수의 인자를 그대로 쓰시면 됩니다.
void glutInitDisplayMode(unsigned int mode) : 컴퓨터 디스플레이의 종류를 결정합니다. 예를 들면, RGBA Color Model을 사용할 것인지, Color-Indexed Color Model을 쓸 것 인지, Single-Buffer로 화면을 그릴 것인지, Dubble-Buffer로 화면을 그릴 것인지 등등을 지정합니다. 반드시 해당 지정을 대표하는 Macro들을 모두 or(|) 연산자로 묶어 입력하셔야 합니다. 아래는 하나의 예제 입니다.

GLUT_RGBA | GLUT_DOUBLE : RGBA 컬러 모델에 Double-buffer를 사용합니다.

(앞으로의 강의 예제들도 위 사항을 기본으로 하겠습니다.) 

void glutInitWindowSize(int width, int height) : 나타날 Window의 가로세로 크기를 지정합니다.
void glutInitWindowPosition(int x, int y) : 나타날 Window의 초기 위치를 지정합니다.
void glutCreateWindow(char *name) : 드디어 윈도우 생성함수 입니다. ^^; 위의 설정 함수들을 먼저 구동 시킨 후 이 함수를 실행하면 바로 윈도우를 띄우겠다는 신호를 GLUT에 보내는 역할을 합니다. name변수는 생성될 윈도우의 title에 해당하는 문자열을 넣으시면 됩니다. (이 함수 직후에 나타나지는 않으며, 후에 설명할 glutMainLoop()함수를 구동하면서 윈도우가 화면에 표시되게 됩니다.)

5. Window와 사용자 입력 Event들의 조작
다음에 설명할 함수들과 밀접한 관련이 있는 Windows API용어가 있습니다. “Message Loop”라는 것인데, Window라는 운영체계나 기타 운영체계에서 많이 사용되는 방식 중 하나로서 각 프로그램을 하나의 무한 Loop로 보고 계속 특정 Event가 발생할 때 그에 해당되는 Message를 프로그램과 타 프로그램, 운영체계간에 주고 받는 내부구조를 얘기합니다. 이때 각 프로그램들은 Message처리부분을 하나의 Loop구조로 표현하기 때문에 위와 같은 용어로 지칭합니다. 

각 Message들은 특정 용도로 묶어서 분류하는데, 예를 들어 마우스 입력을 나타내는 Message들, Window관리에 해당되는 Message들 등으로 분류가 되어있습니다. GLUT는 기본적인 Message Loop에 해당되는 내용들은 미리 코딩되어 숨겨놓은 상태여서 작성자는 이에 대한 고려를 할 필요는 없습니다만, 각 묶여진 Message들의 처리는 각각 기술해 주어야 합니다. (GLUT는 Win32 API로 직접 코딩하는 것보다는 복잡하진 않습니다. 궁금하신 분은 OpenGL Superbible의 4장 wiggle에 대한 내용을 읽어보시면 됩니다. Superbible의 전반적인 예제가 C기반의 Win32 API를 기준으로 코딩되어있고, 책도 그렇게 진도를 나가고 있습니다. 책에는 일부분만 설명되어있지만 부록 CD의 내용을 직접 보시면 책의 내용을 찾기 힘들 정도로 코드가 긴 것을 알 수 있습니다.)

물론 지금 나열할 함수들은 각 Message그룹들을 대표하는 역할을 합니다. 앞에서 말한 Callback함수를 인자로 가지고 있으며, 각각의 Callback함수는 작성자가 직접 작성해주어야 합니다.
void glutDisplayFunc(void (*func)(void)) : 화면에 그릴 내용들을 기술한 Callback함수를 등록합니다. (Win32 API의 실전 Message를 예를 들자면 WM_PAINT정도에 해당하는 부분입니다.) 타 등록 함수와는 달리 이것은 꼭 작성해야 합니다.
void glutReshapeFunc(void (*func)(int width, int height)) : Window의 크기를 변형시켰을 때 실행할 내용을 담은 Callback함수를 등록합니다.
void glutKeyboardFunc(void (*func)(unsigned int key, int x, int y)) : Window상에서 들어오는 키보드에 대한 응답을 기술한 Callback함수를 등록합니다.
void glutMouseFunc(void (*func)(int button, int state, int x, int y)) : Window상에서 Mouse의 동작에 대한 실행내용을 기술한 Callback함수를 등록합니다.
void glutMotionFunc(void (*func)(int x, int y)) : Window상에서 Mouse버튼을 하나이상 누른 상태로 이동하는 중일 때 동작할 내용을 기술한 Callback함수를 등록합니다.

이건 예외입니다. (Callback등록함수가 아닙니다.)
void glutPostRedisplay(void) : 이것은 Window내의 내용을 다시 한번 그리라는 신호를 GLUT에 보냅니다. Loop가 한바퀴 실행되고 다음 차례에 화면을 갱신하게 됩니다. 흐름상으로 바로 화면을 갱신해야 할 필요가 있을 때 사용합니다.

6. 3D Object들의 초기화 및 Drawing
다음 함수들은 말그대로 윈도우 중앙에 정사면체, 구, 도넛형 물체, 원뿔, 정10면체 등등을 그려줍니다. 물론 이 함수들을 사용하면 기본 물체는 쉽게 화면상에 나타낼 수 있지만, 교재로 나갈 내용들은 불행하게도(?) 저급적인 부분에서 다루도록 되어있으므로 강의 중에는 거의 쓰이지 않을 함수들로 간주하시면 됩니다. (실전에서도 거의 쓰이지 않습니다.
glutWireSphere, glutSolidSphere, glutWireCube, glutSolidCube, glutWireTorus, glutSolidTorus …

7. Background Process 조작 
Windows 프로그래밍 참고서들을 보면 Idle 상태에 대해서 설명한 부분이 있습니다. 
말그대로 프로그램상에서 잠시 Event를 기다리며 휴식하는 상태가 있는데, 이때 내부적으로 Code를 집어넣어 마치 background로 동작하는 효과를 나타내게 할 수 있습니다. GLUT에서는 다음 함수를 사용해서 Idle상태때 동작하는 Callback함수를 등록할 수 있습니다.
glutIdleFunc(void (*func)(void))

8. 자, 이제 프로그램 실행! ^^;
이제 모든 GLUT의 설정이 끝났으면 main()함수내의 끝부분에 다음 함수를 적어줍니다. (여태껏 적었던 많은 Callback들을 이제 동작시키는 최후의 함수입니다.)
glutMainLoop();

9. 예제 프로그램 : GLUTCore.c

#define APP_NAME "OpenGL실습과정예제 : GLCore"
#include <stdio.h style="padding: 0px; margin: 0px;">
#include <stdlib.h style="padding: 0px; margin: 0px;">
#include <gl glut.h="" style="padding: 0px; margin: 0px;">

/*-전역변수선언부-*/
int WindowWidth = 640; /* 생성될 주 윈도우 폭 */
int WindowHeight = 480; /* 생성될 주 윈도우 높이 */
/*-glutDisplay
기능 : glutDisplayFunc 함수의 인자로 들어갈 Callback Function 정의
*/
void glutDisplay (void)
{
/* 만일 윈도우가 닫혀있거나 비정상적으로 작아졌을때는 그리지 않는다. */
if (!WindowHeight) return;
/* 화면을 지운다 */
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glTranslatef (0, 0, -20); /* 눈 즉 시점의 위치를 지정합니다. */
/* 그리는 색깔을 검정색으로 맞춘다. */
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
glutWireCube(10.0f);
glutSwapBuffers();
}

/*-glutResize
기능 : glutReshapeFunc() 함수의 인자로 들어갈 Callback Function 정의
*/
void glutResize (int w, int h)

WindowWidth = w;
WindowHeight = h;
glViewport (0, 0, WindowWidth, WindowHeight);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (90, WindowWidth / WindowHeight, 1, 9999);
glutPostRedisplay ();
}

/*-glutKeyboard
기능 : glutKeyboardFunc() 함수의 인자로 들어갈 Callback Function 정의
*/
void glutKeyboard (unsigned char key, int x, int y)
{
switch ( key )
{
/* Q를 누르면 프로그램이 종료하게 되어있습니다. */
case 27:
case 'q':
case 'Q':
exit (1);
break;
}
glutPostRedisplay ();
}
/*-main 함수 정의
*/
void main(void)
{
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (WindowWidth, WindowHeight);
glutCreateWindow (APP_NAME);
glutKeyboardFunc (glutKeyboard);
glutDisplayFunc (glutDisplay);
glutReshapeFunc (glutResize);
/*-초기화 부분*/
glEnable (GL_DEPTH_TEST);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
/*----------*/
glutMainLoop();
}</gl></stdlib.h></stdio.h></gl></gl>

'Info' 카테고리의 다른 글

Info - ASCII code table  (0) 2016.08.31
Info - 이동통신관련 좋은 블로그  (0) 2016.08.31
Info - 리눅스 패키지 관련 사이트  (0) 2016.08.31
Info - 북마크 백업  (0) 2016.08.31
Info - IPSec  (0) 2016.08.31