CritterAI插件CritterAI與Recast Navigation尋路

 引用: https://www.cnblogs.com/MarkWoo/p/5211035.html

 

Unity中爲一個GameObject添加導航信息

  • 首先,需要爲GameObject添加一個NavMesh Agent(用於引導GameObject導航尋路,在component->Navigation中)
  • 然後需要在對應的Terran或者Plane中,選擇Navigation控件中進行Bake(烘焙)來產生導航網格路徑
  • Unity中使用A(A star)與Dijsktra*最短路徑算法結合來進行尋路轉向等操作

Unity導航尋路

  • 實際上Unity官方的導航尋路也是基於Recast Navigation並進行了深度改造,此開源庫的作者於2013年已經加入了Unity Inc

項目

導航網格的生成

  • 靜態導航網格可以藉助CritterAI插件在Unity中直接生成,這個比較簡單,生成導航網格的相關參數配置在下面的網格生成過程中的參數影響(Configuration Parameters)有詳細說明,對照說明進行配置即可,生成的導航網格數據可以同時給客戶端和服務器使用。
  • 真正的難點在於運行時的導航網格生成,具體做法和流程可以參見Recast Navigation的Demo,下面有詳細介紹

基本尋路流程

  • 點選一個實體進行對應位置的移動操作時,會首先調用PathAgent::setTargetPos,在這個函數裏面,會在其對應的尋路服務pPathFindService中調用GetPath來獲取對應的行走路徑
  • 獲取到路徑後,每個PathAgent裏面有一個用於保存行走路徑的變量m_pVec3StraightPath,該變量用於保存本PathAgent的需要進行行走的路徑
  • PathCrowd下面有一個update,這個函數在PathFindService::update裏面不斷地調用(實際上就是實時更新PathAgent的尋路狀態,其實時更新的頻率由傳入PathFindService::update的參數來定)

Recast Navigation

該庫使用十分廣泛,Unity引擎官方的尋路,unreal的UDK的尋路均基於Recast Navigation開發的

關於動態障礙的問題

RecastNavigation在特定設置下可以支持動態網格生成的,也就是說可以直接使用RecastNavigation來做動態障礙,如何做,詢問過RecastNavigation作者,他是這麼回答的:
QQ截圖20151124105735.png-44.3kB

  • 目前項目中現有的動態障礙使用的後一種方法,使用Tile Cache的方式實現的

RecastDetour

  • 在RecastDetour裏面有一個Sample_SoloMesh.cpp這樣一個簡單地demo,這個文件實現瞭如何建立導航網格的全部過程
  • 在RecastDetour裏面還有一個NavMeshTesterTool.cpp,這個文件則演示瞭如何使用前面建立的導航網格來進行尋路動作

Recast Demo

該Demo爲一個綜合性Demo,裏面所演示的內容十分全面(其註釋十分詳盡),下面簡要說明下目錄結構和主要文件,以及主要函數的功能,目前項目中所使用的導航以及導航網格生成動態障礙等等,其設計思想以及代碼流程都是基於該Demo所提供的方案,所以說完全弄透這套代碼基本導航網格尋路以及動態障礙就差不多了

目錄結構

Bin	//最終生成的可執行文件
Contrib	//一些第三方DLL
English.lproj 
Include	
Source
Icon.icns
Info.plist
premake4.lua //premake4的lua配置腳本,用於生成VS2010工程等
screenshot.png

主要文件

CrowdTool.cpp //管理實體移動尋路以及碰撞
NavMeshTesterTool.cpp // 演示Detour如何來尋找路徑,單純的尋找路徑
Sample_SoloMesh.cpp //演示如何來生成導航網格
Sample_TempObstacles.cpp //演示如何添加臨時障礙物對網格產生的影響,與動態障礙相關

關於Demo中的動態障礙

