为什么 computer/game 物理引擎通常是不确定的?
Why are computer/game physics engines often non-deterministic?
多年来使用各种游戏物理引擎进行开发,我注意到在同一台机器上,我观察到运行之间的物理模拟结果大相径庭。最近,Unity 引擎执行此操作,即使物理学是按设定的时间间隔 (FixedUpdate
) 计算的——据我所知,它应该完全独立于帧速率。
我之前在游戏论坛上问过这个问题,被告知是混沌运动造成的:见双摆。但是,如果起始条件得到精确控制,即使双摆也是确定性的,对吗?在同一台机器上,浮点数学的表现不应该相同吗?
我知道浮点数学精度存在问题,但我知道这些问题(如概述 here)在 相同的硬件 上不是问题 - - 浮点不准确是否仍然是确定性的?我错过了什么?
tl;dr:如果 运行 在同一台机器上使用相同的浮点数学(?)进行模拟,那么模拟不应该是确定性的吗?
非常感谢您的宝贵时间。
是的,你是对的。在同一台机器上执行的程序每次都会给出 相同的 结果(至少在理想情况下——可能会有 cosmic rays or other external things that affect memory and what not, but I would say these are not of our concern). All calculations on a computer are deterministic, and so all algorithms of a computer will necessarily be deterministic (which is the reason it's so hard to make random number generators)!
您看到的随机性很可能是在程序中使用一些随机数生成器实现的,随机数的种子从 运行 运行 变化。如果您使用相同的种子开始模拟,您将看到相同的结果。
编辑:我不熟悉 Unity,但做了更多研究似乎表明 FixedUpdate
例程可能是问题所在。
Except for the audio thread, everything in unity is done in the main thread if you don't explicitly start a thread of your own. FixedUpdate runs on the very same thread, at the same interval as Update, except it makes up for lost time and simulates a fixed time step.
如果是这种情况,函数本身看起来有点像:
void physicsUpdate(double currentTime, double lastTime)
{
double deltaT = currentTime - lastTime;
// do physics using `deltaT`
}
由于 deltaT
来自两个不同的 运行,我们自然会得到不同的行为。这是根据后台正在运行的其他进程 运行 确定的,因为它们可能会延迟主线程。这个函数会被不规则地调用,你会观察到 运行s 的不同结果。请注意,这些不规则性主要 而不是 是由于浮点不精确,而是由于积分时的不准确。 (例如,速度通常由 v = a*deltaT
计算,它假设自上次更新以来加速度恒定。这通常是不正确的)。
但是,如果函数看起来像这样:
void physicsUpdate(double deltaT)
{
// do physics using `deltaT`
}
每次使用它进行模拟时,您总是会得到完全相同的结果。
我对 Unity 或其物理模拟没有太多经验,但我发现了以下 forum post which also links to an article 这似乎表明浮点计算精度下降。
正如您所提到的,很多人似乎一直在重复这个问题!
该论坛还链接到此 blog post,这可能会阐明该问题。
多年来使用各种游戏物理引擎进行开发,我注意到在同一台机器上,我观察到运行之间的物理模拟结果大相径庭。最近,Unity 引擎执行此操作,即使物理学是按设定的时间间隔 (FixedUpdate
) 计算的——据我所知,它应该完全独立于帧速率。
我之前在游戏论坛上问过这个问题,被告知是混沌运动造成的:见双摆。但是,如果起始条件得到精确控制,即使双摆也是确定性的,对吗?在同一台机器上,浮点数学的表现不应该相同吗?
我知道浮点数学精度存在问题,但我知道这些问题(如概述 here)在 相同的硬件 上不是问题 - - 浮点不准确是否仍然是确定性的?我错过了什么?
tl;dr:如果 运行 在同一台机器上使用相同的浮点数学(?)进行模拟,那么模拟不应该是确定性的吗?
非常感谢您的宝贵时间。
是的,你是对的。在同一台机器上执行的程序每次都会给出 相同的 结果(至少在理想情况下——可能会有 cosmic rays or other external things that affect memory and what not, but I would say these are not of our concern). All calculations on a computer are deterministic, and so all algorithms of a computer will necessarily be deterministic (which is the reason it's so hard to make random number generators)!
您看到的随机性很可能是在程序中使用一些随机数生成器实现的,随机数的种子从 运行 运行 变化。如果您使用相同的种子开始模拟,您将看到相同的结果。
编辑:我不熟悉 Unity,但做了更多研究似乎表明 FixedUpdate
例程可能是问题所在。
Except for the audio thread, everything in unity is done in the main thread if you don't explicitly start a thread of your own. FixedUpdate runs on the very same thread, at the same interval as Update, except it makes up for lost time and simulates a fixed time step.
如果是这种情况,函数本身看起来有点像:
void physicsUpdate(double currentTime, double lastTime)
{
double deltaT = currentTime - lastTime;
// do physics using `deltaT`
}
由于 deltaT
来自两个不同的 运行,我们自然会得到不同的行为。这是根据后台正在运行的其他进程 运行 确定的,因为它们可能会延迟主线程。这个函数会被不规则地调用,你会观察到 运行s 的不同结果。请注意,这些不规则性主要 而不是 是由于浮点不精确,而是由于积分时的不准确。 (例如,速度通常由 v = a*deltaT
计算,它假设自上次更新以来加速度恒定。这通常是不正确的)。
但是,如果函数看起来像这样:
void physicsUpdate(double deltaT)
{
// do physics using `deltaT`
}
每次使用它进行模拟时,您总是会得到完全相同的结果。
我对 Unity 或其物理模拟没有太多经验,但我发现了以下 forum post which also links to an article 这似乎表明浮点计算精度下降。
正如您所提到的,很多人似乎一直在重复这个问题!
该论坛还链接到此 blog post,这可能会阐明该问题。