GJK算法理论

发布时间 2023-11-14 23:08:07作者: yanghui01

原理

GJK算法的核心就是闵可夫斯基差,即若两个多边形相交,则它们的闵可夫斯基差必然包括原点。

 

闵可夫斯基差

用多边形A的所有点,减去多边形B中所有的点得到的一个点集合(是点之间两两相减后得到的集合,而不是做集合的差集)。
A–B = {a–b∣a ∈ A, b ∈ B}

在碰撞检测中,不会用到完整的闵可夫斯基差的点集,而是会通过迭代的方式,每次A和B各取一个点相减,对于简单的形状一般迭代几次就有结果了,所以并不会用到完整的点集的。

 

相交多边形的闵可夫斯基差必然包含原点,原理又是啥?

这边拿数字距离:离得越远的两个数字,相减的结果,比0大的也多,比如:10-2=8;离得近的数字,相减的结果,与0开始接近,比如:6-5=1;相等的数字,相减结果就是0,比如:5-5=0;

就是差不多类似的原理,说的标准一点就是:两个多边形距离越大,则差集的中心位置离原点越远;反之,离原点越近。如果相交,则差集多边形会包含原点。

 

Support函数

gjk中使用Support函数返回两个点的差,gjk中并不是盲目的对任意两个点做差,而是会先取一个反向,然后对该方向上离得最远的两个点做差。

 

Simplex

中文名叫单纯形或单行体,Support函数得到的差会作为点会存放在这边。

1) 当它包含一个点时,叫0阶单纯形(点)

2) 当它包含两个点时,叫1阶单纯形(线段)

3) 一般2d中最多会保存三个点,也就是2阶单纯形(三角形)

当单纯形组成的形状包含原点时,就表示两个多边形相交。

 

GJK算法步骤

 

GJK会涉及的相关知识

1) 向量点乘

2) 点是否在线段上

3) 点是否在三角形内

4) 求原点到线段的垂线(垂足)

 

代码部分看这边:

gjk算法代码

 

GJK步骤实例

0) 初始化方向,找出第1个support点a3=c1-a2

 

1) dir取反,第1次迭代,找出下一个support点b3=a1-c2

1-a) 根据当前的单纯形(线段a3b3),找出下一次的方向:a3b3垂足垂指向原点

 

 

2) 第2次迭代,找出下一个support点c3=b1-e2

2-a) 根据当前的单纯形(线段a3b3c3),找出下一次的方向:c3a3比c3b3离原点更近,所以取c3a3的垂足垂指向原点作为方向

 2-b) b3从单纯形中删除,原来的c3将变为b3

 

3) 第3次迭代,找出下一个support点c3

 3-a) 单纯形包含原点了,得到结果