從零開始學習導航網格#12 動態阻擋的處理

拖更了一年回來填坑??這應該是這個系列正文的最后一篇,之前的內容可以從這里找到
本篇主要分析一下項目中關于動態阻擋的處理方式,順帶對比回顧一下靜態導航網格的生成流程

recastnavigation中提供了3種模式的導航網格:

  • SoloMesh
  • TileMesh
  • TempObstacles

其中SoloMesh模式是靜態的導航網格,即對場景build一次之后,將導航網格緩存起來供尋路使用,后續不再允許場景的地形發生變化
TempObstacles模式可以支持向場景中動態添加或移除預設形狀的阻擋物,導航網格也會隨之更新(不過只支持添加阻擋物,而不支持添加新的可行走區域)
在處理動態阻擋時,由于單個阻擋對地圖的影響區域是有限的,所以會采用將地圖切割成多個固定大小的tile,以tile為單位進行網格的生成。這樣在添加或移除阻擋時,只需要處理與阻擋相交的tile,而不需要處理整個地圖
TileMesh也是靜態的導航網格,只是與SoloMesh相比它按tile來處理地圖,算是介于SoloMesh和TempObstacles之間的一種模式

在分析TempBostacles模式之前,我們先來回顧一下導航網格尋路的主體思路,這在任何模式下都是通用的:

1.將場景模型轉化為可行走面
2.將可行走面分割成凸多邊形集合
3.計算凸多邊形之間的聯通關系
4.在凸多邊形集合上規劃路徑

我們再來回顧一下SoloMesh是怎么具體實現這幾步的:

1.標記導入的場景3角網格的可行走面
標記可行走三角面
2.將三角面體素化,得到高度域
體素化
3.將高度域轉化成緊縮高度域
緊縮高度域
4.通過區域劃分算法合并緊縮高度域,得到連續的區域
合并區域
5.求出區域的外輪廓
外輪廓
6.由外輪廓得到凸多邊形集合
多邊形集合

TempObstacles與SoloMesh的差異主要體現在兩個方面:

1.按tile劃分處理地圖
2.在由緊縮高度域生成連續區域這一步中,加入通過阻擋物體剔除部分可行走空間的步驟

當動態阻擋被添加或移除時,會找到與阻擋相交的tile,并重新計算它的導航網格。
值得注意的是,生成高度域這一步只做一次,中間結果會以壓縮格式存儲在內存中。
這么做的意義,項目原作者Mikko Mononen大神在博客中是這樣解釋的:
將三角面體素化生成高度域這一步,會占據整個生成過程70%的時間,所以采用緩存的方式可以極大的加快動態生成導航網格的速度。而直接存儲高度域結果又會比較消耗內存,所以以壓縮存儲的方式來存儲(項目中使用fastLZ算法進行數據壓縮)。

Triangle voxelization is usually dominating facter when generating a tile. 
For example it takes 71.5% of the time to generate the highlighted tile in the test scene.

所以TempObstacles的運作流程大體是這樣的,分成預處理階段和更新處理階段:

Preprocess
for each tile
- rasterize static triangles
- find walkable cells
- mark areas
- store compressed heighfield

At Run Time
for a changed tile
- uncompressed heighfield
- mark obstacles
- build regions
- build contours
- build poly mesh
- build detail mesh
- store navmesh

如果之前已經對SoloMesh有比較好的掌握的話,理解起來TempObstacles應該還是沒有什么障礙的。
代碼中比較難讀懂的可能是這個函數(畢竟寫了快600行)

bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
                              const int borderSize, const int walkableHeight,
                              rcHeightfieldLayerSet& lset)

它的作用是得到層次區域化的緊縮高度域,實際上它與SoloMesh中區域劃分算法中的Layer partitoining算法幾乎一樣(我抄我自己)。我在這篇中單獨分析一下Layer partitoining算法,這里就不做贅述了。

最后再說一下tile對連通性的處理:
當一個tile發生變化時,會先從網格中移除這個tile,此時對每個與這個tile相鄰的其他tile,遍歷其中的多邊形,刪除與目標tile相關的連接
然后再將新的tile加入到目標位置,對該tile中的每個多邊形,遍歷周圍tile,判斷是否有鄰接的多邊形,若有則建立新的連接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容