Demo中的動態障礙內容在Sample_TempObstacles.cpp,DetourTileCache.cpp,過程如下:

  • 首先,當在Demo中按下添加障礙時,會在Demo中調用Sample_TempObstacles::addTempObstacle,然後會生成一個ObstacleRequest,然後將這個request放入請求隊列當中去(實際上是個數組)
  • 隨後這個增加障礙物的請求依然會在一個updatedtTileCache::update)中進行,這個update更新的頻率也是按照設置的幀率來確定的,在這個update中,僅僅只做動態障礙相關的更新,比如去除障礙物,添加障礙物等,
  • update首先會對前面的request進行處理,然後纔會進行導航網格update
  • 導航網格的更新會在dtTileCache::buildNavMeshTile中進行,基本處理過程在代碼中有相應註釋,至此,動態地添加障礙物的處理過程完畢

相關參考資料:


CritterAI

CAINav基本結構

  • The Navmesh class defines the structure and state of the navigation mesh. The only user component that deals directly with this class on a regular basis is the component responsible for creating the mesh and managing its state. Normal navigation clients, the one's needing to perform pathfinding and such, rarely if ever interact directly with the navigation mesh.
  • The most important class to understand and become comfortable with is the NavmeshQuery class. It provides almost all of the client navigation features, including A* and Dijkstra path searches, string pulling, point and polygon searches, raycasting, etc.
  • The NavmeshQueryFilter is a seemingly minor class, but it has a large impact on navigation. Filters are used to define the costs of traversing the mesh and flags that control which parts of the navigation mesh are included in operations. Multiple filters can be used to customize the navigation behavior on a per client basis.
  • The PathCorridor class provides a way of moving along a navigation path without worrying about the minutiae of managing the path.
  • The CrowdManager is the big beast of the navigation classes. It not only handles a lot of the path management for you, but also local steering and dynamic avoidance between navigation clients. I.e. It can keep your agents from running into each other.

The Navigation Mesh

  • 即導航網格,爲導航系統的基礎數據模型
  • 包含以下幾個東西:
    • Tiles(導航塊,包含了主要的結構和狀態信息,導航塊是基於具有可塑性的導航網格所構成的,能夠在運行時進行變動,這意味着可以實現導航網格的動態變化)
    • Structural Elements(結構元素,兩種,多邊形和off-mesh connection)
    • State Data(狀態信息,用於關聯單個多邊形和off-mesh connection,包含areaflags,area被用於關聯在結構元素中通過所需的消耗,主要影響尋路。flags控制結構元素什麼時候是可通過的。)
    • Tile and Polygon References(理解導航塊和多邊形引用是熟悉導航網格的關鍵(後面用T&P代指導航塊和多邊形引用),T&P本質上來說是無符號整形用於控制導航網格中的結構元素,T&P是可以用來唯一確定多邊形或者off-mesh connection的標誌,導航網格結構控制着T&P的生命週期,改變導航網格的配置或者導航塊內部結構會導致T&P的無效,T&P可以在幾種情況下保存下來:
      • 導航塊狀態改變時保留下來
      • 運行時loading和unloading導航塊時保留
      • 導航網格在正常的序列化和反序列化期間)
    • 至於如何生成導航網格,請參考最下面的更加具體的參考資料

The Navigation Mesh Query

  • 按照CAINAV文檔的說法,這個是最重要最需要去熟悉理解的一個class,Navigation Mesh Query提供了用於pathfinding所必要的絕大多數特徵信息
  • 特徵,取得的特徵通常包含2大類:
    • Pathfinding
    • local search
  • 尋路依然是基於標準A*與德加斯特拉最短路徑算法(單源最短路徑)

The Path Corridor

  • 提供一個沿着導航路徑走的移動方式

The Crowd Manager(CrowdManager)

  • 簡介:擁塞管理器是導航組件中最龐大的一個,它不僅僅需要處理路徑管理,同時需要管理原地轉向和動態碰撞避免

  • 限制以及問題:

    • 最大的限制在於你必須給定被控制的導航代理實體的position以及速率給crowd manager,你能夠更新最大速度和最大加速度,但是爲了能夠讓crowd manager去完成他自己的工作,它不會准許你不斷地去覆蓋他的位置和速率,也就是說你無法直接控制導航代理實體的移動,這個控制權在crowd manager。
    • 第二個比較重要的限制是導航代理實體從一個當前的多邊形位置到達目標多邊形位置,中間所經過的多邊形位置的數量不准許超過256個,如果你超過了,那麼很有可能導航代理實體會導航失敗無法到達指定目的地,解決辦法在於在長距離導航路徑中間加入中間目的地,說白了太長了一次不行,就分段處理(分治法)。
    • 所有的導航代理實體使用相同的NavmeshQueryFilter
    • 擁塞管理器十分消耗性能,擁塞管理器一次最多能夠處理不超過20個導航代理實體
  • 更加具體的參考資料:

