phenomLi / Blog

Comments, Thoughts, Conclusions, Ideas, and the progress.
219 stars 17 forks source link

碰撞求解(一):使用向量 #34

Open phenomLi opened 5 years ago

phenomLi commented 5 years ago

碰撞求解是紧接着碰撞检测后的一个步骤,顾名思义就是对发生碰撞的对象进行碰撞反应的模拟,比如反弹旋转等。碰撞求解可以说是物理引擎里最难的部分之一了,但是放心,这篇文章会先从最简单的向量部分入门,利用简单的向量知识,模拟简单的碰撞效果。


该文章只涉及少量简单数学,请放心食用。要求:

球与墙壁的碰撞

我们先从最基本的开始,考虑在理想情况下(无重力,阻力,完全弹性碰撞)有一些球在盒子里自由运动的情况: 其中箭头方向代表球的速度方向。


先不考虑球与球直接的碰撞,那么在盒子中,球只会与墙壁发生碰撞,通过碰撞不断改变球的速度方向(大小不变)。我们可以想象到,当球碰撞墙壁时,它的运动轨迹是这样的: 其中蓝色向量代表球碰撞前的速度,红色向量代表球碰撞后的速度。


所以显然的,要求解球碰撞墙壁后的速度方向就是要求红色向量。
为了求解红色的向量,我们可以对这次碰撞进行建模:

u代表碰撞前速度,v代表碰撞后速度,n代表碰撞法向,且uv关于n对称。碰撞法向n通常情况下不容易求得,但是由于现在情景简单,所以这里我们可以一眼看出n就是垂直与墙壁平面的向量。注意n是一个单位向量


现在un都是已知的,我们要做的就是用un去表示v。现在还是不好求出v,但我们可以把v平移到u的起点,然后延长n,延长后的n记为n'


这时,我们很容易得到一个关键等式: 所以只要求出n'就可以了。那么怎么求呢?观察发现,由于uv是等长的,uvn' 形成了一个等腰三角形,我们可以用投影解决。


首先,我们把u投影到n'上,得到1/2|n'|。 将结果乘上2便得到n'的模长,再由于n'n是共线的,且n为单位向量,所以只要将n乘上n'的模长即可求得n'


最后,我们把n'换一下,得到v关于un的表达式:


解决了。很简单。


其实整个流程要注意的只有一点,就是n的方向,如果n是指向墙壁外的,那么最后的表达式就要加号换成减号。

球与球的碰撞

有了上面的基础,求解球与球的碰撞就水到渠成了,只要解决两个问题就好:

  1. 确定碰撞法线n
  2. 墙壁是静止的,球与球是动态的,因此要考虑另一个球的情况:两个球在求解时的法线是相反的


球与球的碰撞法向其实也很简单,相信大家都能看出来是两个球圆心间的向量: 求得后将其单位化即可。


其次对于求解另一个球的v,只要取反向碰撞法向即可,也就是上面说到的加号变减号的情况。

最后

本文只是碰撞求解的入门,在物理引擎中使用上面的方案其实是不现实的,因为对象还包含旋转,摩擦力和非弹性碰撞,单一的求出速度并不能解决所有问题。本文旨在让大家了解什么是碰撞求解,以及对其有个大概的认识。