Gaffer on Games有一篇关于使用RK4 integration来提高游戏物理效果的优秀文章。实现很简单,但其中的数学让我感到困惑。我在概念层面上理解导数和积分,但已经很久没有操作方程了。
以下是Gaffer实现的主要内容:
void integrate(State &state, float t, float dt)
{
Derivative a = evaluate(state, t, 0.0f, Derivative());
Derivative b = evaluate(state, t+dt*0.5f, dt*0.5f, a);
Derivative c = evaluate(state, t+dt*0.5f, dt*0.5f, b);
Derivative d = evaluate(state, t+dt, dt, c);
const float dxdt = 1.0f/6.0f * (a.dx + 2.0f*(b.dx + c.dx) + d.dx);
const float dvdt = 1.0f/6.0f * (a.dv + 2.0f*(b.dv + c.dv) + d.dv)
state.x = state.x + dxdt * dt;
state.v = state.v + dvdt * dt;
}
有人能简单解释一下RK4是如何工作的吗?具体来说,为什么我们要在0.0f
,0.5f
,0.5f
和1.0f
处对导数进行平均?将导数平均到第四阶与使用较小时间步长进行简单欧拉积分有何不同?
阅读下面的答案和其他文章后,我了解了RK4的工作原理。回答我的问题: “有人能简单地解释一下RK4是如何工作的吗?” RK4利用这样一个事实:如果我们使用高阶导数而不仅仅是一阶或二阶导数,我们可以更好地逼近一个函数。这就是为什么泰勒级数比欧拉逼近收敛得快的原因。(看一下页面右侧的动画) 具体来说,为什么我们要在
0.0f
、0.5f
、0.5f
和1.0f
处对导数求平均值?Runge-Kutta方法是一个函数的近似,它在时间步长内对多个点的导数进行采样,而泰勒级数只对单个点的导数进行采样。采样这些导数后,我们需要知道如何加权每个样本以获得最接近的近似。一种简单的方法是选择与泰勒级数相符的常数,这就是如何确定Runge-Kutta方程的常数。 这篇文章使我更加清楚。请注意,
(15)
是泰勒级数展开,而(17)
是Runge-Kutta推导。
将导数平均到第4阶与使用较小的时间步长进行简单的欧拉积分有什么不同?
从数学上讲,它的收敛速度比做许多欧拉逼近要快得多。当然,通过足够的欧拉逼近,我们可以获得与RK4相等的精度,但需要的计算能力不足以证明使用欧拉法。