一種基於Cubic-Bezier的實時避障平滑路徑規劃方法
前幾天在做AI飛行物的路徑規劃(自動尋路)功能,對所用的方法進行一下總結。
本文提供一種將由實時生成的導航路徑點組成的折線路徑轉換為G1或C1連續的Cubic-Bezier拼接曲線的方法,並同時消除(大部分)轉換帶來的碰撞風險。
不涉及:
路徑點的生成
初始切線的制定規則
三次曲線的四點控制可以同時精確描述切入和切出時的位置引數,對於應用於遊戲的三維空間實時姿態控制來說,G1或C1連續的三次拼接曲線已經基本可以滿足絕大部分需求。由於實時規劃的侷限性,無法做到在動態避障的同時(採用不迴圈迭代的方法)利用三次貝塞爾曲線達到G2或C2連續。四次曲線是可以做到的,但是不在本文討論範圍。
二維空間的路徑點和由此拼接成的線段路徑和C1平滑的貝塞爾曲線
出於對效能的考量,應用於遊戲的路徑規劃一般都採用確定可行的折現路徑點,然後再對這個折現進行最佳化模擬出近似的平滑路徑效果的方法。
在由折現轉換為三次曲線的過程中,曲線變換所帶來的偏移會帶來新的碰撞風險。使用路徑點的尋路方法中,只有路徑點之間連線成的折線是安全的,所以一切偏離於折現的部分都要重新評估。
稍微鋪墊下貝塞爾相關方程:
t代表從起點到取樣點的弧長除以總弧長,也等於每個相鄰節點組成的線段上的取樣點掃過的距離的比例。所以
是Bernstein基函式,且正好等於順序無關成功率為t的事件進行n次,成功了i次的機率。它在曲線方程中出現看似巧合其實是必然。它是由貝塞爾曲線各線段取樣點的過渡性質決定的。
綠線代表貝塞爾曲線控制點組成的折線
三次拼接貝塞爾曲線的優勢:
可單獨對每一段曲線進行調整而不影響其他曲線段。路徑點確定後可按需生成路徑曲線:只生成當前取樣點所在曲線段即可。這意味著即使遇到每幀更新的極端情況,每幀需要計算和規劃的三次曲線也只有當前這一段而已。
三維空間三次貝塞爾曲線的“正檢視”
三維空間三次貝塞爾曲線的“側檢視”。四個控制點按順序依次為1234。
為了檢測曲線段是否有碰撞,可以採用生成凸包的碰撞檢測法。上圖是完整路徑規劃中分離出的一段三次貝塞爾曲線段,它由四個控制點組成。可以發現上圖這個由四個控制點組成的四面體就是一個凸包,但是它在2和3兩個頂點附近有大量的空間其實並不“包含”曲線。因此可以稱這兩點附近是“稀疏”的。在很多情況下,誤差都對“深度”更加敏感,即“無效的尖角”所到達的最遠距離對誤差的影響要比比在“非稀疏體積”附近的無效體積能造成的誤差更大,即使這個“無效的尖角”佔用了更少的體積。所以這種尖角是必須要被剔除的。
此時可以運用一些數學技巧找出這個四面體削掉兩個角形成的直角稜臺。使用此稜臺進行碰撞檢測,可有效提高碰撞檢測的精度。
稜臺的製作過程:
設當前貝塞爾曲線的首尾引數點的世界空間座標為P0,P1。
由起始引數點指向相鄰引數點的向量為T0, 由次末引數點指向末尾引數點的向量為T1。
則四個引數點的空間座標分別為:P0,P0+T0,P1-T1,P1。
帶入貝塞爾曲線函式
,其中n=3,
,可以得到此曲線的解析解:
空間連續,處處可導的三次函式的美妙之處在於,它的導數解析式是二次函式。對二次函式求極值想必所有看到這篇文章的人都已經滾瓜爛熟了。
曲線可能生成在空間中的任何位置和任何角度,所以首先要將控制點轉換到一個固定基底的相對座標系下。
如下圖:
X軸為首尾控制點的連線,從首控制點指向尾控制點。
Z軸的方向為P0P1和T0的叉乘方向。
Y軸為X軸和Z軸的叉乘方向。
從現在起,P0P1和T0T1均為在此相對座標系下的表示。
在此座標系下,
曲線從(0,0,0)始,於(dist(P0,P1),0,0)終,P0T0位於XY平面
,由此構建了一個便利的相對座標系。
對曲線求極值,極值中的Z和Y分量分別記為H1,H2。
偽公式:
面向X軸方向的正交檢視
如上圖所示,計算得到的H1和H2是切割後稜臺的寬和高,至此,構建稜臺所需的8個頂點的座標已經全部(直接或間接)已知。
使用H1H2從三稜錐中分離稜臺
此直角稜臺雖然即不是包裹曲線的最小六面體凸包,也不是最小包裹稜臺,但優勢是已經切掉了最稀疏的兩塊區域,且構建和計算都相當簡單,在大部分情況下和最小凸包或者最小稜臺的判斷精度已經差別不大了。
黃色線框為最小凸包在面向X軸正交檢視下的大致形狀(粗略手繪不精確)
粉色線框為最小稜臺在面向X軸正交檢視下的大致形狀(粗略手繪不精確)
由於T1和T2在H1H2面上的投影不是正交的(T1,T2正交作為一種特殊情況可以被包含在一般情況中處理),所以T1和T2的範數改變都能同時影響到H1和H2。鑑於此,在檢測到碰撞時,可直接對T1和T2進行同比例縮放。
為什麼可直接對T1和T2進行同比例縮放?
回顧貝塞爾曲線方程:
這是一個累加式。B可以簡單理解為某種機率公式。在某一時刻,
中
只有一次項。
這意味著當把方程轉化為座標的函式時,結果的座標分量和對應的自變數是線性相關的。
這樣就確保了這種縮放操作
不會破壞切線的方向,也就在避障的同時維持住了G1或者C1(C1所需的額外處理見下文)連續。
檢測到六面體碰撞發生時,採用二分法同步 縮放六面體H1和H2的值。然後用寬高縮放後的稜臺重新進行碰撞檢測。出於效能的考慮需要限制二分法迭代次數。大部分情況下,二次或三次迭代已經足夠了。然後直接將這個縮放值同時應用於T0和T1的縮放。
將H1H2縮放為原來的1/2,同時將T0和T1也縮放為原來的1/2,新稜臺仍為修改後貝塞爾曲線的包裹直角稜臺
在虛幻引擎中,這個稜臺可以用procedural mesh生成並執行碰撞檢測。
hint:若規劃的是飛行器飛行路徑,改變T0和T1的範數會影響飛行器經過時的角速度或角加速度,需要加入更多限制判斷條件。
當迭代指定次數後,所生成的無碰撞直角稜臺包裹的三階貝塞爾曲線段即為既滿足切入方向為T0,切出方向為T1,又可以大幅降低碰撞風險的G1連續曲線。(此時仍可能產生碰撞的條件是,碰撞體被完全包裹進稜臺中且與曲線有重疊,這一般透過改進路徑點查詢演算法可以有效解決)。
從G1進化到C1的方法也很簡單。只需要同時評估當前曲線段(P)和下一條曲線段(設為Q),因為
的方向已經確定(G1連續的必要條件),分別求出兩條曲線直角稜臺的縮放比率,取最小的那個同時應用於
和
即可。
二維投影下的原始貝塞爾,避障演算法處理後的G1和C1連續的貝塞爾的總路徑圖(實際上是隻生成當前的曲線段,不會去維護整條路徑曲線)。
未經避障處理的原始貝塞爾路徑
G1平滑處理的貝塞爾路徑
C1平滑處理的貝塞爾路徑
作圖工具:Blender