在C ++中限制FPS

时间:2017-01-19 12:46:07

标签: c++ opengl sleep glfw frame-rate

我目前正在制作一款游戏,我想限制每秒帧数,但我遇到了问题。这就是我正在做的事情:

我通过这个每帧执行的方法得到deltaTime:

void Time::calc_deltaTime() {
    double currentFrame = glfwGetTime();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;
}

deltaTime具有我期望的值(大约0.012 ....到0.016 ......)

而且我正在使用deltaTime来延迟帧通过睡眠窗口功能,如下所示:

void Time::limitToMAXFPS() {

    if(1.0 / MAXFPS > deltaTime)
        Sleep((1.0 / MAXFPS - deltaTime) * 1000.0);
}

MAXFPS等于60,我乘以1000将秒转换为毫秒。虽然一切看起来都是正确的,但我的基础是超过60 fps(我的速度大约是72 fps)

我也尝试使用while循环方法:

void Time::limitToMAXFPS() {

    double diff = 1.0 / MAXFPS - deltaTime;

    if(diff > 0) {

        double t = glfwGetTime( );

        while(glfwGetTime( ) - t < diff) { }

    }

}

但是我仍然得到超过60 fps,我仍然得到大约72 fps ...我做错了什么或有更好的方法来做这个?

5 个答案:

答案 0 :(得分:3)

睡眠可能非常不准确。一个常见的现象是实际睡眠时间的分辨率为14-15毫秒,这使你的帧速率达到70左右。

Is Sleep() inaccurate?

答案 1 :(得分:3)

将周期返回CPU会有多重要?对我来说,完全使用睡眠似乎是一个坏主意。如果我错了,请有人纠正我,但我认为应该避免睡眠功能。

为什么不简单地使用一个无限循环,如果超过一定的时间间隔就会执行。尝试:

const double maxFPS = 60.0;
const double maxPeriod = 1.0 / maxFPS;

// approx ~ 16.666 ms

bool running = true;
double lastTime = 0.0;

while( running ) {
    double time = glfwGetTime();
    double deltaTime = time - lastTime;

    if( deltaTime >= maxPeriod ) {
        lastTime = time;
        // code here gets called with max FPS
    }
}

上次使用GLFW时,无论如何它似乎自我限制为60 fps。如果你正在做任何高性能定位(游戏或3D图形),避免任何睡眠,除非你想使用多线程。

答案 2 :(得分:1)

我已经放弃了尝试限制这样的fps ...正如你所说的Windows与Sleep非常不一致。我的fps平均值总是64 fps而不是60.问题是Sleep将整数(或长整数)作为参数,所以我使用static_cast进行转换。但我需要将其作为双重传递给它。每帧16毫秒不同于16.6666 ......这可能是这个额外4 fps的原因(所以我认为)。

我也尝试过:

std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<long>(1.0 / MAXFPS - deltaTime) * 1000.0)));

sleep_for也发生了同样的事情。然后我尝试将剩余的十进制值从毫秒传递到chrono::microsecondschrono::nanoseconds,将它们一起使用3以获得更好的精度但是猜测我仍然得到了64 fps的怪异。

另一个奇怪的事情是表达式(1.0 / MAXFPS - deltaTime)* 1000.0)有时(是的,这是完全随机的)当我将1000.0更改为const整数时使表达式变为(1.0 / MAXFPS - deltaTime)* 1000 )由于某种原因,我的fps只是跳到74,而表达式完全相同,没有任何事情发生。它们都是双重表达,我认为这里不会发生任何类型的推广。

所以我决定通过函数wglSwapIntervalEXT(1)强制V-sync;为了避免屏幕撕裂。然后我将使用deltaTime与每个值相乘的方法,这些值可能非常依赖于执行我游戏的计算机的速度。这将是一种痛苦,因为我可能会忘记增加一些价值,而不是在我自己的计算机上注意到它会造成不一致,但我没有别的办法......感谢大家的帮助。

答案 3 :(得分:0)

我最近开始使用glfw进行我正在进行的小型项目,并且我在std::chrono旁边使用std::this_thread::sleep_until来达到60fps

auto start = std::chrono::steady_clock::now();
while(!glfwWindowShouldClose(window))
{
    ++frames;
    auto now = std::chrono::steady_clock::now();
    auto diff = now - start;
    auto end = now + std::chrono::milliseconds(16);
    if(diff >= std::chrono::seconds(1))
    {
        start = now;
        std::cout << "FPS: " << frames << std::endl;
        frames = 0;

    }
    glfwPollEvents();

    processTransition(countit);
    render.TickTok();
    render.RenderBackground();
    render.RenderCovers(countit);

    std::this_thread::sleep_until(end);
    glfwSwapBuffers(window);
}

添加您可以通过调整end轻松调整FPS偏好设置。 现在说,我知道glfw限制在60fps但我必须在while循环之前用glfwSwapInterval(0);禁用限制。

答案 4 :(得分:-1)

您确定您的睡眠功能是否接受浮点值。如果只接受int,您的睡眠将是睡眠(0),这将解释您的问题。