插值和碰撞

让我们拿一个简单的例子来说明一个球从墙上弹起。 物理学与显示分离。 物理被设置为运行在每秒20帧的速度,显示比这更快(通常是60 fps)。

为了平滑渲染,渲染函数得到一个称为alpha的参数,这个参数是帧的时间(即alpha = accumulator / time_per_physics_frame)的时间百分比(0和1之间的浮点数/双精度值)。 我们用这个值进行插值

position = currentPosition * alpha + previousPosition * (1 - alpha) 

从一个位置移动到另一个位置时,这个效果很好。 例如,如果x = 2,并且我们以高fps在dx = 4处移动,则球从2到6在x处呈现。

现在说球有x = 2,dx = -4,并且在x = 0处有一堵墙。物理模拟器将球更新为x = 2,dx = 4(碰撞保留所有的能量而没有弹性)。 所以使用上面的插值没有渲染的球撞墙。

插值函数如何处理像墙碰撞的事情?

我有一个类似的问题关于视觉插值。 在我的情况下,我用物体速度直观地预测了当前帧和下一帧之间的物理移动。 问题是在物理模拟到达之前,物体被允许在视觉上通过坚固的障碍物。 有一个简单的解决scheme。 而不是试图预测物理运动,我让我的显示器实际上跟随物理模拟。 就我而言,这很简单:

 visualPos = actualPos - speed * (1.0 - alpha) 

虽然这是我以前的插值方法

 visualPos = actualPos + speed * alpha 

这样,碰撞显示正确。

但是,这似乎并不能解决您的问题。 我想我想说的是:只要你插入,你的结果永远不会是完美的。 在你的具体情况下,我建议增加物理FPS – 20似乎真的很低。

由于您的物理系统可能会为位置以外的物体生成速度,因此您可以使用Hermite样条曲线进行插值,而不仅仅是使用线性插值。 Hermite样条在样条的开始和结束处接受切向量,在那里可以放入对象的速度。

这应该对你的例子有所帮助,因为当球从x = 2,dx = -4到x = 2,dx = 4时,三次样条将使它移向墙壁,然后反转速度并返回到原来的位置。 它看起来不像是一场碰撞,因为它能够在时间步长的时间内顺利地逆转速度,就像一艘太空飞船发射推进器离开墙壁,而不是撞墙,反弹 – 这是一个非常多的速度不连续变化。 不过,这可能还是比刚刚落地的球好。

你遇到的是物理引擎的一个非常普遍的问题。 基本上,你的物体是在你的帧率提供的裂缝之间。 首先它靠近墙壁,然后在墙内,而不会发生碰撞!

有两个解决这个问题的方法:

  • Ducktape它 – 使用更小的时间步,这实际上是一个更高的帧率。 如果将帧率提高到60 fps,则“墙壁之前”和“墙内”之间现在有6帧。 为什么这是一个ducktape解决scheme? 因为你的帧率可能还不够高,你永远不能把它升起来。

  • 正确地修复 – 不要只将你的物理基础放在当前的位置上。

我不打算解释第一个解决scheme,这很简单。 如果这对你有用,太棒了! 许多游戏已经提供了解决scheme。

不过,我真的想解释第二个解决scheme。

假设我们有以下情况:

球的情况

在这里,红球想从墙上弹开。 我们可以看到它的方向由蓝线表示。 但是,这不是它的方向,而是它的速度 ,这是direction * speed 。 所以,我们在这里的是球的当前位置和球的未来的位置,这将是position + (direction * speed)

现在,我们可以使用墙的表面正常偏转我们的球:

Boink!

这里要注意的重点是:球还没有移动。 就球而言,它仍然在墙前。

代码现在应该看起来如下:

  • 球在必要时更新其方向和速度。
  • 球从方向和速度计算它的速度。
  • 球从位置和速度计算其未来的位置。
  • 场景使用球的位置和未来的位置来确定球将与墙相撞。
  • Wall将Ball的速度反映在其表面上,为Ball创造新的未来位置,新的方向和新的速度。
  • Ball将其位置设置为未来的位置并更新其方向和速度。

现在你的球永远不会落在裂缝中。 更好的是:多个物体可以与Ball相撞,并且希望所有的物体都能解决到未来的位置。 但是,这将需要场景的多次碰撞解决。

为了进一步阅读,寻找“扫描testing”。