先列举几个关于渲染帧率的文章:
1. http://ruinerlee.blog.163.com/blog/static/215611167201292990203/
2. http://blog.codingnow.com/2008/04/fps.html
3. http://blog.youkuaiyun.com/strongcoding/article/details/6252313
#include
#include
#pragma comment(lib,"winmm.lib")
int main()
{
DWORD currentTime;
DWORD lastTime = timeGetTime();
DWORD frameCounter = 0;
DWORD frameTime = 0;
DWORD elapsedTime = 0;
while(1)
{
currentTime = timeGetTime();
frameTime += (currentTime - lastTime);
elapsedTime += (currentTime - lastTime);
lastTime = currentTime;
if(frameTime > 16) // 1000/60 ,渲染一次需要的时间
{
frameCounter++;
frameTime -= 16; //因为有可能大于16,直接置零会导致少算
}
if(elapsedTime >= 1000)
{
std::cout << frameCounter << std::endl;
frameCounter = 0;
elapsedTime -= 1000;
}
}
return 0;
}
解释:
渲染帧速率,即每秒渲染的帧数。上面的程序设置固定的帧速率为60,之所以使用frameTime累积时间值,是因为电脑中的程序是CPU切换执行的,而这种切换速度是非常快的,只有累积的时间大于渲染一帧需要的时间时才会累加frameCounter。elapsedTime 变量是累积程序运行的时间,当程序运行的时间大于或者等于1000ms也就是1s的时候,打印一下FPS。
下面是2个案例:
#include "Timing.h"
#include <SDL/SDL.h>
namespace Tengine {
FpsLimiter::FpsLimiter() {
}
void FpsLimiter::init(float maxFPS) {
setMaxFPS(maxFPS);
}
void FpsLimiter::setMaxFPS(float maxFPS) {
_maxFPS = maxFPS;
}
void FpsLimiter::begin() {
_startTicks = SDL_GetTicks();
}
float FpsLimiter::end() {
calculateFPS();
float frameTicks = SDL_GetTicks() - _startTicks;
// Limit the FPS to the max FPS
if (1000.0f / _maxFPS > frameTicks) {
SDL_Delay(1000.0f / _maxFPS - frameTicks);
}
return _fps;
}
void FpsLimiter::calculateFPS() {
static const int NUM_SAMPLES = 10;
static float frameTimes[NUM_SAMPLES];
static int currentFrame = 0;
static float prevTicks = SDL_GetTicks();
float currentTicks;
currentTicks = SDL_GetTicks();
_frameTime = currentTicks - prevTicks;
frameTimes[currentFrame % NUM_SAMPLES] = _frameTime;
prevTicks = currentTicks;
int count;
currentFrame++;
if (currentFrame < NUM_SAMPLES)
{
count = currentFrame;
}
else
{
count = NUM_SAMPLES;
}
float frameTimeAverage = 0;
for (int i = 0; i < count; i++)
{
frameTimeAverage += frameTimes[i];
}
frameTimeAverage /= count;
if (frameTimeAverage > 0)
{
_fps = 1000.0f / frameTimeAverage;
}
else {
_fps = 60.0f;
}
}
}
另一个示例:
package com.base.engine;
import java.io.File;
import java.net.URI;
import java.util.zip.ZipFile;
public class MainComponent {
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static final String TITLE = "3D Engine";
private static final double FRAME_CAP = 60.00;//每秒游戏刷新的次数,但是我不可能每秒画5000次。
private boolean isRunning;
private Game game;
public MainComponent ()
{
isRunning = false;
game = new Game();
}
public void start(){
if(isRunning)
return;
run();
}
public void stop(){
if(!isRunning)
return;
isRunning =false;
}
//要使Game在固定的时间单元内刷新一次。这样帧率对游戏的场景就没有影响了。如:我要让我的ball在固定的时间内移动一次,而不管在这固定的时间内实际画了多少在屏幕上。
private void run(){
isRunning = true;
int frames = 0;
long frameCounter = 0;
//一帧需要的时间
final double frameTime = 1.0 / FRAME_CAP;
long lastTime = Time.getTime();
double unprocessedTime = 0;
while(isRunning){
boolean render = false;
long startTime = Time.getTime();
long passedTime = startTime - lastTime;
lastTime = startTime;
unprocessedTime += passedTime / (double)Time.SECOND;
frameCounter += passedTime;
while(unprocessedTime > frameTime){
render =true;
unprocessedTime -= frameTime;
if(Window.isCloseRequested())
stop();
Time.setDelta(frameTime);
//TODO: update game
game.input();
game.update();
if(frameCounter >= Time.SECOND){//每秒钟输出一次FPS
System.out.println(frames);
frames = 0;
frameCounter =0;
}
}
if(render){
render();
frames++;
}else{
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
cleanUp();
}
private void render(){
game.render();
Window.render();
}
private void cleanUp(){
Window.dispose();
}
public static void main(String[] args) {
Window.createWindow(WIDTH, HEIGHT, TITLE);
MainComponent game = new MainComponent();
game.start();
}
}
Time.java
package com.base.engine;
public class Time {
public static final long SECOND = 1000000000L;
private static double delta;
public static long getTime(){
return System.nanoTime();
}
public static double getDelta(){
return delta;
}
public static void setDelta(double delta){
Time.delta = delta;
}
}