1

我为这篇长篇博文先道歉,但正如你可能看到的那样,我已经考虑这个问题已经有一段时间了,我觉得在我的脑袋爆炸之前我需要其他人的一些意见:-)

一段时间以来,我一直在尝试各种方法来构建满足以下所有标准的游戏引擎:

  • 对象更新和对象渲染完全分离
  • 完全决定论
  • 以个人速度更新和渲染
  • 不阻塞共享资源

对象更新和对象渲染完全分离

对象更新和对象渲染的分离似乎对于确保在向图形 API 发送数据和交换缓冲区时优化资源使用至关重要。即使您想确保完全并行性以使用 CPU 的多个内核,似乎仍然必须管理这种分离。

完全决定论

许多游戏类型,尤其是多人游戏版本,必须确保完全确定性。否则玩家将体验到同一游戏的不同状态,有效地打破了游戏逻辑。游戏回放也需要确定性。并且它对于其他目的非常有用,在这些目的中,每次模拟运行在给定相同的起始条件和输入的情况下每次都产生相同的结果是很重要的。

以个人速度更新和渲染

这确实是完全确定性的先决条件,因为您不能让模拟依赖于渲染速度(即各种显示器刷新率、图形适配器速度等)。在最佳条件下,更新速度应设置为某个固定间隔(例如,每秒 25 次更新 - 可能会更少,具体取决于更新类型),并且渲染速度应为客户端的显示器刷新率/图形适配器允许的任何值。

这意味着应该允许渲染速度高于更新速度。虽然这听起来像是一种浪费,但有一些已知的技巧可以确保增加的渲染周期不会浪费(内插/外推),这意味着更快的监视器/适配器将获得更令人愉悦的视觉体验。

但是,还必须允许渲染速度低于更新速度,即使这确实会导致浪费更新周期 - 至少添加的更新周期不会全部呈现给用户。然而,这对于确保流畅的多人游戏体验是必要的,即使其中一个客户端中的渲染由于某种原因突然缓慢爬行也是如此。

不阻塞共享资源

如果要实现上述其他标准,还必须遵循我们不能允许渲染等待更新,反之亦然。当然,很明显,当 2 个不同的线程共享对资源的访问并且一个线程正在更新其中一些资源时,就不可能保证永远不会发生阻塞。但是,可以将这种阻塞保持在绝对最小值 - 例如,在更新对象队列和先前渲染对象队列之间切换指针引用时。

所以...

我对这里所有熟练的人的问题是:我要求太多了吗?

我一直在许多网站上阅读有关这些不同主题的想法。但是,我所看到的建议似乎总是忽略了其中的一部分。也许原因是你不能在不妥协的情况下拥有这一切。

很久以前,当我把我的想法放在这个线程中时,我开始了这个看似常见的任务: 关于渲染循环策略的思考

那时我的第一个天真假设是,更新和读取是否同时发生并不重要,因为这种变化对象状态是如此之小,以至于您不应该注意到一个对象是否偶尔领先另一个对象。

现在我有点聪明了,但有时仍然感到困惑。

一种可以满足我所有愿望的方法的最有希望和最详细的描述是:http: //blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part1/ 一个三态模型将确保渲染器始终可以选择一个新的队列进行渲染,而无需等待(切换指针引用时可能只有一微秒)。同时,更新程序总是可以访问构建下一个状态树所需的 2 个队列(1 个队列用于创建/更新下一个状态,1 个队列用于读取先前状态 - 即使渲染器将其读取为出色地)。

我最近有时间对此进行示例实现,并且效果很好,但是有两个问题。

  • 一个是必须处理对所有相关对象的多个引用的小问题
  • 另一个更严重(除非我太需要了)。这就是在给定快速屏幕刷新率的情况下,外推法(与内插法相反)用于维持视觉上令人愉悦的状态表示。虽然这两种方法都可以显示偏离可靠计算的对象状态的状态,但在我看来,当预测无法代表现实时,外推法会产生更多可见的伪影。我的立场似乎得到了支持: http ://gafferongames.com/networked-physics/snapshots-and-interpolation/ 据我所知,不可能在三态设计中实现插值,因为它要求渲染器始终具有对 2 个队列的读取访问权限,以计算两个已知状态之间的中间状态。

因此,我正在尝试扩展 slapware-blog 上建议的三态模型,以利用插值而不是外推 - 同时尝试简化多参考结构。虽然在我看来是可能的,但我想知道价格是否太高。为了实现我所有的目标,我需要拥有

  • 2 个由渲染器独占的队列(或状态)(它们可以被另一个线程用于只读目的,但在渲染期间从不更新或切换
  • 1 个具有最新更新状态的队列(或状态)准备好切换到渲染器,当它完成渲染当前场景时
  • 1 个队列(或状态),下一帧由更新程序构建/更新
  • 1 个队列(或状态),包含上次构建/更新的帧的副本。这与上次发送到渲染器的状态相同,因此更新器应该可以访问该队列/状态以读取先前的状态,并且渲染器应该可以访问以渲染状态。

因此,这意味着我应该始终保留 4 个渲染状态副本,以使该设计能够平稳、无锁定、确定地运行。

我担心我想太多了。因此,如果你们中的任何人建议将我拉回地面,或建议可以改进的地方,对设计的批评,或者可能是对解释如何实现这些目标的良好资源的引用,或者为什么会这样或不是一个好主意 - 请和他们一起打我:-)

4

0 回答 0