web

canvas 프레임(fps) 측정하기, 보장하기

blackbearwow 2024. 6. 4. 18:36

canvas를 이용해 웹 게임을 만들다 보면, 해당 게임이 몇 프레임으로 화면에 주사되고있는지 궁금해진다.

60fps모니터면 60fps를, 144fps 모니터면 144fps를 주사하여 부드러운 화면 주사율을 내보내고 싶다.

 

하지만 항상 canvas를 사용해 웹 게임을 만들 때마다 이상하게 60fps, 144fps에 못미치는 프레임인 것 같았다. 

막연하게 뭔가 렉걸리는 듯하다는 느낌만 받았었지만, 측정 방법도 모르고 그냥 그려려니 했다. 

그치만 sparebeat라는 웹 리듬게임을 해보니 굉장히 스무스하게 화면이 주사되는것이었다! 내가 만든 리듬게임은 뚝뚝 끊기는 느낌인데... 

느낌으로 판단하지 말고 이제 정확한 측정방법을 통해 몇 프레임인지 알아내고, 어떻게 해야 프레임을 보장할 수 있는지 알아보자.

 

프레임 측정하기

웹 브라우저의 프레임은 굉장히 측정하기 쉽다. 두가지 방법이 있다.

첫번째 방법은 개발자도구 더보기 - Run command - show rendering을 하고 

Frame Rendering Stats를 체크하면 

좌측 상단에 실시간으로 프레임을 볼 수 있다.

두번째 방법은 개발자도구의 performance탭을 이용하는것이다.

performance 녹화로 게임을 해보고

프레임들이 6.9~7.0ms라면 144fps가 되는것이다. 

 

하 지 만 

 

우리가 하고싶은것은 canvas의 fps측정이지 웹 브라우저의 fps측정이 아니다.

canvas에 그리는건 js의 코드에 의존하므로 어떠한 방식으로 canvas에 draw하고있는지 보자.

나의 코드에서는 setInterval을 이용해 화면을 주기적으로 갱신하고 있다. (아마도 여러분도 setInterval 또는 setTimeout을 이용하고 있으리라 예상한다.)

이 setInterval이 1초에 몇번 호출되느냐를 console.log를 이용해 확인하면 될것이다. 

Date.now() 또는 perfromance.now()를 사용해서 계산하면 된다.

fps측정을 위해 변수를 측정하고 

시간을 초기화 하고

프레임을 console.log로 찍는다. 

그러면 FPS가 167이 찍힌다. 

오잉? fps는 모니터의 144보다 높은 167이 찍히는데 뭐가 문제이길래 프레임이 끊기는가? 

문제는 setInterval, setTimeout에 있다. 위에 측정한 것은 그저 코드가 몇번 실행 되는지이다. oneFrame이 1초에 167번 실행되는데, draw()함수도 167번 실행되니 canvas는 167번 화면이 바뀐다고 생각할 수 있다. 하지만 이것은 브라우저의 repaint주기와 맞지 않는다면 애니메이션이 끊겨보일 수 있는 것이다. 

프레임 보장하기 - requestAnimationFrame

requestAnimationFrame을 사용하면 브라우저의 repaint주기와 일치하게 콜백을 실행하여 최적의 타이밍에 애니메이션이 렌더링된다. 

setInterval대신 requestAnimationFrame을 사용하고

oneFrame안에 requestAnimationFrame을 호출하여 다음 repaint주기에 콜백 함수를 호출하게 한다.

그러면 굉장히 스무스하고 끊기지 않는 화면이 될것이다!

개발자도구의 performance탭을 이용해 측정해보면, 매 프레임 마다 Animation Frame Fired가 일어나 oneFrame을 호출하는것을 볼 수 있다.