如何制作基本的 FPS 计数器?
How to Make a Basic FPS Counter?
我试图在我的立方体渲染程序中显示我的每秒帧数。我想看看它的表现。那么,我该怎么做呢?我已经对此进行了研究,但我看到的示例要么使用了多个 类 但仍然不起作用,要么它们使用了我没有的库。有没有办法通过使用像 ctime 这样的预安装库来获得 FPS?我在 C++ 中使用 OpenGL。
这是我的(空)函数:
void GetFPS()
{
}
然后我在我的渲染函数中显示我的 FPS:
std::cout << xRot << " " << yRot << " " << zRot << " " << FPS << "\n"; //xRot, yRot, and zRot are my cube's rotation.
我的程序设置为 60FPS,但我想查看实际的 FPS,而不是设置的值。
只需保存渲染场景前后的时间"ticks",然后进行简单计算。
这是一个使用 <ctime>
的 clock()
函数的示例。 (请注意 clock()
在不同平台上的工作方式不同)
clock_t current_ticks, delta_ticks;
clock_t fps = 0;
while(true)// your main loop. could also be the idle() function in glut or whatever
{
current_ticks = clock();
render();
delta_ticks = clock() - current_ticks; //the time, in ms, that took to render the scene
if(delta_ticks > 0)
fps = CLOCKS_PER_SEC / delta_ticks;
cout << fps << endl;
}
您必须使用 clock()
对 2 个不同的时间间隔进行采样
但是注意到有几个问题:
- 时钟的分辨率是几毫秒(您可以使用 std::chrono 等解决方法,但是根据实施情况,即使 chrono 也可能没有那么高的分辨率。在我的 GCC 4.9.1 PC 上,我从来没有得到比即使 std::chrono.
也需要 16 毫秒
- 通常使用
clock()
你会得到 0 很多次,有时你会测量实时(在我的例子中它只跳了 15/16 毫秒)
- 除非您使用垂直同步 (vsync),否则您将不会测量实际帧时间,而只会测量渲染循环中花费的 CPU 时间(要激活垂直同步,您必须使用 OS 函数或例如使用像 SDL 这样提供可移植跨平台实现的库)
- 要测量实际渲染时间,您可以使用 GL 的时间查询(您可能在任何时候都只有 1 个计时器绑定,因此如果您测量帧率,则无法测量渲染特定内容需要多长时间)。
- 不要测量 FPS(除非您只想向用户展示它),而是以毫秒为单位测量帧时间,这样可以更直观地估计性能。 (你知道从 100 到 80 FPS 是 2.5 毫秒的差异,从 40 到 20 FPS 是 25 毫秒的差异!)
这样做:
double clockToMilliseconds(clock_t ticks){
// units/(units/time) => time (seconds) * 1000 = milliseconds
return (ticks/(double)CLOCKS_PER_SEC)*1000.0;
}
//...
clock_t deltaTime = 0;
unsigned int frames = 0;
double frameRate = 30;
double averageFrameTimeMilliseconds = 33.333;
while(rendering){
clock_t beginFrame = clock();
render();
clock_t endFrame = clock();
deltaTime += endFrame - beginFrame;
frames ++;
//if you really want FPS
if( clockToMilliseconds(deltaTime)>1000.0){ //every second
frameRate = (double)frames*0.5 + frameRate*0.5; //more stable
frames = 0;
deltaTime -= CLOCKS_PER_SEC;
averageFrameTimeMilliseconds = 1000.0/(frameRate==0?0.001:frameRate);
if(vsync)
std::cout<<"FrameTime was:"<<averageFrameTimeMilliseconds<<std::endl;
else
std::cout<<"CPU time was:"<<averageFrameTimeMilliseconds<<std::endl;
}
}
上面的代码在你做一些需要几秒钟的事情时也有效。我做了一个每秒更新一次的计算,你也可以更频繁地更新它。 (请注意,我在大多数需要 FPS 的项目中都使用了该代码)
只需在任何循环中调用它即可测量每秒的调用次数。
#include <chrono>
void printFPS() {
static std::chrono::time_point<std::chrono::steady_clock> oldTime = std::chrono::high_resolution_clock::now();
static int fps; fps++;
if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - oldTime) >= std::chrono::seconds{ 1 }) {
oldTime = std::chrono::high_resolution_clock::now();
std::cout << "FPS: " << fps << std::endl;
fps = 0;
}
}
如果您只是为了打印它而测量 FPS,您可以使用 std::chrono
因为它测量挂钟。使用 std::clock()
会得到比 std::chrono
更准确的值,因为它测量的是处理时间,但您可能不想以如此高的精度打印 FPS。
下面的解决方案使用 std::chrono
来计算程序的正常运行时间并在每次帧更新后递增帧计数器。将帧计数器除以程序的正常运行时间即可得到 FPS。
#include <chrono>
#include <iostream>
#include <thread>
using namespace std::chrono;
steady_clock::time_point first_tp;
unsigned long frame_count = 0;
duration<double> uptime()
{
if (first_tp == steady_clock::time_point{})
return duration<double>{ 0 };
return steady_clock::now() - first_tp;
}
double fps()
{
const double uptime_sec = uptime().count();
if (uptime_sec == 0)
return 0;
return frame_count / uptime_sec;
}
void time_consuming_function()
{
std::this_thread::sleep_for(milliseconds{ 100 });
}
void run_forever()
{
std::cout << "fps at first: " << fps() << '\n';
first_tp = std::chrono::steady_clock::now();
while (true)
{
std::cout << "fps: " << fps() << '\n';
time_consuming_function();
frame_count++;
}
}
int main()
{
run_forever();
}
运行 它在我的机器上产生:
$ ./measure_fps
fps at first: 0
fps: 0
fps: 9.99108
fps: 9.99025
fps: 9.98997
fps: 9.98984
而将其调整为 std::clock()
会得到
$ ./measure_fps
fps at first: 0
fps: 0
fps: 37037
fps: 25316.5
fps: 23622
fps: 22346.4
我试图在我的立方体渲染程序中显示我的每秒帧数。我想看看它的表现。那么,我该怎么做呢?我已经对此进行了研究,但我看到的示例要么使用了多个 类 但仍然不起作用,要么它们使用了我没有的库。有没有办法通过使用像 ctime 这样的预安装库来获得 FPS?我在 C++ 中使用 OpenGL。
这是我的(空)函数:
void GetFPS()
{
}
然后我在我的渲染函数中显示我的 FPS:
std::cout << xRot << " " << yRot << " " << zRot << " " << FPS << "\n"; //xRot, yRot, and zRot are my cube's rotation.
我的程序设置为 60FPS,但我想查看实际的 FPS,而不是设置的值。
只需保存渲染场景前后的时间"ticks",然后进行简单计算。
这是一个使用 <ctime>
的 clock()
函数的示例。 (请注意 clock()
在不同平台上的工作方式不同)
clock_t current_ticks, delta_ticks;
clock_t fps = 0;
while(true)// your main loop. could also be the idle() function in glut or whatever
{
current_ticks = clock();
render();
delta_ticks = clock() - current_ticks; //the time, in ms, that took to render the scene
if(delta_ticks > 0)
fps = CLOCKS_PER_SEC / delta_ticks;
cout << fps << endl;
}
您必须使用 clock()
对 2 个不同的时间间隔进行采样
但是注意到有几个问题:
- 时钟的分辨率是几毫秒(您可以使用 std::chrono 等解决方法,但是根据实施情况,即使 chrono 也可能没有那么高的分辨率。在我的 GCC 4.9.1 PC 上,我从来没有得到比即使 std::chrono. 也需要 16 毫秒
- 通常使用
clock()
你会得到 0 很多次,有时你会测量实时(在我的例子中它只跳了 15/16 毫秒) - 除非您使用垂直同步 (vsync),否则您将不会测量实际帧时间,而只会测量渲染循环中花费的 CPU 时间(要激活垂直同步,您必须使用 OS 函数或例如使用像 SDL 这样提供可移植跨平台实现的库)
- 要测量实际渲染时间,您可以使用 GL 的时间查询(您可能在任何时候都只有 1 个计时器绑定,因此如果您测量帧率,则无法测量渲染特定内容需要多长时间)。
- 不要测量 FPS(除非您只想向用户展示它),而是以毫秒为单位测量帧时间,这样可以更直观地估计性能。 (你知道从 100 到 80 FPS 是 2.5 毫秒的差异,从 40 到 20 FPS 是 25 毫秒的差异!)
这样做:
double clockToMilliseconds(clock_t ticks){
// units/(units/time) => time (seconds) * 1000 = milliseconds
return (ticks/(double)CLOCKS_PER_SEC)*1000.0;
}
//...
clock_t deltaTime = 0;
unsigned int frames = 0;
double frameRate = 30;
double averageFrameTimeMilliseconds = 33.333;
while(rendering){
clock_t beginFrame = clock();
render();
clock_t endFrame = clock();
deltaTime += endFrame - beginFrame;
frames ++;
//if you really want FPS
if( clockToMilliseconds(deltaTime)>1000.0){ //every second
frameRate = (double)frames*0.5 + frameRate*0.5; //more stable
frames = 0;
deltaTime -= CLOCKS_PER_SEC;
averageFrameTimeMilliseconds = 1000.0/(frameRate==0?0.001:frameRate);
if(vsync)
std::cout<<"FrameTime was:"<<averageFrameTimeMilliseconds<<std::endl;
else
std::cout<<"CPU time was:"<<averageFrameTimeMilliseconds<<std::endl;
}
}
上面的代码在你做一些需要几秒钟的事情时也有效。我做了一个每秒更新一次的计算,你也可以更频繁地更新它。 (请注意,我在大多数需要 FPS 的项目中都使用了该代码)
只需在任何循环中调用它即可测量每秒的调用次数。
#include <chrono>
void printFPS() {
static std::chrono::time_point<std::chrono::steady_clock> oldTime = std::chrono::high_resolution_clock::now();
static int fps; fps++;
if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - oldTime) >= std::chrono::seconds{ 1 }) {
oldTime = std::chrono::high_resolution_clock::now();
std::cout << "FPS: " << fps << std::endl;
fps = 0;
}
}
如果您只是为了打印它而测量 FPS,您可以使用 std::chrono
因为它测量挂钟。使用 std::clock()
会得到比 std::chrono
更准确的值,因为它测量的是处理时间,但您可能不想以如此高的精度打印 FPS。
下面的解决方案使用 std::chrono
来计算程序的正常运行时间并在每次帧更新后递增帧计数器。将帧计数器除以程序的正常运行时间即可得到 FPS。
#include <chrono>
#include <iostream>
#include <thread>
using namespace std::chrono;
steady_clock::time_point first_tp;
unsigned long frame_count = 0;
duration<double> uptime()
{
if (first_tp == steady_clock::time_point{})
return duration<double>{ 0 };
return steady_clock::now() - first_tp;
}
double fps()
{
const double uptime_sec = uptime().count();
if (uptime_sec == 0)
return 0;
return frame_count / uptime_sec;
}
void time_consuming_function()
{
std::this_thread::sleep_for(milliseconds{ 100 });
}
void run_forever()
{
std::cout << "fps at first: " << fps() << '\n';
first_tp = std::chrono::steady_clock::now();
while (true)
{
std::cout << "fps: " << fps() << '\n';
time_consuming_function();
frame_count++;
}
}
int main()
{
run_forever();
}
运行 它在我的机器上产生:
$ ./measure_fps
fps at first: 0
fps: 0
fps: 9.99108
fps: 9.99025
fps: 9.98997
fps: 9.98984
而将其调整为 std::clock()
会得到
$ ./measure_fps
fps at first: 0
fps: 0
fps: 37037
fps: 25316.5
fps: 23622
fps: 22346.4