为啥计算机/游戏物理引擎通常是不确定的?

Posted

技术标签:

【中文标题】为啥计算机/游戏物理引擎通常是不确定的?【英文标题】:Why are computer/game physics engines often non-deterministic?为什么计算机/游戏物理引擎通常是不确定的? 【发布时间】:2017-04-25 02:53:29 【问题描述】:

多年来使用各种游戏物理引擎进行开发,我注意到在同一台机器上,我观察到运行之间的物理模拟结果大相径庭。最近,Unity 引擎执行此操作,即使物理是按设定的时间间隔计算的 (FixedUpdate)——据我所知,它应该完全独立于帧速率。

我之前在游戏论坛上问过这个问题,并被告知这是由于混乱的运动:参见双摆。但是,如果启动条件得到精确控制,即使是双摆也是确定性的,对吧?在同一台机器上,浮点数学的行为不应该是一样的吗?

我了解浮点数学准确性存在问题,但我了解这些问题(如 here 所述)不是相同硬件上的问题——不是浮点不准确性还是确定性的?我错过了什么?

tl;dr:如果在同一台机器上运行模拟,使用相同的浮点数学(?),模拟不应该是确定性的吗?

非常感谢您的宝贵时间。

【问题讨论】:

@RyanVincent 浮点数是一个近似值,是的,但它们仍然是确定性的,因此混乱的系统应该没有影响。 值得注意的是,FixedUpdate() 确实以一致的频率运行 (Time.fixedTime)。更改间隔只会更改在Update() 之前调用FixedUpdate() 的次数(以“赶上”),尽管具体数字会根据自上一帧以来经过的时间而有所不同。这是a little more info,了解实际情况。 @Serlite 找到相同的来源:) 相应地编辑了我的答案。 @RyanVincent 来自文章:“......那么我们现在是否在所有编译器和机器上都有确定性结果?没有。” (强调我的)请注意,在同一台计算机上,结果将是相同的。 【参考方案1】:

是的,你是对的。在同一台机器上执行的程序每次都会给出相同的结果(至少理想情况下——可能有cosmic rays或其他影响内存的外部事物,但我会说这些是不是我们关心的)。计算机上的所有计算都是确定性的,因此计算机的所有算法都必然是确定性的(这就是it's so hard to make random number generators的原因)!

您看到的随机性很可能是在程序中使用一些随机数生成器实现的,并且随机数的种子因运行而异。如果您使用相同的种子开始模拟,您将看到相同的结果。

编辑:我不熟悉 Unity,但做更多研究似乎表明 FixedUpdate 例程可能是问题所在。

除了音频线程,如果你没有明确地启动你自己的线程,所有的事情都是在主线程中完成的。 FixedUpdate 在同一个线程上运行,与 Update 的时间间隔相同,只是它弥补了损失的时间并模拟了一个固定的时间步长。

source

如果是这样的话,并且函数本身看起来有点像:

void physicsUpdate(double currentTime, double lastTime)

    double deltaT = currentTime - lastTime;
    // do physics using `deltaT`

在这里,由于deltaT 在两次不同的运行中不同,我们自然会得到不同的行为。这是由后台运行的其他进程决定的,因为它们可能会延迟主线程。这个函数会被不定期地调用,你会从运行中观察到不同的结果。请注意,这些不规则性大多不是是由于浮点不精确,而是由于进行积分时的不准确性。 (例如,速度通常由 v = a*deltaT 计算,假设自上次更新以来加速度恒定。这通常是不正确的)。

但是,如果函数看起来像这样:

void physicsUpdate(double deltaT)

    // do physics using `deltaT`

每次您使用它进行模拟时,您总是会得到完全相同的结果。

【讨论】:

我认为您的编辑是真正的答案。对于每个物理更新调用,两次运行的 Time.deltaTime 值不一定相同。使用该值进行数学运算会产生小的差异,并且会随着时间的推移而增加。 这对我来说似乎是最好的答案。我将继续深入研究为什么我使用的每个游戏物理引擎都是非确定性的,但我只想感谢您抽出宝贵时间提供如此出色的答案!也许他们都受此困扰——也许固定更新有些难以实现? 是的,我无法找到 Unity 物理的任何故意随机方面,所以在我看来,deltaT 的变化更有可能是问题所在。 @ScottChamberlain 是的,我同意。我最初不确定我们在谈论什么“非确定性”的东西。还应注意,最后一种情况的主要差异不是因为浮点不精确,而是因为线性积分导致的误差。 我的印象是 Unity 的 FixedUpdate 例程在一个例程中被调用,类似于本文中概述的例程(在这种情况下,变量 deltatime 不应该是不确定性的来源):kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8 【参考方案2】:

我对 Unity 或其物理模拟没有太多经验,但我发现以下 forum post 还链接到 article,这似乎表明它与浮点计算的精度有关。

正如你所提到的,很多人似乎一直在重复这个问题!

论坛还链接到此blog post,这可能会对这个问题有所了解。

【讨论】:

浮点数学是确定性的。给定相同的输入,您应该始终获得相同的输出。 感谢您的回答,但这些文章没有提到 IEEE 浮点数学在相同的硬件上有所不同...只是硬件不同。浮点数学在相同的硬件上应该是确定性的...对吗? @AaronMeier 我编辑了要链接到的问题的博客文章似乎表明可能存在影响它的运行时因素,因此很有可能! @Clint - 可能是这样,但 randomascii 帖子没有提到相同的硬件,但它确实引用了 this post,其中特别提到了 不同 中的浮点非确定性硬件。

以上是关于为啥计算机/游戏物理引擎通常是不确定的?的主要内容,如果未能解决你的问题,请参考以下文章

目前哪个游戏物理引擎最先进

关于Unity中物理引擎的使用

003-unity3d 物理引擎简介以及示例

Bullet物理引擎简单说明

SPRITEKIT游戏框架之关于PHYSICS物理引擎属性

unity物理引擎浅谈