NavMesh生成研究(五):細節網格生成
這篇文章描述了構造導航網格過程中的第五步,也就是最後一步:帶有高度細節資訊的三角網格的生成。
源資料類:PolyMeshField
和 OpenHeightField
構造類:DetailMeshBuilder
資料類:TriangleMesh
如果你需要回憶這一步的大致過程,請回到總體概述。
為什麼需要這一步
如果源網格的可行走表面被投影到xz平面上,且被前一個步驟中生成的多邊形網格覆蓋,那麼這兩者能很好地匹配。但是在3維空間中,多邊形網格可能不會與源網格的高度輪廓恰好一致。這一階段增加了高度細節,使得細節網格能夠在三維上匹配源網格的表面。為了實現這個目標,我們遍歷所有的多邊形,只要多邊形過度偏離源網格,就在多邊形的邊和內部插入頂點。
在下面的例子中,靠近樓梯的多邊形網格在xz平面上匹配,但是在y軸上偏離了很多。
當高度細節加入後,在y軸上匹配得更好了。
從技術上來說,這一步對於尋路不是必需的。我們真正所需的只是一個凸多邊形網格,它用來生成尋路演算法相關的圖——上一階段中建立的多邊形網格已經提供了所有必要的資料。某些場合尤其如此——例如使用物理或者射線將尋路代理放置在源網格的表面上。事實上,Recast Navigation的Detour庫只使用了多邊形網格做尋路。當前步驟中生成的高度細節是可選的,若包括進去,則只是用於優化各種Detour函式計算出的頂點位置。
同時需要注意的是,這個過程也只是生成對原始網格表面的一個更好估算。體素化決定了無法得到完全精確的位置。除此以外,考慮到效能和記憶體的影響,高度細節過多往往會比過少更糟糕。
第一步:高度補丁(height patch)
你這樣就以為無需體素空間和高度域了?不完全是這樣。為了加入高度細節,我們需要能夠確定多邊形的表面是否與覆蓋它的開放高度域區間離得足夠遠。高度補丁就是用於這個目的。它包含與一個多邊形相交的每個開放高度域格子位置的期望高度。基本上,它是開放高度域某一部分的簡單裁剪,帶有下列特徵:
- 它只包含單個多邊形的AABB包圍盒的高度資訊。
- 它只包含每個格子位置的底部高度(無區間)。
- 它只對每個格子位置有單個高度(無覆蓋)。
總覽
當前階段的主要步驟如下:對於每個多邊形來說,
- 對多邊形的外邊取樣。若這條邊偏離高度補丁大於
contourMaxDeviation
- 對多邊形執行德勞內三角化(Delaunay triangulation)。
對多邊形的內部表面取樣。若表面偏離高度補丁大於
contourMaxDeviation
值,則新增頂點。對於任何新頂點更新三角化。給多邊形的邊新增細節
這一步更好地匹配資料在高度補丁裡的多邊形的邊的高度。它是兩個取樣過程的第一步,第二步是處理多邊形表面。
接下來從2D角度看。在下面一組圖中,我們從沿y軸上升的那一側來看網格。
對於多邊形的每條邊:基於contourSampleDistance
的值將邊切割成線段。例如:如果邊長10個單位,取樣距離是2個單位,那麼將邊切割成5條等長的線段。這裡的“取樣頂點”並非全部會被用到,它們只是可能的頂點。
使用高度補丁資料,將每個取樣頂點的高度(y值)快照到高度域中。
檢查取樣頂點到原始邊之間的距離。若超過最大偏離,則插入離原始邊最遠的取樣頂點。
重複距離檢查,直到多邊形新的部分已完成。
三角化
網上有大量關於德勞內三角化的資訊,因此我們不再贅述,唯一想說的就是:在給邊新增細節後,它被用來對多邊形做三角化。到此為止原始多邊形不復存在。所有的操作都是針對三角形網格。
這是多個可能的三角化的第一步。從這一步開始,當任意新的頂點加入到網格中時,三角化將會發生。
給內部多邊形表面新增細節
到此為止我們從單個多邊形得到了較小的三角形網格。(或者,如果原始的多邊形就是三角形,而且沒有新的頂點在邊的細節這一步加入,那麼我們仍然擁有一個三角形。)所有的頂點仍然在網格的邊上。在這一步中,我們檢查網格的內部表面,看它是否與高度補丁中的資料偏離太多。
下面一組圖仍然是2D的。但是我們切換到xz平面的俯視視角。
新增高度細節到三角形網格的內部表面與新增到邊上類似。取樣頂點的格子沿著網格的AABB包圍盒所在的xz平面被構建。間距基於contourSampleDistance
的值。取樣頂點的y軸的值被快照儲存到高度補丁裡的資料中。
網格外部的取樣頂點被丟棄掉。
在剩餘的取樣頂點中,找到離三角形網格的表面最遠的那個。如果它比contourMaxDeviation
的值更遠,那麼就將它加入網格中,並重新三角化。
重複這個過程,直到再沒有采樣頂點超過contourMaxDeviation
的值。
結尾
這一步中的其他工作屬於事務性工作。由獨立多邊形建立的細節三角形網格被合併成單個網格,並被載入到TriangleMesh
的例項中。整個過程就此完結。我們得到了最終的導航網格。