關於CritterAI中的尋路算法A*

A*尋路算法本身資料比較豐富,就不做過多贅述,通常網上給的資料中的A*尋路適用於網格爲方格子的情況,這裏CritterAI中的網格爲凸多邊形(多爲三角形)


網格生成過程中的參數影響(Configuration Parameters)

cellSize

  • 描述:> 0,設定體素(voxel)在X-Z-plane(OpenGL座標系)上的大小,決定體素(voxel)在對原始幾何圖形進行採樣時的精細度,值越小越精細,越大越粗略
  • 影響:較小的值能夠產生更加精確接近原始集合圖形的網格,減少在生成導航網格過程中生成多邊形產生較大偏離度的問題(詳見NavMesh的過程的Generate Detailed Mesh),但是會消耗更加多的處理時間和內存佔用,該設置爲核心設置,會影響其他所有的參數設置
  • 相關解釋:
    體素

cellHeight

  • 描述:> 0,體素(voxel)在Y-plane(OpenGL座標系)上的大小,決定體素(voxel)在對原始幾何圖形進行採樣時的精細度,值越小越精細,越大越粗略,僅影響Y-Axis上的圖形
  • 影響:較小的值能夠產生更加精確接近原始集合圖形的網格,減少在生成導航網格過程中生成多邊形產生較大偏離度的問題(詳見NavMesh的過程的Generate Detailed Mesh,但是與cellSize不一樣,較低的值並不會對內存消耗產生有顯著影響),有一點需要注意,較低的值雖然能夠使網格貼合原始圖形,但是如果是凹凸不平的地形,較低的值可能會造成鄰接的網格之間產生斷裂,導致本來應該連在一起的網格造成分離
  • cellHeight設置較高時,可以看到網格和原始圖形間距較大
    cellHeight-high
  • cellHeight設置較小時,可以看到網格和原始圖形貼合比較緊密
    cellHeight-low

minTraversableHeight

  • 描述:> 0, 最低可通過高度,設定從底部邊界到頂部邊界之間的最低高度,該高度爲模型可通過的高度

  • 影響:會影響場景中一些地形或者組件的可通過範圍,比如桌子,如果設定值過低,會導致模型高度就算高過桌子也會從桌子中間傳過去,設置過高會導致部分不被准許通過的場景也能穿過,另外一點,minTraversableHeight的設定值的大小至少得是cellHeight的2倍

  • 當minTraversableHeight設置恰當時,網格不會跑到桌子下面去

  • 當minTraversableHeight設置的值過低時,網格會跑到桌子下面去
    minTraversableHeight-lower

maxTraversableStep

  • 描述:> 0,可跨越不同地形時的高度,設定像是從普通平面移動到樓梯這樣的地形是否可通過的高度閥值

  • 影響:過低的值可能會導致無法通過原本可通過的地形,比如從平面到樓梯,導航網格生成時可能會發現樓梯的導航網格斷裂缺失,導致無法樓梯尋路,設定值過高會導致原本不該通過的小物件能夠被角色跨越,同樣,值設定必須大於cellHeight的2倍

  • 當maxTraversableStep設置的值比較恰當時,樓梯表面有網格生成

  • 當maxTraversableStep設置的值過低時,樓梯表面沒有網格生成

  • 當maxTraversableStep設置的值過高時,結果不需要有網格的地方也會生成網格

maxTraversableSlope

  • 描述:> 0,最大可通過的斜坡的傾斜度

  • 影響:過低的值會導致無法通過原本可通過的地形

  • 當maxTraversableSlope設置的值恰當時,網格能夠延生到斜面上去

  • 當maxTraversableSlope設置的值過低時,網格沒能延生到斜面上

clipLedges

  • 描述:None, 邊緣突出部分是否可以行走
  • 影響:

traversableAreaBorderSize

  • 描述:>= 0,可行走區域與阻擋物之前的距離大小

  • 影響:值設定必須大於cellSize的2倍才能產生效果(因爲導航網格的生成的實際上是建立在由voxel所組成的三維世界中),當開啓clipLedges時,實際的border會比較大

  • 當traversableAreaBorderSize > 0時,無法行走的邊界較大

  • 當traversableAreaBorderSize == 0時,無法行走的邊界幾乎沒有,很小
    traversableAreaBorderSize-littel

smoothingThreshold

  • 描述:>= 0,當產生用於表示派生區域的距離場時,會被使用該值,

  • 影響:這個值會影響區域的形成結構和border檢測,通常該值越大得到的區域會越大,該值越小產生的三角形越削瘦,該值還會是的border的尺寸變大,smoothingThreshold的值會直接影響border大小,當smoothingThreshold設置爲0時,border依靠在牆和欄杆邊,在相同的traversableAreaBorderSize值情況下,smoothingThreshold設置大於0時,會顯著增大邊界與牆壁或者欄杆的距離

  • 相關解釋:
    距離場:

  • 當smoothingThreshold == 0時,可以看到很多削長的三角形,同時網格邊界也是標準的
    smoothingThreshold-standard-border

  • 當smoothingThreshold == 2時,圖像中擁有更高的三角形結構,但是同時網格邊界也變大了

useConservativeExpansion

  • 描述:None, 應用一些算法來避免產生殘缺的區域
  • 影響:
  • 當沒有啓用useConservativeExpansion時,生成的區域會是一個複雜的多邊形區域,而且後面的三角化算法還沒法兒處理,這片區域會是鬆散的網格
    useConservativeExpansion-disable

minUnconnectedRegionSize

  • 描述:> 0, 最小的無法被連接的區域(這裏的區域指的是在網格生成之前,某些要與其他區域連接的區域)

  • 影響:當一個區域小於設定的這個minUnconnectedRegionSize,在生成網格時不會被考慮進去,也就是說這些區域上面不會生成網格

  • 舉個例子:在某些場景中,一些物件是不能被尋路的,比如固定場景中的一些岩石等等,當minUnconnectedRegionSize的值設置恰當時,在岩石等這些不能被尋路的物件上面不會生成網格,這樣尋路時就不會走這裏,當minUnconnectedRegionSize的值設置的過分小時,可能讓岩石也生成了一些孤立的小網格(在官方資料中被稱爲island,就像一些孤島一樣,這裏無法被尋路,但是確也生成了網格, 如果遊戲中准許actor通過瞬移的方式進入孤島,那麼這裏生產的nav網絡就是有意義的)

  • 當minUnconnectedRegionSize設置恰當時,桌面上不會生成網格,即桌面上不是可行走的

  • 當minUnconnectedRegionSize設置過低時,桌面上會生成一些沒有必要的網格
    minUnconnectedRegionSize-fault

mergeRegionSize

  • 描述:> 0, 合併區域尺寸,當一個區域小於該尺寸時,如果可以,則會被合併進一些大的區域

  • 影響:合理設置值可以規避一些區域產生算法生出一些不必要的小三角形的問題,當該值過小時,會產生一些又細又長的三角形,產生一些很細小的區域,需要把這個值設定到一個合理的大小

  • 當mergeRegionSize過小時,網格會有很多削長的三角形
    mergeRegionSize-lower

  • 當mergeRegionSize比較大時,足夠大到能夠消除一些削長三角形時

maxEdgeLength

  • 描述:>= 0, 指示網格邊界的多邊形最大的邊

  • 影響:當設置該值>0時,會在長的多邊形邊界上增加頂點,同時生產新的邊,這樣有助於減少相當數量的削長的三角形,當該值set to 0時,會關閉該特性

  • 當特性無效時

  • 當特性有效時

edgeMaxDeviation

  • 描述:>= 0, 網格邊界與原始集合圖形的偏離量

  • 影響:值越小,生成的網格三角形越多越密,也越貼近原始幾何圖形,同樣也會消耗更多的資源來做這些工作

  • 當表面邊緣匹配完全被關閉時

  • 當表面邊緣匹配被開啓時

maxVertsPerPoly

  • 描述:>= 3, 每個多邊形的最大頂點數
  • 影響:越高的值意味着越複雜的多邊形,也意味着越高的性能消耗,通常情況下6個頂點能夠平衡需求和性能

