Learn 哔哩哔哩 「一見単純な複雑な問題、奇妙でエレガントな解決策 (GJK アルゴリズム) |
1. 凸形状と凹形状の基本的な考え方
図 1.1 に示すように、すべてのグラフィックスは凸面と凹面の 2 つのタイプに分類できます。
凸形状のプロパティは次のとおりです。
- 形状上の任意の 2 点を結ぶ線は形状の内側にある必要があり、凹型形状よりも扱いやすくなります。
- その形状上のすべての点について、テレビがこの方向の最も遠い点になるような方向が存在する必要があります。つまり、形状上のすべての可能な方向を横断し、その方向の最も遠い点を見つけると、必然的に形状上のすべての点が取得されます。
凹形状は上記の性質に従わないため、凹形状を扱う場合は複数の凸形状に分割して計算を簡略化し、形状間の交差判定をすべて凸形状の交差問題に変換することができます。
2. 2 つの形状の交差に関連する特徴
2つの図形の交点の判定に「原点」という概念が現れる理由を図2.1に示します。2つの凸形状が交わるとき、その差分を原点とする2つの点(ベクトル)が存在するはずであり、これは2つの間に交点があることの証明でもある。
上述の「原点」解法は、ミンコフスキー和/差分(ミンコフスキー和/差分)の概念をさらに提案しています。
2.1 ミンコフスキー和/差
ミンコフスキー和: 1 つの形状内のすべてのポイントを別の形状内のすべてのポイントに加算します。そして、各形状上の各点は原点から始まるベクトルとして扱われます。
ミンコフスキー差: ある形状内のすべてのポイントから、別の形状内のすべてのポイントを減算します。
ミンコフスキー差には次の 2 つの特性もあります。
- 2 つの凸形状のミンコフスキー差によって得られる形状も凸です。これは、凸形状の性質に従って、任意の 2 点の線がミンコフスキー差に存在する必要があることを意味します。
- 2 つの形状が交差する場合、それらのミンコフスキー差には原点が含まれている必要があります。つまり、2 つの形状には少なくとも 1 つの共通点があります (図 3 と同じ原理)。
したがって、2つの形状の交点を判断する問題は、2つの形状のミンコフスキー差分に原点が含まれるかどうかを判断する問題となる。
2 つの凸形状 A と B の 3 点の差を選択して三角形を形成します (これらの 3 辺はミンコフスキー差内になければなりません); 原点が三角形に含まれる場合は、原点もミンコフスキー差内に存在する必要があることを意味しますとすると、図形Aと図形Bが交差していると判断できます。
したがって、2 つの形状の交点を判断する問題は、凸形状 A と B のミンコフスキー差の中に、原点付近の三角形 (つまり、原点を含む三角形) を形成する 3 つの点が見つかるかどうかというようにさらに単純化されます。図 2.5 に示します。この三角形はシンプレックスと呼ばれます。
2.2 単一行 (シンプレックス)
異なる次元では、単一の行の形状は同じではありません。2D では、単一の行は三角形であり、3D では、単一の行は四面体です。
2.3 サポート機能(サポート機能)
凸形状の特徴 2 によれば、凸形状上の点に方向をマッピングすることができ、方向ベクトルを形状上の最も遠い点にマッピングする関数をサポート関数と呼び、対応する点をサポート関数と呼びます。サポートポイント。
このサポート関数の非常に興味深い点は、2 つの凸サポート関数を追加すると、そのミンコフスキー和のサポート関数とサポート ポイントが得られることです。
ミンコフスキー差に直面する場合、最初の凸形状 A のベクトル方向を指定してそのサポート ポイントを見つけます。次に、この方向の反対方向を 2 番目の凸形状 B 上の方向として使用して、凸形状 B 上のサポート ポイントを見つけます。これら 2 つの点の減算が、ミンコフスキー差境界上のサポート ポイントです。これは、ミンコフスキー差の原点を含む三角形を見つけるのに役立ちます。
興味深いことに、図 2.7-2.8 を観察すると、ミンコフスキー和の支点を見つける場合、凸形状 A と B 上で選択された方向は同じであり、ミンコフスキー差の支点を見つける場合、凸形状A、Bで選択した方向が左右逆になります。この違いの原因は、ミンコフスキーと貧困そのものの定義に関係しています。
サポート関数の計算:
サポート関数は、凸エッジによって指定された方向 d の最も遠い点 v を返します。図 2.9 の式に示すように、内積は 2 つのベクトル間の方向の類似性を測定できます。2 つのベクトルの方向が類似しているほど、内積の値は大きくなり、一方向の点が遠くなります。内積が大きくなります。この特性により、サポート ポイントを解決することが可能になります。
3. GJK アルゴリズムとその実装の詳細
3.1 GJK アルゴリズム
1. まず、ランダムな方向を選択し、この方向のサポート ポイント (シンプレックスの最初のポイント) を見つけます。
2. 現在のサポート ポイントをベクトルの開始点とし、原点を指すベクトルを新しい方向 d として見つけ、2 番目のサポート ポイントを見つけます。
3. 2 番目のサポート ポイントと現在の方向 d の内積結果が 0 より小さいかどうかを判断します。内積の性質により、必要な 2 つのベクトルの内積が 0 以上であり、2 つのベクトル間の角度が [0°, 90°] であることがわかります。2 つの形状が交差する場合、原点と第 2 支点によって形成されるベクトルと現在の方向 d との間の角度は [0°, 90° ] となり、第 2 支点の位置の妥当な範囲が示されます。図 3.0 の青い領域にあります。
1) 2 番目のサポート ポイントと方向 d の内積が 0 未満の場合、現在の反復方向で原点を横切ることができるサポート ポイントがないこと、つまり 2 番目のサポート ポイントが方向 d に該当しないことを意味します。図 3.0 の青い領域では、2 つの形状が交差していないため、GJK アルゴリズムが終了します。
2) 逆に、現在の 2 番目のサポート ポイントをシンプレックスに追加します。
4. 2 番目のサポート ポイントが妥当な場合、2 つのサポート ポイントは直線に接続され、その線に垂直なベクトルが新しい方向 d になり、新しいサポート ポイントは三角形を形成するように計算されます。
5. 現在の三角形に原点が含まれているかどうかを確認します。交差する場合、2 つの図形は交差します。そうでない場合は、方向を更新して、新しいサポート ポイントを追加します。原点に最も近い三角形の辺の垂直ベクトルを選択し、この辺の 2 点を保持し、残りの 1 点を削除して、この垂直ベクトルを新しい方向として使用します。 d 3 番目のサポート ポイントを再度見つけて、次回実行します。反復と判断。
3.2 実装の詳細
質問:
- ミンコフスキー差上の点が原点と交差しているかどうかはどうやってわかりますか?
- 2 つのポイントがある場合、新しい方向を選択するにはどうすればよいでしょうか?
- 現在形成されている三角形に原点が含まれているかどうかをどのように検出できるでしょうか?
- 現在の三角形に原点が含まれていない場合、次の方向を選択するにはどうすればよいですか
質問 1: ミンコフスキー差上の点が原点と交差しているかどうかを確認するにはどうすればよいですか?
図 3.1 のように点 A が原点を通過するかどうかを確認します。原点から点 A はベクトルと見なされ、ベクトルと方向 d の内積によって判断され、内積が負の場合、現在の点は原点を通過しません。そうでない場合は、その逆です。
質問 2: 2 つのポイントがある場合、新しい方向を選択するにはどうすればよいですか?
まず、勝ち点が2つある場合、A点が最後に追加された点、B点が最初に追加された点となることが多いです。まずベクトル AO(OA) とベクトル AB(BA) を構築し、これら 2 つのベクトルに垂直で垂直上向きのベクトルを 2 つのベクトルの相互乗算によって解きます。次に、垂直ベクトルとベクトル AB Vector (3 倍の積) を解きます。これは、私たちが言及した新しい方向性です。
質問 3 と質問 4: 現在形成されている三角形に原点が含まれているかどうかを検出するにはどうすればよいですか? 現在の三角形に原点が含まれていない場合、次の方向をどのように選択すればよいでしょうか?
三角形を形成する 3 つの点 A、B、C (多くの場合、A は最後に追加されたサポート点) があり、三角形の各辺に垂直線を引いて空間の面積を定義すると仮定します。 、ボロノイ領域を形成します。B 点 1 と C が固定されていると仮定すると、点 A のすべての可能な位置が与えられると、対応する領域も変化します。起源がどの領域に行き着く可能性が高いかを判断するには、それを分析する必要があります。
3.1. 起源を含むことができない領域とその分析:
Rc: サポート ポイント C が最初のサポート ポイントであるため、次のサポート ポイントを選択する場合は、ポイント C を開始点として取り、原点を次の新しい方向 d としてポイントしてサポート ポイントを見つける必要があります。は、Rc とは反対方向に原点に向かって探索することを意味するため、原点は Rc 内に存在することはできません。
Rb: 原点が Rb にある場合は、現在のシンプレックスが無効であり、現在選択されている点 B が無効であるため、点 B が原点を超えることができないことを意味します。
Ra: 原点が Ra にある場合は、現在のシンプレックスが無効であり、現在選択されている点 A が無効であるため、点 A が原点を超えることができないことを意味します。
Rbc: Rbc には原点が含まれる可能性がないため、BC の方向の垂直線は、Rbc の方向とは完全に反対の点 A を見つけるために使用されます。
3.2. 原点とその分析が含まれる領域かどうかを確認する必要があります。
Rab: 点 A が有効な点になると、原点を特定の方向に横切る (つまり、原点を含む) 場合、点 A が位置する領域は図 3.6 に示されます。この範囲では、Rab は原点を含む可能性があります。
上記の予想を検証するために、三積定理によって AB に垂直なベクトルを定義します。現在の垂直ベクトルとベクトル A0 の内積が 0 より大きい場合、原点は Rab にあることを意味します。シンプレックスは適切ではありません。このシンプレックスを再選択して更新する必要があります。シンプレックスから点 C を削除し、AB に垂直なベクトルが 3 番目のサポート ポイントを見つけるための新しい方向 d として使用されるため、Rab がチェックする必要があります。
Rac: この領域のチェック ロジックは Rab と同様で、原点が Rac にある場合は、現在の点 B を削除し、点を再選択します。
最も重要な領域チェックの 1 つは次のとおりです。
Rab と Rac の 2 つの領域のみがチェックされます。Rab 領域と Rac 領域のどちらにも原点が含まれていない場合、つまり、AB および AC に垂直なベクトルとベクトル AO の内積が 0 より小さい場合、現在の原点が残りの Rabc にあることを意味します。
3.3 GJK アルゴリズムの詳細
def GJK(s1,s2)
#两个形状s1,s2相交则返回True。所有的向量/点都是三维的,例如([x,y,0])
#第一步:选择一个初始方向,这个初始方向可以是随机选择的,但通常来说是两个形状中心之间的向量,即:
d= normalize(s2.center-s1.center)
#第二步:找到支撑点,即第一个支撑点
simplex=[support(s1,s2,d)]
#第三步:找到第一个支撑点后,以第一个支撑点为起点指向原点O的方向为新方向d
d=ORIGIN-simplex[0]
#第四步:开始循环,找下一个支撑点
while True
A=[support(s1,s2,d)]
#当新的支撑点A没有经过原点,那我们就返回False,即两个形状没有相交
if dot(A,d) <0:
return False
#否则,我们就将该点A加入到simplex中
simplex.append(A)
#handleSimplex负责主要逻辑部分。主要负责处理寻找新方向和更新simplex的逻辑内容,当当前simplex包含原点,则返回Ture
if handleSimplex(simplex,d):
return Ture
def handleSimplex(simplex,d)
#如果当前的simplex为直线情况,则进入lineCase(simplex,d)函数,寻找下一个方向d,并返回False,即直线情况下的simplex不包含原点
if len(simplex==2):
return lineCase(simplex,d)
#如果当前的simplex为三角情况,则进入triangleCase(simplex,d,
return triangleCase(simplex,d)
def lineCase(simplex,d)
#构建向量AB与AO,并使用三重积得到下一个方向
B,A = simplex
AB,AO=B-A,ORIGIN-A
ABprep= tripleProd(AB,AO,AB)
d.set(ABprep)
#由于一条直线的情况下,原点不能包含在simplex中,所以返回False
return False
def triangleCase(simplex,d)
#构建向量AB,AC与AO,并来检测原点在空间的哪个区域。
C,B,A = simplex
AB,AC,AO=B-A,C-A,ORIGIN-A
#通过三重积分别得到垂直于AB、AC的向量,检测区域Rab、Rac中是否包含原点。
ABprep= tripleProd(AC,AB,AB)
ACprep= tripleProd(AB,AC,AC)
#如果原点在AB区域中,我们移除点C以寻找更加完美的simplex,新的方向就是垂直于AB的向量
if dot(ABprep,AO)>0:
simplex.remove(C);d.set(ABprep)
return False
#如果原点在AC区域中,我们移除点B以寻找更加完美的simplex,新的方向就是垂直于AC的向量
elif dot(ACprep,AO)>0:
simplex.remove(Ba);d.set(ACprep)
return False
#如果这两种情况都不符合,那就说明当前的三角形中包含原点,两个形状相交
return Ture
def support(s1,s2,d)
#取第一个形状上方向d上最远点并减去第二个形状上相反反向(-d)上最远的点
return s1.furthestPoint(d)-s2.furthestPoint(-d)
私の理解と記憶を強化するために、侵害の問題が含まれる場合は、私に連絡してください。削除します~