-1

我有一个模拟,我试图将其转换为“实时”。我说“实时”是因为如果需要可以降低性能(也可以减慢观察者/客户的时间)。但是,如果对象数量很少,我想限制性能,使其以稳定的帧速率(在这种情况下约为 100 FPS)运行。

我分别尝试了 linuxsleep()Sleep()windows,但它似乎不够准确,因为 FPS确实下降到我目标的一小部分。我想这种情况在游戏中很常见,尤其是在线游戏,但我找不到任何关于这个主题的有用材料。帧限制的最佳方式是什么?是否有一种睡眠方法可以保证它不会放弃比指定更多的时间?

注意:我在 2 个不同的集群(linux 和 windows)上运行它,所有节点都只有内置视频。所以我必须在两个平台上实现限制,它不应该是基于视频卡的(如果有的话)。我还需要仅对一个线程/节点实施限制,因为节点之间已经存在同步,如果一个线程受到适当限制,其他节点将自动受到限制。

编辑:一些伪代码显示了我如何实现限流器:

while (ProcessControlMessages())
{
    uint64 tStart;
    SimulateFrame();
    uint64 newT =_context.GetTimeMs64();
    if (newT - tStart < DESIRED_FRAME_RATE_DURATION)
        this_thread::sleep_for(chrono::milliseconds(DESIRED_FRAME_RATE_DURATION - (newT - tStart)));
}

我还在考虑是否可以每 N 帧进行一次限制,其中 N 是所需帧速率的一小部分。我会试一试并报告。

4

2 回答 2

2

对于游戏来说,帧限制器通常是不够的。相反,更新游戏状态的方法(在您的情况下SimulateFrame())保持帧速率独立。例如,如果你想移动一个对象,那么实际的偏移量就是对象的速度乘以最后一帧的持续时间。同样,您可以对所有类型的计算执行此操作。

这种方法的优点是用户在保持实时性的同时获得了最大的帧速率。但是,您应该注意帧持续时间不要太小(< 1 ms)。这可能导致计算不准确。在这种情况下sleep,具有固定持续时间的小型可能会有所帮助。

这就是游戏通常处理这个问题的方式。你必须检查你的模拟是否也适合这种技术。

于 2013-09-15T06:35:44.913 回答
1

与其让每一帧都尝试睡眠足够长的时间以成为一个完整的帧,不如让它们睡眠以尝试平均化。保持全局/线程拥有的时间计数。对于每一帧都有一个“期望的最早结束时间”,从之前期望的最早结束时间计算,而不是从当前时间计算

tGoalEndTime = _context.GetTimeMS64() + DESIRED_FRAME_RATE_DURATION;
while (ProcessControlMessages())
{
    SimulateFrame();
    uint64 end =_context.GetTimeMs64();
    if (end < tGoalEndTime) {
        this_thread::sleep_for(chrono::milliseconds(tGoalEndTime - end)));
        tGoalEndTime += DESIRED_FRAME_RATE_DURATION;
    } else {
        tGoalEndTime = end; // we ran over, pretend we didn't and keep going
}

注意:这使用了您的示例sleep_for,因为我想显示执行它的最少更改次数。 sleep_until在这里效果更好。

诀窍是任何睡眠时间过长的帧都会立即导致接下来的几帧赶上。

注意:在现代消费者操作系统上,您无法获得 2 毫秒内的任何时间(100 fps 上的 20% 抖动)。大多数消费者操作系统上的线程时间量约为 100 毫秒,因此在您睡觉的那一刻,您可能会在轮到您之前休眠多个时间量。 sleep_until 可能会使用特定于操作系统的技术来减少抖动,但您不能依赖它。

于 2013-09-15T18:56:39.210 回答