衝突検出アルゴリズムの GJK アルゴリズム

  1. 序章

参考:

SAT はオブジェクト間の衝突を分離の観点から判断しますが、 GJK はオブジェクト間の衝突をオーバーラップの観点から調べます。

GJK は、Gilbert、Johnson、Keerthi の 3 人の先輩によって発明され、2 つの凸多面体間の衝突検出と最短距離を計算するために使用されます。GJK アルゴリズムはO(M+N)の時間計算量内で衝突を検出できます.アルゴリズムの各反復中、アルゴリズムは原点に近い方向を優先するため、収束速度は非常に高速になります. アルゴリズムの証明プロセスはより複雑ですが、原理は比較的簡単に理解できます。GJK は、収束率が反復の方向に依存する反復ベースのアルゴリズムです。

GJK アルゴリズムのコア ロジックは次のとおりです: 2 つの多角形 p と q と初期方向が与えられると、シンプレックスを反復的に構築および更新し、シンプレックスが原点を含むかどうかを判断します. 原点が含まれる場合、2 つのポリゴンは交差し、そうでない場合は交差します交差しないでください。

1.1 GJK アルゴリズムの原理

GJK アルゴリズムの結論は次のとおりです。2 つの多角形が交差する場合、2 つの多角形によって形成されるミンコフスキー差には原点が含まれている必要があります。セクション 1.1 で示したように、差分セットのポイントは原点の両側に分散されます。ここでの違いはポリゴンだけです。

1.2 ミンコフスキー差

多角形 A のすべての点から多角形 B のすべての点を差し引いた点の集合。

ミンコフスキー差分の意義は、2 つの多角形の頂点間の座標分布関係を取得することです.2 つの多角形が交差する場合、差分の点は原点の周りに分布します。つまり、差分には原点が含まれます。

差分セットにはいくつかの特別な特性があります. 差分セットによって形成される多角形の形状は、2 つの多角形間の距離と直接的な関係はありません. 2 つのポリゴン間の距離が大きいほど、差の中心は原点から遠くなり、そうでない場合は原点に近くなります。交差する場合、減算ポリゴンには原点が含まれます。

1.3 シンプレックス

ミンコフスキー差分の計算は非常に面倒なプロセスです. 幸いなことに, 衝突の計算には完全なミンコフスキー差分ポリゴンは必要ありません. 原点を含むことができる差分ポリゴンを計算するだけで済みます. 2D 空間の場合は三角形を取得する必要があり、3D 空間の場合は四面体が必要です。表現の便宜上、このような差多角形をシンプレックスと呼びます。

1.4 サポート機能

表現の便宜上、シンプレックス内の点をサポート ポイントと呼び、サポート ポイントを取得する方法をサポート関数と呼びます。サポート関数の役割は、指定された方向でポリゴンの最も遠い点を計算することです。サポート関数は、特定の方向に沿って 2 つのポリゴンから最も遠い 2 つのポイントを見つけ、その差を計算します。

  • 特定の方向で最も遠い点を見つける方法は? ベクトルの内積が必要です。各頂点とベクトル d の点積をトラバースし、ベクトル d の方向で最も遠い点である点積値が最大の頂点を見つけることができます。この 点 は支点 とも 呼 ば れ る

  • なぜサポート機能が必要なのですか? これは、シンプレックスを構築するときに、生成されたシンプレックスが最大の領域を含み、アルゴリズムの収束を高速化できるように、ミンコフスキー差の内部の点ではなく、可能な限り頂点を取得することを望んでいるためです。

2.GJKアルゴリズム

2.1 GJK アルゴリズムの疑似コードとアルゴリズムの手順

疑似コード:

bool GJK(Shape shapeA, Shape shapeB)
{
    // 得到初始的方向
    Vector2 direction = findFirstDirection();
    // 得到首个support点
    simplex.add(support(direction));
    // 得到第二个方向
    direction = -direction;
    while(true)
    {
        Vector2 p = support(direction);
        // 沿着dir的方向,已经找不到能够跨越原点的support点了。
        if (Vector2.Dot(p, direction) < 0)
            return false;
        
        simplex.add(p);
        // 单形体包含原点了
        if (simplex.contains(Vector2(0, 0)))
            return true;

        direction = findNextDirection();
    }
}

