python碰撞檢測演算法 GJK碰撞檢測演算法

2021-10-19 03:28:00 字數 2354 閱讀 6582

現實世界裡我們對於是否碰撞的判斷可以說極其容易而且準確,比如下圖。在二進位制的世界裡,一切就沒這麼直觀了。

gjk(gilbert-johnson-keerthi distance algorithm)

gjk 就是此次要實現的碰撞檢測演算法。如果對碰撞演算法有過了解的話,大概率聽過另乙個碰撞檢測演算法 sat(separating axis theorem)。

gjk 相較於 sat 有什麼優點嗎?快簡單

實際上就我目前了解的碰撞檢測演算法,應用物件都是凸多邊形(convex polygon)。如果不是凸多邊形,問題也不大,可以事先分割。

minkowski difference

由於不知道 min 到底是「明」還是「閔」,所以下面都用 md 表示了。

md 是 gjk 演算法的理論基礎。那麼到底什麼是 md ?

假設有兩個凸多邊形:

s1 =[,,,]

s2 =[,,]

那麼它們的位置看起應該像下圖這樣。

md 就是 s1 與 s2 所有點的差形成的集合。

md(s1, s2):

s3 =for p1 in s1:for p2 in s2:

s3.push(p1 - p2)return s3

md(s1, s2)=>[,,,,,,,,,,,]

這些點的布局如下圖所示:

關鍵的地方來了。首先要介紹乙個新的概念叫 convex hull。

convex hull 是包含點集的最小凸多邊形。拿上面的例子來說:

鋪墊了這麼久,現在可以說結論了。

我們把 s1 - s2 點集形成的 convex hull 命名為 s3。如果 s3 包含點 (0, 0),那麼 s1 和 s2 發生碰撞。

有沒有覺得很簡單?對,原理就是這麼簡單。

functionwrap(points)for(const p of points)let i =0, end

while(true)}

i +=1

current = end

if(end.x === hull[0].x && end.y === hull[0].y)break}return hull

最後就是判斷點是否在多邊形內的演算法了,可以看我之前的文章。

互動示例

思考有小夥伴不禁要問:這樣的巢狀迴圈真的比 sat 快?確實,上面的實現並不是真正意義上的 gjk 演算法。但是核心思想是一樣的:

如果兩個凸多邊形的 minkowski difference 所形成的 convex hull 包含點 (0, 0),那麼這兩個凸多邊形相交。

怎麼優化這個實現呢?

我們只需要盡早的從已知的條件裡判斷出是否包含原點即可。

真正的 gjk 演算法用了乙個很取巧的方式來減少迴圈次數,而且效果很理想。當然這也是下篇文章裡的內容了。

感興趣的小夥伴也可以從下面的參考資料裡先嘗試一波。

參考資料

國際慣例先放圖。

gjk 是怎麼快速判斷出這兩個圖形是否碰撞的呢?

support function

support function 用來計算凸體在給定方向上的最遠點。什麼意思呢?

圖示中的例子帶入,可以得到 (9, 6) = (0, 4) - (-9, -2),正是圖二三角形的乙個頂點。

將方向取反再呼叫 getsupport,我們可以得到 (-1, -2) = (-6, 0) - (-5, 2),也是圖二三角形的乙個頂點。

這樣做的意義是什麼呢?因為可以確保我們所取的兩個點跨度足夠大,有更大的概率包含原點,減少迴圈次數。

那麼問題來了:

初始給定的方向是怎麼來的?

已經獲取了兩個點,那麼第三個點如何確定呢?

通過 a(9, 6),b(-1, -2),可以計算出垂直於向量 ab(-10, -8) 且指向原點方向的向量,這個向量將會作為 direction 來獲取第三個點。

這裡要用到向量積來計算出 direction。

**片段

核心演算法

獲取到三個點後,我們需要判斷原點的是否在這三個所形成的多邊形內。如果在說明碰撞,不在則剔除乙個點後繼續尋找下乙個點。

上面這種情況:w * ao < 0,說明原點在 ab 內部,則驗證剩餘的邊(實際上不需要驗證所有的邊)。假如我開始獲取到的兩個點是 b,c,則我們只需要驗證 ab,ac,因為原點一定在 bc 內部。

這裡的關鍵點在於:如何計算出垂直於 ab 且指向遠離點 c 的方向的向量 w ?

直接貼**了,畢竟也解釋不了為何是這樣的運算順序。

**片段

互動示例

上面只是介紹了我覺得實現 gjk 演算法中比較重要的點。整個流程可能並不夠清晰,所以這裡附上完整的步驟分解示例。

總結gjk 演算法並不複雜,完整的**不到 200 行。主要用到的數學知識是數量積和向量積。

參考資料

碰撞檢測 膠囊體碰撞檢測

膠囊體 給定一條線段l,所有道l的距離為r的點的集合。由定義可知,膠囊體由半徑r和線段l標識。檢測兩個膠囊體是否發生碰撞,即檢測兩條線段l1 l2的最短距離d是否大於l1 l2的半徑r1 r2之和,d r1 r2 則未碰撞,否則發生碰撞。設線段l1端點為a1 a2,線段l2端點為b1 b2,號表示兩...

H5 JS 遊戲常用演算法 碰撞檢測 畫素檢測演算法

使用畫素碰撞檢測法算是最精確的演算法了,當然,帶來的代價也是比較明顯的,那就是效率上的低下。除非是在極為特殊的情況下,要求使用非常精確的碰撞,否則,一般情況下在遊戲中是不建議使用這種演算法,特別是在執行效率不太高的html5遊戲中。一般來說在使用畫素碰撞檢測之前會使用aabb矩形包圍盒先檢測兩個精靈...

Unity碰撞檢測

碰撞個必要條件為兩個角色必須都掛載 rigibody 剛體元件,至少乙個角色掛載 collider指令碼 第一種 觸發器,必須開啟 collider的 istrigger 為 true 兩個碰撞物件會相互穿過 void ontriggerenter collider collider 開始觸發器 v...