I noticed users are finding this Q&A and being misled,所以我想在这里发帖指出接受的答案不正确,并且没有像它声称的那样给出与帧率无关的结果。
我们可以通过简单的电子表格计算来证明这一点。设置三个具有不同时间步长的时间序列,并使用该答案中的公式:
[Velocity Cell] = [Previous Velocity Cell]
+ (Accel - Frict * [Previous Velocity Cell] * [Time Step]) * [Time Step]
[Position Cell] = [Previous Position Cell] + [Velocity Cell] * [Time Step]
这三组结果在很短的时间后就会明显不同(这里我想象的是 1.6 秒的模拟)
这是意料之中的,因为乘以时间步长只能正确解释 线性 变化。它隐含地假设变化率在我们模拟的区间内保持不变,因此该区间内的总变化就是当前速率乘以区间持续时间。
只要允许变化率本身发生变化(即,一旦速度由于重力或摩擦等加速度而发生变化),那么这个假设就被违反了。在较慢/较长时间步长上运行的代码将假定速度在整个持续时间内只有一个值,而在较快/较短时间步长上运行的代码将在同一时间间隔内看到多个不同的值,并且自然会到达不同的值结果。
I explore this problem in more detail in this answer here,展示了如何推导计算模拟区间内变化率变化的方程,但这里是 TL;DR:
如果您希望以恒定加速度与帧速率无关的集成,请使用:
position += velocity * timeStep + 0.5 * acceleration * timeStep * timeStep;
velocity += acceleration * timeStep;
如果您想要与 乘法拖动 实现与帧速率无关的集成,请使用:
newVelocity = velocity * pow(fractionRemainingAfterOneSecond, timeStep);
position += (newVelocity - velocity) / naturalLog(fractionRemainingAfterOneSecond);
velocity = newVelocity;
如果您想要与加速和拖动无关的帧速率集成......您无法获得它(抱歉)。我们没有积分的闭式解
即使我在上面给出的两个所谓的与帧速率无关的解决方案也是如此,如果你有无限精度的实数。在实际代码中,每一步都会出现舍入误差,并且以不同的时间步长运行相同的模拟会导致舍入误差在不同的地方堆积。但它们将比公认答案中提供的更强大。
为了完整起见,这里比较显示了使用上述与帧速率无关的公式模拟的轨迹,以 60 FPS 和 10 FPS 步进。我还提供了一个根本不使用累积增量的分析解决方案,以表明具有不同时间步长的模拟不仅彼此一致,而且还与基本事实一致(直至舍入误差)。