アルゴリズムの手順:衝突検出アルゴリズムの GJK アルゴリズム - Zhihu (zhihu.com)

ここで重要なのは、反復をどのように終了させるか、次の反復の方向性です. 他の概念の方が理解しやすいです. アルゴリズムのコアステップを言葉で説明しましょう。

  1. 最初の方向をランダムに選択し、サポート関数を使用して最初のサポート ポイントを取得します。

  1. 次の反復方向として初期方向を反転します。

  1. 反復ループが始まります。

  1. サポート機能を使用して、新しいサポート ポイントを取得します。

  1. 反復方向の新しいサポート ポイントの射影が 0 未満の場合、この方向では、原点を横切ることができるサポート ポイントを見つけることができないことを意味します。つまり、原点を含むことができるシンプレックスを形成することはもはや不可能です。2 つのポリゴンが交差せず、この端が検出されます。

  1. 支持点が 3 つある場合は、この 3 点を使用して三角形を形成し、原点が含まれている場合は衝突が発生したことを意味し、検出の終了が検出されます。

  1. それ以外の場合は、原点に最も近いサポート エッジの 2 つのサポート ポイントのみを保持します。

  1. このとき、残りの2点の支持点で直線を作り、その直線の垂線を計算します。そして、次の反復方向として原点に向かう方向を取る垂直線を選択します。

  1. 手順 3 に進みます。

ここで理解するのがより難しいのは、ステップ b. 現時点では、シンプレックスには 2 つの状況があります。

  1. 初めてループに入ると、シンプレックスには最初のサポート ポイントが 1 つしかありません。射影が 0 より小さい場合は、原点から離れる方向に沿って、原点を横切ることができるサポート ポイントが見つからないことを意味します。つまり、この点と最初の点の両方が原点の同じ側にあります。

  1. サイクルに入るのが初めてではなく、シンプレックスにはサポート ポイントが 2 つしかなく、ステップ 8 によって反復方向が生成されます。これは、シンプレックスの残りの 2 つのサポート ポイントによって形成される線に垂直です。射影が 0 未満の場合、シンプレックスに残っている 2 つの点のみが、原点に最も近い 2 つの支持点であることを意味します。同時に、この 2 点で形成される線分は、ミンコフスキー差分集合の原点に最も近いエッジです. このエッジは、2 つの多角形間の最短距離を計算するための鍵となります. このエッジは次の章で使用されます.

特別な場合に注意が必要である.ステップ e で原点が 2 つの支持点によって形成される直線上に正確にある場合, それは原点がミンコフスキー差分集合の境界上にあることを意味する. つまり、2 つのポリゴンが衝突し始めたところです。

2.2 アルゴリズムの詳細

(1) 三角形に原点が含まれているかどうかを判断する

ポイントが三角形の内側にあるかどうかを判断する - Zhihu (zhihu.com)

  • 点 O が三角形の内側にある場合、三角形の辺に沿って反時計回りに歩き、点 O は辺の左側に留まらなければなりません。図のように、点はAB、BC、CAの左回りに歩いたときの左側にあります。

  • 如何判断点在一个边的左侧呢?可以借助向量叉乘来判断O是否在向量AB的哪一侧。通过计算向量AO与向量AB的叉乘的值为正,则表示O在AB的左侧,反之为右侧。

向量的叉乘可以用来判断点P是在向量AB的左侧还是右侧。判断一点是否在三角形内部 - 知乎 (zhihu.com)

其运算结果仍是一个向量,我们记之为向量c,它的模定义为:

其中θ为向量a和向量b的夹角,如上图所示,

  • c的模:即以ab为两条边的平行四边形的面积;

  • c的方向:即ab构成平面的法向量,c的方向定义为垂直于ab所构成的平面,并且abc构成右手螺旋定则,也就是右手四指方向从a转向b,大拇指即得到c方向。

