如何制作基本的 FPS 计数器?

问题描述 投票:0回答:6

我正在尝试在立方体渲染程序中显示每秒帧数。我想看看它的表现。那么,我该怎么做呢?我已经对此进行了研究,但是我看到的示例要么使用多个类但仍然不起作用,要么它们使用我没有的库。有没有办法通过使用预装的库(如 ctime)来获取 FPS?我正在使用 OpenGL 和 C++。

这是我的(空)函数:

void GetFPS()
{

}

然后我在渲染函数中显示我的 FPS:

std::cout << xRot << " " << yRot << " " << zRot << " " << FPS << "\n"; //xRot, yRot, and zRot are my cube's rotation.

我的程序设置为 60FPS,但我想查看实际的 FPS,而不是它设置的值。

c++ opengl frame-rate
6个回答
21
投票

您必须使用

clock()
对 2 个不同的时间间隔进行采样 但注意到存在几个问题:

  • 时钟的分辨率是几毫秒(您可以使用 std::chrono 等解决方法,但是根据实现的不同,即使 chrono 也可能没有那么高分辨率。在我的带有 GCC 4.9.1 的电脑上,即使使用 std,我也从未获得比 16 毫秒更好的分辨率::计时。
  • 通常使用
    clock()
    你会多次得到 0,有时你会测量一个实时时间(在我的例子中,它只是跳跃 15/16 毫秒)
  • 除非您使用垂直同步(vsync),否则您将不会测量实际帧时间,而只会测量渲染循环中花费的CPU时间(要激活垂直同步,您必须在操作系统功能中设置SwapInterval(1),或者例如使用SDL等库提供可移植的跨平台实现)
  • 要测量真实渲染时间,您可以使用 GL 的时间查询(任何时候您可能只有 1 个计时器绑定,因此如果您正在测量帧速率,则无法测量渲染特定内容所需的时间)。
  • 不要测量 FPS(除非您只是想向用户展示),而是以毫秒为单位测量帧时间,这样可以更直观地估计性能。 (您知道从 100 FPS 到 80 FPS 存在 2.5 毫秒的差异,从 40 FPS 到 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 的项目中都使用了该代码)


8
投票

只需保存渲染场景前后的时间“滴答声”,然后进行简单的计算即可。

这是一个使用

<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;
}

4
投票

只需在任何循环中调用它即可测量每秒的调用次数。

#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;
    }
}

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

0
投票

快速且完整

#include <time.h>   // clock
#include <stdio.h>  // snprintf

unsigned int iMemClock, iCurClock, iLoops;
char aFPS[12];

/* main loop */
{
    if (iMemClock > (iCurClock = clock()))
        iLoops++;
    else
    {
        snprintf(aFPS, sizeof(aFPS),"FPS: %d",iLoops);
        iMemClock = iCurClock + CLOCKS_PER_SEC;
        iLoops = 0;
    }

    /*
    someRoutines(); 
    */
}
/* main loop */

0
投票

我无法让这些工作发挥作用。这是我使用 this method 获取 ms 的解决方案。

// Gets the time in milliseconds
auto ms() {
    auto now = Clock::now();
    auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
    auto fraction = now - seconds;

    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(fraction);
    return milliseconds.count();
}

// Main loop
auto prevTime = ms();
while (running) {
  frames++;

  processRender();

  if (deltaTime >= 1000) {
    // Do something here every second
    second();
    deltaTime = 0;
    frames = 0;
  }

  auto currTime = ms();
  diff = currTime - prevTime;
  if (diff > 0) {
    deltaTime += diff;
  }
  prevTime = currTime;
}
© www.soinside.com 2019 - 2024. All rights reserved.