C++ 控制帧率的常用方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5508922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:19:45  来源:igfitidea点击:

What's the usual way of controlling frame rate?

c++graphics

提问by hstefan

I'm new to graphics, so I don't know how people usually control the frame rate for rendering things. I mean, how can you set you application to render at, say, 30fps? There's probably lots of APIs that offers such thing, but I need to code it from scratch.

我是图形的新手,所以我不知道人们通常如何控制渲染事物的帧速率。我的意思是,您如何将应用程序设置为以 30fps 的速度呈现?可能有很多 API 提供这样的东西,但我需要从头开始编写它。

回答by ssube

There are two "usual" ways of "controlling" framerate, and neither is quite that simple.

“控制”帧率有两种“常用”方式,但都不是那么简单。

The first and more controlling of the two, and something that is usually optional, is VSync. This forces the video card to only push out a new frame when the monitor is done refreshing. Many monitors refresh at 60 Hz, so you tend to get 60 FPS.

两者的第一个和更多控制,通常是可选的,是垂直同步。这会强制视频卡仅在显示器刷新后推出新帧。许多显示器以 60 Hz 刷新,因此您往往会获得 60 FPS。

This works quite well to capframerate to monitor refresh rate, but when framerate drops below refresh, it's forced to the next multiple. Thus, as the framerate starts to drop a bit, you lose quite a bit of potential rendering time, because it's forced to 60, then 30, then 20, etc.

这可以很好地限制帧率以监控刷新率,但是当帧率低于刷新率时,它会被强制为下一个倍数。因此,随着帧率开始下降,您会损失相当多的潜在渲染时间,因为它被强制为 60、30、20 等等。

(a bit of info about vsync in DirectXand OpenGL)

(关于DirectXOpenGL 中的vsync 的一些信息)

The second method, commonly used (with vsync optionally added on) is not to limit framerate. Instead, adjust your code to handle differences. This is far more flexible in the long run and generally better coding, IMO, and much simpler than trying to force a particular FPS count.

常用的第二种方法(可选添加 vsync)是不限制帧速率。相反,调整您的代码以处理差异。从长远来看,这要灵活得多,而且通常编码更好,IMO,而且比尝试强制特定 FPS 计数要简单得多。

Assuming you have a simple render loop, it starts out looking something like:

假设你有一个简单的渲染循环,它开始看起来像:

while ( gameloop )
{
    float framedelta = ( timeNow - timeLast )
    timeLast = timeNow;

    for each ( GameObject object in World )
    {
        object->Animate(framedelta);
        object->Move(speed * framedelta)
    }

    render();
}

You want to look at the time difference/time passed/delta, and work from there. Allow the framerate to scale based on hardware and settings (there are too many variations for you to predict or handle even half), and make your game work with that instead of controlling it. Much easier for you and more flexible and stable in practice.

您想查看时差/经过的时间/增量,然后从那里开始工作。允许帧率根据硬件和设置进行缩放(有太多的变化让您无法预测或处理甚至一半),并使您的游戏使用它而不是控制它。对您来说更容易,在实践中更灵活和稳定。

回答by André Caron

The typical way to yield a predictable(if not constant) frame rate (with video or 3D graphics) is described in the following pseudo-code.

下面的伪代码描述了产生可预测(如果不是恒定的)帧速率(使用视频或 3D 图形)的典型方法。

Algorithm

算法

  1. Prepare the next frame (render in back-buffer);
  2. Sleep for the remainder of the time slice;
  3. Ask the frame to be displayed (swap front and back buffers).
  1. 准备下一帧(在后台缓冲区中渲染);
  2. 睡眠时间片的剩余时间;
  3. 询问要显示的帧(交换前后缓冲区)。

Note the position of the sleep operation. It's sandwiched between the preparation and display of the same frame. This is the principal key to a constant frame rate! You want the preparation of the frame to count in the total time slice for displaying the frame.

注意睡眠操作的位置。它夹在同一个框架的准备和显示之间。这是恒定帧率的主要关键!您希望帧的准备计入用于显示帧的总时间片

There are a number of variants on how to implement each of these steps (choice of sleep operation based on it's resolution, reliability, etc.), but the core is there.

关于如何实现每个步骤(根据分辨率、可靠性等选择睡眠操作)有许多变体,但核心就在那里。

Tips for extra reliability

提高可靠性的提示

  • Don't invoke your sleep function once for the entire interval. Define some constant with the maximum error you're ready to accept and repeatedly sleep for periods of this interval until the time remaining is smaller or equal to this amount.
  • Don't be scared to occasionally drop a frame when you know you won't be able to prepare the next frame in time. It's visually more appealing to skip a frame than it is to produce a variable frame rate.
  • If you can avoid background threads on a single-processor system, avoid them. Using worker threads will really mess up the reliability of your sleep function. The best approach is to split your background work into small chunks and have this work executed instead of sleeping.
  • 不要在整个时间间隔内调用一次 sleep 函数。用您准备接受的最大误差定义一些常数,并在此间隔期间反复休眠,直到剩余时间小于或等于此数量。
  • 当您知道无法及时准备下一帧时,不要害怕偶尔丢帧。跳过一帧在视觉上比产生可变帧率更有吸引力。
  • 如果可以避免单处理器系统上的后台线程,请避免它们。使用工作线程真的会破坏睡眠功能的可靠性。最好的方法是将您的后台工作分成小块,然后执行这项工作而不是休眠。

The 1st is easy to implement and can be hidden away in a helper function. The 2nd is a little more touchy as it requires you to keep statistics of average rendering speed, among other things. The 3rd is hard to implement as it's often difficult to predict how much time different tasks will take. It's only usually implemented in real-time systems with hard constraints.

第一个很容易实现,可以隐藏在辅助函数中。第二个有点敏感,因为它要求您保留平均渲染速度的统计数据等。第三个很难实施,因为通常很难预测不同任务将花费多少时间。它通常只在具有硬约束的实时系统中实现。