#include <iostream>
#include <math.h>
using namespace std;
struct Point {
    double x;
    double y;
};
double product(Point p1,Point p2,Point p3) {
    //首先根据坐标计算p1p2和p1p3的向量,然后再计算叉乘
    //p1p2 向量表示为 (p2.x-p1.x,p2.y-p1.y)
    //p1p3 向量表示为 (p3.x-p1.x,p3.y-p1.y)
    return (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x);
}
bool isInTriangle(Point p1,Point p2,Point p3,Point o) {
    //保证p1,p2,p3是逆时针顺序
    if(product(p1, p2, p3)<0) return isInTriangle(p1,p3,p2,o);
    if(product(p1, p2, o)>0 && product(p2, p3, o)>0 && product(p3, p1, o)>0)
        return true;
    return false;
}
int main() {
    Point p1,p2,p3,o;
    cin >> p1.x >> p1.y;
    cin >> p2.x >> p2.y;
    cin >> p3.x >> p3.y;
    cin >> o.x >> o.y;
    bool flag = isInTriangle(p1,p2,p3,o);
    if(flag) puts("Yes");
    else puts("No");
}
  • 判断若p3在p1p2→的右侧!则表示输入的点的顺序是顺时针的,即A,C,B式的输入,将p2、p3调换位置即可保证顺序是逆时针。

(2)迭代结束条件

GJK 是一种 迭代算法,它需要不断地检测单纯形是否包含原点。它退出迭代的条件是

  1. 单纯形包含原点

  1. 单纯形最后添加的顶点与搜寻方向点乘小于0

(3)2D求垂线

3D:叉积(cross)得到的向量其实是一个垂直向量,垂直于两个进行叉积的向量构建的平面。

(4)找一条边面向原点的法向量方向

这种方法被称为矢量三重积

具体方式:

首先我们定义两个向量 AO 和 AB,如下图所示

我们可以通过 AO 和 AB 的叉乘,找到他们的所在平面的法向量方向,如下图所示

然后再将上一步的结果和 AB 做叉乘,就可以得到指向原点的目标方向。

(5)判断点是否在立方体内部

Rotated Region3: Rotated Boxes in 3D Space - Scripting Helpers

判断点在平面的哪侧:这就意味着,如果投影是负的我们就知道两个向量之间的角差大于90°这就意味着我们在平面下面。另一方面,如果投影是正的那么我们就知道角差小于90°并且我们在平面上方。最后,如果我们的投影是0,那么我们就知道给定的点实际上在平面上。

判断点是否在立方体内部:现在我们知道了如何判断一个点在平面上的哪一边,下一步就是把这个知识应用到我们旋转的区域上。概念很简单,我们用六个面法线都背离立方体中心的平面来定义一个立方体。这样,我们就可以对照所有6个平面来检查任意给定的点,如果有一个点在这6个平面某一个的“上方”,则点在区域外,如果这个点均在这6个平面的“下方”,点就在区域内。

(6)找四面体离原点最近的面

step1:根据右手螺旋定则,找到三个面的法向量(法向量方向为背离立方体中心的平面);

step2:然后依次判断原点O在每个面的哪侧,如若在ABC面的外侧,则原点更接近ABC,用它作为新的单纯形;如果原点在所有面的内侧,则它一定在四面体内部,表明两个物体发生碰撞。

3. 3D code代码实现

code1

博客:Winter's Blog,github:IwEngine/IwEngine/include/iw/physics/impl at master · IainWinter/IwEngine (github.com)

code2

一个文件:gjktest/testopengl.cpp at main · matan45/gjktest (github.com)

code3

kevinmoran/GJK: Basic 3D collision detection implementation using the Gilbert–Johnson–Keerthi distance algorithm along with the Expanding Polytope Algorithm (github.com)

  • translate()原理

使用Vec3.transformMat4转换本地坐标为世界坐标,结果为2倍的本地坐标? - Creator 3.x - Cocos中文社区

世界坐标系和本地坐标系 - 快乐码原 | Yesmore

おすすめ

転載: blog.csdn.net/qq_27586341/article/details/129690850