精選文章

SmallBurger Asset Home

  SmallBurger

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個物件,相關運作狀況的影片,請參考…



Dream continues in...

沒有留言:

張貼留言