GJK碰撞检测原理

GJK是一种非常规但速度很快的凸体碰撞检测算法,本文将简单介绍GJK的基本原理。为了方便理解,文中以2D环境为例进行介绍。

首先我们考虑2D平面上两个凸多边形A和B,当A、B发生碰撞时,A和B必然会发生某一部分的重合,也就是说,A中的某些点与B中的某些点在空间上重叠了(至少有一个点),进一步讲,就是在A中存在一点PA,同时在B中存在点PB,满足:PA - PB = 0
在这里插入图片描述
基于上述事实,我们自然可以想到,只要发现A中的某点减去B中的某点为0,即可判断AB二者发生碰撞。那如何检查呢?一个朴素而有效的思路是——将A中的每一个点依次减去B中的每一个点,看是否为0。

漂亮,恭喜你已经完全掌握了GJK算法的精髓。

具体讲就是两点:

  • 计算AB二者的闵可夫斯基差A ㊀ B——即A中的每一个点依次减去B中的每一个点
  • 检查原点O是否在A ㊀ B形成的多边形中——即检查是否有为0的情况

用数学的方式表示的话,就是检查:
O ∈ A ㊀ B O ∈ A ㊀ B OAB

我们知道,对于两个凸多边形,二者的闵可夫斯基和也是一个凸多边形。由于闵可夫斯基差可以理解为闵可夫斯基和的特殊情况,因此可知:两个凸多边形的闵可夫斯基差是一个凸多边形。

这里需要提到凸多边形的一个特点。对于凸多边形边界上的任意一点P,如果用Dp表示从多边形中心指向P点的方向,那P点即为该凸多边形在Dp方向上的最远点(否则P点在这个方向上就凹进去了)。

另外一条关于凸多边形的特性是,在凸多边形边界上任意三点组成的三角形,一定在凸多边形内部。因此,我们只要从凸多边形上任意找到三个点,组成一个三角形ABC,然后检查原点O是否在三角形ABC内部,如果在,那原点一定也在凸多边形中,检查结束。如果不在,那就再找一个点形成新的三角形继续检查。

其过程大体如下:

  • 首先我们找到凸多边形边界上任意两点A和B,形成一条连线AB
    在这里插入图片描述
  • 此时O不在AB连线之上,于是我们需要找到新的一点C组成三角形ABC,在确定C点的时候,为了使形成的三角形更有几率包含原点,C点应该在连线AB靠近O的一侧。我们可以通过向量三重积得到AB指向O一侧的法线VN,以VN作为方向找到多边形的极值点C,检查O是否在三角形ABC中。

在这里插入图片描述

  • 如果O仍然不在ABC中,此时我们需要看O位于ABC的哪个沃洛诺伊域中,并以该域的边为基础,按照上面的方式继续找到点D组成新的三角形。以上图的情形为例,此时将以BC作为边,向O的一侧确定D。

在这里插入图片描述

  • 然后我们发现新的三角形BCD包含了原点O,于是查找结束,原始的两个多边形有碰撞。

在实际的使用中,我们往往是通过原始凸多边形的顶点进行检查。因为有性质:
两个凸集的闵可夫斯基和的顶点都是由两凸集的顶点相加得到的。 两个凸集的闵可夫斯基和的顶点都是由两凸集的顶点相加得到的。 两个凸集的闵可夫斯基和的顶点都是由两凸集的顶点相加得到的。

我们可以大概想一下这条性质,假设需要进行碰撞检查的原始凸多边形为A和B。对于A中的一个顶点P,A的中心到P确定一个方向V。可知,在V的方向上,P附近的点离中心都是比P要近的。然后我们用V作为方向查找凸多边形B重点极值点P’,其结果只有两种情况:

  • B中在该方向上只有一个点最远,即P’也是B中的一个顶点。
  • B中在该方向上有多个同等远的点,即B中有一条与V垂直的边。

无论以上哪种情况,P都会在求得的闵可夫斯基C中确定一个顶点。换句话讲,就是闵可夫斯基和的顶点是由原始多边形的顶点决定的。
闵可夫斯基差同理,只不过在A和B中取的方向相反。

这样,每次确定一个方向后,只要从A中找到在该方向上延申最远的顶点(点积最大),然后找到B中在该方向的反方向上延申最远的顶点,二者相减,就可以找到C中在该方向上的极值顶点。通过这种方式,我们就可以做到在C中只按照原点带来的启发方向不断查找顶点组成新的三角形进行检查,当检查到三角形包含原点时,发生碰撞,当没有顶点可以查找时,检查退出,不发生碰撞。

所以实际的过程更像是下面这样:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值