简体   繁体   English

在C ++中限制FPS

[英]Limiting FPS in C++

I'm currently making a game in which I would like to limit the frames per second but I'm having problems with that. 我目前正在制作一款游戏,其中我想限制每秒的帧数,但是我遇到了问题。 Here's what I'm doing: 这是我在做什么:

I'm getting the deltaTime through this method that is executed each frame: 我正在通过每帧执行的此方法获取deltaTime:

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

deltaTime is having the value I would expect (around 0.012.... to 0.016...) deltaTime具有我期望的值(大约0.012 ....到0.016 ...)

And than I'm using deltaTime to delay the frame through the Sleep windows function like this: 并且比起我使用deltaTime通过如下的“睡眠”窗口功能延迟帧:

void Time::limitToMAXFPS() {

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

MAXFPS is equal to 60 and I'm multiplying by 1000 to convert seconds to milliseconds. MAXFPS等于60,我乘以1000,将秒转换为毫秒。 Though everything seems correct I'm sill having more than 60 fps (I'm getting around 72 fps) 虽然一切似乎都正确,但我仍然拥有超过60 fps的帧速(我达到了约72 fps)

I also tried this method using while loop: 我也使用while循环尝试了这种方法:

void Time::limitToMAXFPS() {

    double diff = 1.0 / MAXFPS - deltaTime;

    if(diff > 0) {

        double t = glfwGetTime( );

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

    }

}

But still I'm getting more than 60 fps, I'm still getting around 72 fps... Am I doing something wrong or is there a better way for doing this? 但是我仍然获得超过60 fps的速度,仍然达到72 fps的速度...我做错了什么吗?或者有更好的方法来做到这一点吗?

How important is it that you return cycles back to the CPU? 将周期返回给CPU有多重要? To me, it seems like a bad idea to use sleep at all. 对我来说,根本不使用睡眠似乎是一个坏主意。 Someone please correct me if I am wrong, but I think sleep functions should be avoided. 如果我错了,请有人纠正我,但我认为应该避免睡眠功能。

Why not simply use an infinite loop that executes if more than a certain time interval has passed. 为什么不简单地使用一个无限循环,如果超过一定时间间隔,该循环将执行。 Try: 尝试:

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

Last time that I used GLFW, it seemed to self-limit to 60 fps anyway. 上一次我使用GLFW时,无论如何它似乎都自我限制为60 fps。 If you are doing anything high performance orientated (game or 3D graphics), avoid anything that sleeps, unless you wanna use multithreading. 如果您要执行任何面向高性能的任务(游戏或3D图形),请避免执行任何休眠操作,除非您想使用多线程。

Sleep can be very inaccurate. 睡眠可能非常不准确。 A common phenomenon seen is that the actual time slept has a resolution of 14-15 milliseconds, which gives you a frame rate of ~70. 常见的现象是实际睡眠时间的分辨率为14-15毫秒,这使您的帧速率约为70。

Is Sleep() inaccurate? Sleep()是否不正确?

I've given up of trying to limit the fps like this... As you said Windows is very inconsistent with Sleep. 我已经放弃尝试像这样限制fps了……正如您所说的,Windows与Sleep非常不一致。 My fps average is being always 64 fps and not 60. The problem is that Sleep takes as argument an integer (or long integer) so I was casting it with static_cast. 我的fps平均始终是64 fps,而不是60。问题是Sleep接受一个整数(或长整数)作为参数,因此我使用static_cast进行了强制转换。 But I need to pass to it as a double. 但是我需要将它作为一个双倍传递给它。 16 milliseconds each frame is different from 16.6666... That's probably the cause of this extra 4 fps (so I think). 每帧16毫秒不同于16.6666 ...这可能是造成此额外4 fps的原因(所以我认为)。

I also tried : 我也尝试过:

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

and the same thing is happening with sleep_for . sleep_for也发生了同样的事情。 Then I tried passing the decimal value remaining from the milliseconds to chrono::microseconds and chrono::nanoseconds using them 3 together to get a better precision but guess what I still get the freaking 64 fps. 然后,我尝试将剩余的十进制值从毫秒传递到chrono::microsecondschrono::nanoseconds将它们一起使用3以获得更好的精度,但是我仍然可以得到惊人的64 fps。

Another weird thing is in the expression (1.0 / MAXFPS - deltaTime) * 1000.0) sometimes (Yes, this is completely random) when I change 1000.0 to a const integer making the expression become (1.0 / MAXFPS - deltaTime) * 1000) my fps simply jumps to 74 for some reason, while the expression is completely equal to each other and nothing should happen. 当我将1000.0更改为const整数,使表达式变为(1.0 / MAXFPS-deltaTime)* 1000)我的fps时,表达式中有时会出现另一个奇怪的事情(1.0 / MAXFPS-deltaTime)* 1000.0)(是的,这是完全随机的)只是由于某种原因跳到74,而表达式完全相等,什么也不会发生。 Both of them are double expressions I don't think is happening any type promotion here. 它们都是双重表达式,我认为这里没有发生任何类型提升。

So I decided to force the V-sync through the function wglSwapIntervalEXT(1); 因此,我决定通过功能wglSwapIntervalEXT(1)强制进行V同步; in order to avoid screen tearing. 为了避免屏幕撕裂。 And then I'm gonna use that method of multiplying deltaTime with every value that might very depending on the speed of the computer executing my game. 然后,我将使用那种将deltaTime与每个值相乘的方法,该值可能非常取决于执行游戏的计算机的速度。 It's gonna be a pain because I might forget to multiply some value and not noticing it on my own computer creating inconsistency, but I see no other way... Thank you all for the help though. 这会很痛苦,因为我可能会忘记增加一些值,而没有在自己的计算机上注意到它,这会导致不一致,但是我看不到其他方式...谢谢大家的帮助。

I've recently started using glfw for a small side project I'm working on, and I've use std::chrono along side std::this_thread::sleep_until to achieve 60fps 我最近开始将glfw用于正在进行的一个小型项目,并且在std::this_thread::sleep_until旁边使用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);
}

to add you can easily adjust FPS preference by adjusting end . 要添加,您可以通过调整end轻松调整FPS偏好设置。 now with that said, I know glfw was limited to 60fps but I had to disable the limit with glfwSwapInterval(0); 现在,我知道glfw被限制为60fps,但是我不得不使用glfwSwapInterval(0);禁用该限制glfwSwapInterval(0); just before the while loop. 在while循环之前。

Are you sure your Sleep function accept floating point values. 您确定“睡眠”功能接受浮点值吗? If it only accepts int , your sleep will be a Sleep(0) which will explain your issue. 如果它只接受int ,则您的睡眠将是Sleep(0),它将解释您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM