2022年6月8日 星期三

關於超大地圖Recastnavigation尋路資料建立的做法

 由於專案有複雜超大地圖(unity單位15000*15000)的需求,在Recast資料建立上遇到了一些問題…

  1. 整塊大地建立不出來,發生了以下的錯誤…
    if (maxVertices >= 0xfffe)
    {
            ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices);
            return false;
    }
  2. 就算是分了區塊,但因為Recast底層建立的函式,無法並行建立,所以造成了建立時間過久的狀況(超過一天以上)
解決方案:
  1. 自行實作一個建立console工具程式,並用批次檔來運行多個執行檔,來達到並行建立區塊的目的。
  2. 最後將相關的區塊移到unity裡來進行彙整,並輸出跨區域尋路的整塊地圖。
利用美術的相關模型生成柱狀體檔格資料:(原本可以直接使用美術的mesh直接生成,但因為資料容易有不合法的問題及因為專案只需要2D的尋路,所以為了減少生成問題,使用了這個方式)




















利用外包計算(其實只是做格子的拜訪)的演算法,來算出各區塊的包覆範圍,分割地圖區塊:


將各個Console程式計算的區塊地圖彙整到unity,進行地圖合併及提供之後計算跨區域路線計算:



















計算跨區域路線,並存檔,完工…



















後記:實測建立時間可以節省2/3以上,目前覺得還要回來unity進行合併,多了一個步驟,不知道之後有沒辦法分塊,合併及路線計算能在一個步驟就完成,以下是相關的視頻:

2021年10月27日 星期三

關於GPUInstance與GPU VS CPU culling的恩怨情仇

大家應該都知道GPUInstance是拿來畫大量物件的重要利器,但他最大的問題,就是沒有處理Culling,當拿來畫同一種巨量草之類的,面數少的話,應該是沒什麼問題(同種類,只需傳送一次Mesh資料,數量多的話,因為面數少,所以vertex shader處理次數少,也還ok)。但當我們把鏡頭拉近的時候,其實剔除處理就變得很重要,否則有可能GPU instance會比一般用page culling的drawMesh API性能還來得差…


那我們如果幫GPUInstance也切page的話,情況就會變好嗎?其實不一定,在拉近的時候,太多數的情況是還蠻OK的,但如果有拉遠鏡頭的需求,會導致DrawInstance的API呼叫次數變多,進而導致mesh傳輸量增加,這種狀況下反而切page變成是一種負優化…

最近比較流行的是直接使用GPU+ComputeShader來做GPU culling,並搭配DrawMeshInstancedIndirect這個API來畫,聽起來似乎是蠻理想的方案,但他最大的問題,就是當鏡頭拉近的時候,如果種類非常多,由於數量是由GPU直接算出來的,CPU完全不知道,所以還是得直接呼叫DrawMeshInstancedIndirect這個API來畫,就算GPU算出來的數量是零,還是導致了把mesh傳輸到GPU,造成了負優化,尤其是當種類越多,這個問題會越嚴重…另外還有硬體支持度的問題…

所以種類物件越多的場景,如果想全場景GPU instance化來提升性能,目前可以想得到的方式就是使用CPU+JobSystem來處理剔除,整個處理流程如下:

  1. Page Culling,看是要用八元樹還是四元樹,請隨意
  2. 依CullingPageList,將其送到JobSystem來進行剔除處理
  3. 等Job IsCompleted後,將其資料拷貝到相關要畫的陣列中(動態蒐集陣列資料)
  4. 畫出所有instancer的物件(這時候只會畫真正在視野範圍內的物件)


試著在紅米三,種類高達127種,測試物件數量高達到30000個左右的正式場景,物件面數約幾百面到2000面左右,有搭配LOD來優化,鏡頭不論遠近,FPS幾乎都頂在60(在優化前,是使用一般的DrawMesh+PageCuling,性能從35~40提升到頂60),目前也支持跨硬體API的架構(也就是會視硬體狀況,自動切換DrawMeshInstancedProcedural、DrawMeshInstanced、DrawMesh API,而且Shader都是同一個,目前的狀況是會多了一個變體),以下的測試案例是100個種類,250000個物件,相關運作狀況的影片,請參考…

2021年10月7日 星期四

檢查地表混合範圍的功能來提升性能

基於目前的地表渲染Shader,由於地表混合要讀多張貼圖,另外在混合計算上也比較花性能,所以做了一個可以檢測目前地表混合權重不為1的範圍有那些,如果能將其大部份的狀況下,只保持邊緣的地方有混色的話,可以大幅提升在中低階手機的性能,概念是這樣…
//如果第二層的權重小於等於零,直接回傳第一層tileMap的顏色,不進行混色處理
if (subMapWeightRatio <= 0)
    return mainMapColor;
相關影片如下:

2021年9月8日 星期三

The Terrain Instance Editor

在Unity裡蠻常看到先用一般物件放好,再轉instance資料的做法來編輯instance場景物件,這種方式非常不便利,而且當物件一多的時候,編輯性能就會很差,沒辦法體現GPU instance的威力…

由於目前少有直接可以編輯Instance的編輯器,所以只好硬著頭皮自己寫一個,這個算是目前從發佈第一個Unity開發相關影片(2016/8/19)以來,覺得相對做得比較完整的編輯器,目前支持Terrain 、 Vegetation splatting,以及paint per instance and adjust transform…等功能,相關影片如下:

2021年8月26日 星期四

大地圖多筆刷需求的解決方案

Unity的Terrain系統的splatting功能,如果要支持超過四層筆刷的話,就只能一直開更多張的control map,不然就是要分成不同的terrain page,但page跟page之類的過渡,可能又需要占掉一個筆刷來處理,所以基本上不是一個好的多筆刷支持方案。

有一種方式,是直接在contol map的rgba通道中直接記錄筆刷的index,這樣一來就可以支持比較多的筆刷,他的設計理念是R、G通道記錄texture index,B通道記錄G通道的weight ratio,然後利用weight ratio來決定怎麼做混色,而平常weight ratio為零的時候,就直接return R通道的結果來優化掉混色的相關處理,測試過之後,效果還不錯,因此為他寫了一個編輯器。

相關的編輯視頻如下:

2021年8月18日 星期三

使用Smooth tile processing來解決重複感的問題

在戰爭策略遊戲的上帝視角,在拉遠的時候,常常會看到地表重複感的問題,常看到手法是使用隨機或美術手工拼接Tile uv旋轉來解決,雖然可以解決重複格子感的問題,但格子感的問題仍無法解決。

如果這時候動態依照鏡頭的高度直接調整tile值,也不是一個好的方案,會造成跳動感,這裡導入了Smooth tile processing來解決重複感的問題,相關效果如下:

2021年8月5日 星期四

巨量骨骼蒙皮角色解決方案-GPU skin+GPU instacing+GPU culling+CPU job

 傳統的CPU端bone skin轉成在GPU端做是良好的大量骨格角色解決方案,加上了GPU instacing之後,大量減少了傳輸數據,性能可以再往上提升,不過由於沒有做到完整的剔除,導致處理了過多的vertex資料,也造成了性能不佳。

這裡再加上了GPU culling來做剔除處理,大大減少了處理vertex的數量,性能往上提升非常多,但由於transform處理邏輯(這邊是用旋轉來當例子)在CPU端做,導致了不少的CPU bounds,影響了性能,所以又加上了Job system來處理這一部份,性能又往上提升了一個層次…

相關影片如下…