帧率(FPS)计算的六种方法总结

帧率(FPS)计算是游戏编程中常见的一个话题。大体来说,总共有如下六种方法:

一、固定时间帧数法

帧率计算的公式为:

1
fps = frameNum / elapsedTime;

如果记录固定时间内的帧数,就可以计算出同步率。此种方法用得较多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int fps()
{
static int fps = 0;
static int lastTime = getTime(); // ms
static int frameCount = 0;

++frameCount;

int curTime = getTime();
if (curTime - lastTime > 1000) // 取固定时间间隔为1秒
{
fps = frameCount;
frameCount = 0;
lastTime = curTime;
}
return fps;
}

还有另一种写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int fps(int deltaTime)
{
static int fps = 0;
static int timeLeft = 1000; // 取固定时间间隔为1秒
static int frameCount = 0;

++frameCount;
timeLeft -= deltaTime;
if (timeLeft < 0)
{
fps = frameCount;
frameCount = 0;
timeLeft = 1000;
}
return fps;
}

二、固定帧数时间法

帧率计算的公式为:

1
fps = frameNum / elapsedTime;

如果每隔固定的帧数,计算帧数使用的时间,也可求出帧率。此种方法使用得较少。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int fps()
{
static int fps = 0;
static int frameCount = 0;
static int lastTime = getTime(); // ms

++frameCount;

if (frameCount >= 100) // 取固定帧数为100帧
{
int curTime = getTime();
fps = frameCount / (curTime - lastTime) * 1000;
lastTime = curTime;
frameCount = 0;
}
return fps;
}

三、实时计算法

实时计算法直接使用上一帧的时间间隔进行计算,结果具有实时性,但平滑性不好。

1
2
3
4
5
int fps(int deltaTime) // ms
{
int fps = static_cast<int>(1.f / deltaTime * 1000); // 别忘了先转换为浮点数,否则会有精度丢失
return fps;
}

四、总平均法

总平均法使用全局帧数除以全局时间,以求出帧率。

1
2
3
4
5
6
7
8
9
10
11
int beginTime = getTime();

int fps()
{
static int frameCount = 0;

++frameCount;

int deltaTime = getTime() - beginTime();
return static_cast<int>(frameCount * 1.f / deltaTime * 1000); // 别忘了先转换为浮点数,否则会有精度丢失
}

五、精确采样法

精确采样法采样前N个帧,然后计算平均值。此种方法需要额外的内存空间,所以不常用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int fps(int deltaTime) // ms
{
static std::queue<int> q;
static int sumDuration = 0; // ms

int fps = 0;
if (q.size() < 100) // 样本数设为100
{
sumDuration += deltaTime;
q.push(deltaTime);
fps = static_cast<int>(q.size() * 1.f / sumDuration * 1000.f); // 别忘了转换为浮点数,否则会有精度丢失
}
else
{
sumDuration -= q.front();
sumDuration += deltaTime;
sumDuration.pop();
sumDuration.push(deltaTime);
fps = static_cast<int>(100.f / sumDuration * 1000.f); // 别忘了转换为浮点数,否则会有精度丢失
}
return fps;
}

六、平均采样法

平均采样法利用上次的统计结果,克服了精确采样法需要使用额外空间的缺点。此种方法较常用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int fps(int deltaTime) // ms
{
static float avgDuration = 0.f;
static alpha = 1.f / 100.f; // 采样数设置为100
static int frameCount = 0;

++frameCount;

int fps = 0;
if (1 == frameCount)
{
avgDuration = static_cast<float>(deltaTime);
}
else
{
avgDuration = avgDuration * (1 - alpha) + deltaTime * alpha;
}

fps = static_cast<int>(1.f / avgDuration * 1000);
return fps;
}