哪种物理模拟方法最适合真正的大增量时间(几小时到几周)?
此外,在不同的增量时间和增量时间相结合时,我是否会遇到任何问题?
哪种物理模拟方法最适合真正的大增量时间(几小时到几周)?
此外,在不同的增量时间和增量时间相结合时,我是否会遇到任何问题?
Answers:
在这些较大的时间跨度中,您可能会使用恒定加速度(可能是零加速度)。相对于时间的恒定加速度的导数为0。这意味着其相对于时间不变,因此,您的增量时间有多大无关紧要。
时间方面的这种小整合提供了您所需的方程式。
a = a
v = at + v0
s = .5at^2 + v0*t + s0
其中:a =加速度,v =速度,v0 =初始速度,s =位置,s0 =初始位置,t =时间
使用此策略,您可以根据需要使用毫秒到几周的时间。将它们结合起来将在方程的v0
和s0
参数中进行。
为了处理碰撞,您必须实现与高速小对象相似的策略。首先使用上述公式计算新位置,然后在所有对象的新旧位置之间进行扫描。由于这些对象中的任何一个都可能彼此相交(几分钟或几天之前),因此这可能变得非常复杂。由于您有这么大的增量时间,因此希望您有足够的时间来处理这些潜在的冲突。
让我们以重力为例。
在下面的函数中,假设我们具有用于位置和速度的类成员变量。由于每dt秒钟的重力,我们需要更新它们。
void update( float dt )
{
acceleration = G * m / r^2;
velocity = velocity + acceleration * dt;
position = position + velocity * dt;
}
随着dt
模拟越来越小,我们的模拟越来越精确(尽管如果dt
变得太小,则在将小数加到大数时会遇到精度错误)。
基本上,您必须确定dt
仿真可以处理的最大数量,以获得足够好的结果。如果输入的dt
结果太大,则只需将仿真分解为较小的步骤,其中每个步骤都是dt
您允许的最大值。
void update( float dt )
{
acceleration = G * m / r^2;
velocity = velocity + acceleration * dt;
position = position + velocity * dt;
}
// this is the function we call. The above function is a helper to this function.
void updateLargeDt( float dt )
{
const float timeStep = 0.1;
while( dt > timeStep )
{
update( timeStep );
dt -= timeStep ;
}
update( dt ); // update with whatever dt is left over from above
}
因此,使用此策略,您可以调整timeStep
以适应所需的保真度(将其设置为一秒钟,一分钟,一小时或其他任何时间,以准确地表示物理学。
大多数游戏倾向于使用简单的Euler前向积分方法(即,将速度随时间积分到位置中,并将加速度积分到速度中)。不幸的是,欧拉方法仅适用于非常小的时间尺度和短期运行。
有更复杂的方法,它们在很长的时间范围内都更准确。最受欢迎和最容易实现的也许是Runge-Kutte-4。RK4通过采样过去的四个位置和速度并进行插值来确定将来的位置。在更长的时间范围内,它往往比Euler方法更准确,但计算量更大。
例如,如果您要计算每隔几天实时更新一次的真实轨道行星的物理特性,则欧拉方法将导致由于数值误差,该行星仅在经过几次轨道后就射向太空。RK4通常会在累积过多误差之前使行星以大致相同的形状绕轨道运行数千次。
但是,在RK4中实现冲突可能非常具有挑战性...