Animation by Idling
OpenGL 에서 이미지의 움직임과 동작을 주기 위한 방법으로 glutIdleFunc() 과 glutTimerFunc() callback 함수가 있다. 함수의 syntax 는 다음과 같다.
void glutIdleFunc( void (*func)(void) ); void glutTimerFunc( unsigned int millisec, void (*func)(int value), int value ); |
참고 Site: glutIdleFunc() http://www.opengl.org/resources/libraries/glut/spec3/node63.html
glutTimerFunc() http://www.opengl.org/resources/libraries/glut/spec3/node64.html
간단한 Animation 을 해보기 위해 다음의 함수를 main() 함수에 등록하고, idle() 함수 와 Timer() 함수를 만들어 보자.
추가 전역변수:
GLfloat speed = 1.0; GLboolean rot_status = TRUE; |
main() 함수:
. . // init GLUT and create Window .
// enter GLUT event processing cycle . . |
diaplay() 함수: 마지막의 glFlush(); 를 주석처리 해주고 대신
. . // glFlush(); // 주석처리 |
keyboard() 함수: 삼각형의 회전 속도의 변화를 주기위하여 다음을 더한다.
. . case ' ': // space bar . . |
idle() 함수:
void idle( void ) { zrot += speed * 0.025f; if (zrot > 360.0f) zrot -= 360.0f; glutPostRedisplay(); // tell GLUT that the display has changed } |
Timer() 함수:
void Timer( int value ) |
main() 에 있는 glutInitDisplayMode() 의 Mode 가 GLUT_SINGLE 에서 GLUT_DOUBLE 로 변화되었음을 볼 수 있다. 그리고 display() 함수의 마지막을 glFlush() 대신 glutSwapBuffers() 를 사용하였다. 이는 GLUT_DOUBLE 로 이중 Buffer 를 사용할여 앞, 뒤의 Buffer 를 서로 Swapping 하면서 교환하라는 명령을 주기 위함이다.
한 Buffer 에서 지웠다 그리기를 계속 반복하면 깜박거림이 발생하여 눈에 거슬리므로 두 개의 Buffer 를 교대로 사용한다. 초기화시에 GLUT_DOUBLE flag 를 전달하면 OpenGL 은 화면에 출력하는 Front Buffer 와 뒤에서 그리는 작업을 하는 Back Buffer, 두 개의 Buffer 를 준비한다. glutSwapBuffers() 에 의해 Front Buffer 와 Back Buffer 가 일시에 교체됨으로써 Back Bufff 에 미리 준비해 놓은 그림이 바로 나타난다. 순간적으로 교체되므로 깜박거림은 전혀 느낄 수 없다. 이 과정을 계속 반복하면 animation 이 되는 것이다. Buffer 를 교체하는 것 자체가 출력이므로 glFlush() 는 호출하지 않아도 상관없다. 위 에서 speed 는 전역변수로 rotation 속도를 조절하기 위한 변수이다. '<' 와 '>' key 로 크기를 조절하게 하였다.
idle() 함수는 단지 idling 시간만을 지정해 주고, glutPostRedisplay() 함수를 불러 display 할 내용을 변화시키도록 한다.
위 두개의 함수의 차이를 보면 Timer() 함수는 함수내에서 다시 재귀 (recursive) 형태로 자신을 다시 호출한다는 것이다. 이유는 glutTimerFunc() 은 지정된 시간후에 지정된 함수를 딱 한번 호출한다. 주기적으로 계속 호출하려면 callback 함수에서 자신을 다시 호출해야 한다. 지속적으로 호출되는 방식에 비해 약간 불편하지만 매 호출시마다 다음 주기를 가변적으로 결정할 수 있다는 면에서 활용성은 오히려 더 높다. 더 이상 Timer() 호출이 필요없으면 callback 을 재등록하지 않으면 된다. 함수의 동작형태는
millisec 후에 Timer() 함수를 호출하며 인수로 value를 전달한다. value는 Timer callback 으로 전달되어 작업 시간의 거리를 지시하는데, Timer 의 용도가 하나뿐이라면 아무 값이나 주어도 상관없다. callback 을 등록해 놓으면 millisec 후에 callback 함수가 호출된다. main() 에서는 다만 시동만 걸어줄 뿐이고 다음 타이머 호출 시점은 callback 함수가 자체적으로 결정할 수 있다.
System 이 초당 60 frame 을 refresh 한다고 가정하면, 가장 빠른 frame 율은 60 fps 이다. 따라서 1/60 초 이내에 frame 이 정리되고 다시 그려져야 부드럽게 움직이는 animation 이 된다. 그림이 복잡하여 한 frame 을 그리는데 1/45 초가 걸린다면, frame 율은 30 fps 가 될 것이다. 이 경우 graphic 은 1/30 - 1/45 = 1/90 초의 frame 당 시간 (sec per frame) 의 idle 이 요구된다. 만일 Back Buffer 에서 각각의 그림들이 그려지는 시간이 일정하지 않다면, 어떤 frame 은 시간을 좀더 많이 쓰고, 어떤 frame 은 시간을 적게 쓰게 되는 현상들이 발생할 것이다. 이러한 현상들에 의해 부드러운 Animation 진행과정이 방해 받게된다.
프로그램을 컴파일한 후 실행하면서, 앞 절, keyboard 프로그램 실행시 Test 해 보았던 것들을 해보면, 어떤 변화가 일어나는지를 볼 수 있을 것이다.
응용 Program:
무한정 움직이는 1개의 당구공을 생각해 보자. 당구공은 당구대의 벽면에 대한 입사각에 대하여 같은 반사각으로 튕겨진다. 이 원리를 적용하여 공의 위치를 속도에 따른 움직이는 거리를 계산하여 glTranslate() 함수를 사용, 공이 Table 내에서 계속 움직이도록 프로그램 한것이다.
우선 몇개의 전역변수를 정의 하였다.
#define angle -30.0 // launching angle
// set window size & image size coordinates & image view mode |
다음 display() 함수를 다음과 같이 수정한다.
. . // clear all color & depth buffers
/* Translate & rotate the image */
/* Draw circular ball */
sprintf( info, "x=%.1f, y=%.1f, launching angle=%.3f", xtr, ytr, angle );
glutSwapBuffers(); |
위에서 drawTable(); 함수의 내용을 지금 설명에는 조금 이른감이 있어 아래 Source Code 에 포함 되어있는것을 사용하기로 한다.
다음 idle() 함수 또는 Timer() 함수를 다음과 같이 작성한다.
void idle( void )
xtr += speed * cos( xdeg * PI/180.0 );
if (ytr >= ymax) ydeg = -ydeg;
glutPostRedisplay(); // tell GLUT that the display has changed |
ball 의 table 을 향한 입사각과 반사각에 대한 계산이므로 조금만 깊이 살펴보면 원리를 이해할 수 있을것이다.
그외 reshape(), keyboard() 및 special() 함수를 약간 수정하여 컴파일 후 실행배보면 재미있는 결과를 볼것이다.
실행할 때 선택사항은 다음과 같다.
'>' 와 '<' key - 공의 속도를 변화.
'arrow' keys - 공의 입사각의 변화
'r', 'g', 'b', 'w' key - 공의 색상 변화
'F11' & 'F11' - Toggle fullsize window
Source Code: 01_4 - animation.zip
01_4 - moving_ball.zip
'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글
1장 6절 - Mouse Motion Event (0) | 2013.01.22 |
---|---|
1장 5절 - Mouse Event (0) | 2013.01.22 |
1장 3절 - Keyboard Event (0) | 2013.01.20 |
1장 2절 - Resize OpenGL Window (0) | 2013.01.20 |
1장 1절 - Create a Simple OpenGL Window (0) | 2013.01.19 |