contourSampleDistance

  • 描述:>= 0, 設置採樣距離,類似遊戲中的凹凸貼圖類似概念,用於NavMesh過程中的Generate Detailed Mesh,匹配原始集合圖形表面的網格(利用生成更加精細的三角形保證網格來貼合那些凹凸不平的地表)

  • 影響:越高的值意味着越貼近原始幾何圖形表面的最終網格,也意味着越高的性能消耗,當值在0.9以下時會關閉這個特性

  • 當該特性關閉時,可以看到多邊形的邊緣一直沿着原始幾何圖形的表面,但是中央區域缺沒有網格

  • 當該特性設置爲中等程度時,可以發現添加了更多的三角形在中央網格區域
    contourSampleDistance_moderate

  • 當該特性設置爲高程度時,可以發現生成了更多三角形緊密貼合原始圖形

contourMaxDeviation

  • 描述:>= 0, 設置最大的採樣偏移距離,最好和contourSampleDistance結合起來看,其效果的精確度受到contourSampleDistance的影響
  • 影響:當contourSampleDistance爲0時,這個特性選項無效,在實際使用時發現在這個值越接近0,其生成的網格就越偏離原始圖形

  • Voxelization - Create a solid heightfield from the source geometry.
  • Generate Regions - Detect the top surface area of the solid heightfield and divide it up into regions of contiguous spans.
  • Generate Contours - Detect the contours of the regions and form them into simple polygons.
  • Generate Polygon Mesh - Sub-divide the contours into convex polygons.
  • Generate Detailed Mesh - Triangulate the polygon mesh and add height detail.

Voxelization(體素化)

Generate Regions

  • 生成各個多邊形區域(目前生成的多邊形有多個小網格組成,邊緣都還帶有網格,在下一步中會進行簡化),生成的區域主要爲簡單的多邊形(使用分水嶺算法生成),分水嶺算法還會生成很多NULL regions
  • 分水嶺算法基本在這一步驟中的基本過程,Using the watershed analogy, the spans which are furthest from a border represent the lowest points in the watershed. A border span represents the highest possible water level. The main loop iterates, starting at the lowest point in the watershed, then increments with each loop until the highest allowed water level is reached.

Generate Contours(Contour Generation Detail)

  • 生成各個多邊形的邊界輪廓並標記起來,在上一步驟中,生成的多邊形由於是由很多的小網格組成,則會有十分多的小網格頂點,這裏實際上不需要這麼多頂點,只需要不同區域之前劃分的邊界處的必要頂點即可,這裏需要通過Douglas-Peucker algorithm簡化這些邊緣輪廓,基本思路就是把多個必要點(mandatory vertices)之間密密麻麻的小點近似成一條直線,這條直線就是簡化後的不同的regions區域.

Convex Polygon Generation(Convex Polygon Generation)

  • 合併重複邊界輪廓信息,整合到網格里面去
  • (這一步驟中的主要重點工作)由於凹多邊形在對於導航網格而言是無用的,這一步驟需要對上面一步中生成的多邊形中的凹多邊形進行子分割其邊界輪廓,讓其分化成凸多邊形,主要步驟參考此步驟鏈接
  • 聚集各個多邊形之間的鄰接信息(即多邊形鄰接信息)

Detail Mesh Generation(Detail Mesh Generation)

  • 前面步驟中生成的多邊形網格在高度域上可能會與原始網格表現不一致(主要是在y軸方向上),生成的多邊形網格與原始網格會發生偏離,這一步中就是爲了修正這些偏移
  • 對於每一個多邊形:
    • 對多邊形進行外形邊緣進行採樣,爲那些偏離到一定高度補丁值得多邊形添加頂點,這些頂點用於採樣分割
    • 對多邊形進行德勞內三角化
    • 對多邊形內表面進行採樣,爲那些偏離到一定高度補丁值得多邊形添加頂點
    • 繼續對新增頂點的多邊形進行德勞內三角化
  • 更多信息參考上面此步驟鏈接
  • 相關知識:德勞內三角化(最大化三角形內其最小角的角度,避免出現極度"削瘦"的三角形),
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章