GLUT Tutorials

초당프레임수(FPS) 계산하기

우리가 만든 어플리케이션이 얼마의 빠르기로 실행되고 있는 것일까요? 종종 어플리케이션에 작은 변경을 가하지만 성능에는 어떻게 영향을 끼치는지 확실하게 알 수 없습니다. 즉, 그러한 변경사항들이 초당 장면이 그려지는 수인 FPS 에 얼만큼 영향을 줄까요? 이번 장에서는 FPS 를 계산하기 위해서 어떻게 GLUT 를 사용하는지 알아보겠습니다. 이번 장에서 알아보는 것은 성능을 측정하는 완벽한 방법이 아니라 하나의 참고사항일 뿐입니다.

GLUT 는 시스템의 여러 사항에 대해서 알 수 있도록 함수를 제공하는데, 이 함수로 알 수 있는 것 중 하나가 glutInit 함수가 호출되었을 때부터 누적된 밀리초입니다. 이 함수는 glutGet 으로 다음은 이 함수의 설명입니다.

int glutGet(GLenum state); 

인자 설명:
state - 알고 싶은 값의 이름입니다.

이 함수는 많은 용도로 사용될 수 있습니다. 예를 들면, 창의 좌표를 얻는다거나 또는 OpenGL 버퍼의 깊이를 얻는데 사용할 수 있습니다. 이번 장에서는 이 함수를 glutInit 함수가 호출되었을 때부터 누적된 밀리초를 얻는데 사용할 것입니다. 누적된 밀리초를 얻기 위해서는 state 인자에 GLUT_ELAPSED_TIME 을 넘겨줘야합니다.

int time;
time = glutGet(GLUT_ELAPSED_TIME);

그럼 지금부터 이 함수를 가지고 FPS 를 계산해 봅시다. 프레임속도는 매 프레임마다 다릅니다. 즉, 모든 프레임들이 각각 그려질 때마다 걸리는 시간이 다르다는 것입니다. 그 것은 운영체제에서 주어진 어플리이케이션 하나만 실행되고 있는 것이 아니기 때문입니다. 운영제체가 주어진 어플리케이션을 처리할 때에만 카메라가 움직일 것이고 이에 따라 렌더링되는 장면이 달라질 것입니다. 그래서 예제에서는 FPS 를 매 프레임마다 계산하지 않고 1 초 단위로 계산합니다.

FPS 를 계산하기 위해서 세 개의 변수 frame, time, timebase 를 선언하고 timebase 와 frame 변수는 0 으로 초기화합니다.

int frame=0, time, timebase=0;

이 변수의 용도를 알아보겠습니다.

  • frame - 마지막으로 FPS 를 계산한 후부터 현재까지의 프레임수입니다.
  • time - 현재의 밀리초입니다.
  • timebase - 마지막으로 FPS 를 계산했을 때의 밀리초입니다.

다음 코드는 idle(휴면) 함수로 등록된 함수에 적을 코드입니다. 프레임수를 계산합니다. 자세한 것은 코드 아래에 있는 설명을 참고하세요.

...
frame++;
time=glutGet(GLUT_ELAPSED_TIME);

if (time - timebase > 1000)
{
    fps = frame*1000.0/(time-timebase));
    timebase = time; 
    frame = 0;
}
...

frame 변수를 사용해서 프레임수를 증가하고 time 변수에 현재 시간을 담습니다. 그 다음 time 변수와 timebase 변수를 비교해서 1 초가 지났는지 검사합니다. 즉 time 변수에서 timebase 변수의 차가 1000 밀리초보다 크면 1 초가 지난 것입니다. 만약 1 초가 지나지 않았다면 FPS 를 계산하지 않고 1 초가 지났다면 FPS 를 계산합니다.

time 변수와 timebase 변수의 차는 마지막으로 FPS 를 계산한 후부터 경과된 밀리초단위의 시간을 알려줍니다. 밀리초단위의 경과된 시간으로 1000 을 나누면 초단위로 경과된 시간을 얻게됩니다. FPS 를 계산하기 위해서 남은 일은 초단위의 경과된 시간에 렌더링된 프레임수(마지막으로 FPS 를 계산한 후부터 누적되온 값)를 곱해주는 것입니다. 이 계산의 결과로 새로운 FPS 를 얻게 됩니다. 끝으로 timebase 변수를 현재 밀리초로 다시 설정하고 frame 변수는 0 으로 설정합니다.

어플리케이션이 처음 시작할 때는 timebase 값이 0 이기 때문에 1 초가 지난 다음에 처음으로 계산된 FPS 값을 볼 수 있습니다. 하지만 이 FPS 값은 오차가 큰데, 그 이유는 FPS 를 계산할 때 창이 초기화되는 시간까지 포함되어 있기 때문입니다. 조금만 테스트를 계속해 보면 이 값이 실제 FPS 보다 훨씬 작은 값이었단 걸 알 수 있습니다.

다음 코드처럼 해주면 FPS 를 창에 출력할 수 있습니다.

...
frame++;
time=glutGet(GLUT_ELAPSED_TIME);
if (time - timebase > 1000)
{
    sprintf(s,"FPS:%4.2f",
    frame*1000.0/(time-timebase));
    timebase = time; 
    frame = 0;
}

glColor3f(0.0f,1.0f,1.0f);
glPushMatrix();
    glLoadIdentity();
    setOrthographicProjection();
    renderBitmapString(30,35,(void *)font,s);
glPopMatrix();
resetPerspectiveProjection();
...

위의 코드 조각은 이전에 살펴본 '비트맵폰트와 직교투영' 장에서 다룬 것입니다.