GPUInstance

请明月發表於2024-10-18

關於GPUInstance
1.用於渲染加速的硬體特性.
gpu硬體支援的一種特性,使用少量的渲染呼叫(DrawCall)渲染同一網格的多個副本.也就是說在渲染時,他只需要提交一個網格副本,一個材質球,然後在把這些模型物件中不同的屬性(比如:位置,大小,旋轉,顏色等)提取出來放到一個陣列中.

這是最新渲染api提供的一種技術,如果繪製1000個物體,它將一個模型的vbo提交給一次給顯示卡,至於1000個物體不同的位置,狀態,顏色等等將他們整合成一個per instance attribute的buffer給gpu,在顯示卡上區別繪製,它大大減少提交次數,它在不同平臺的實現有差異,例如gles是將per instance attribute也當成一個vbo提交,然後gles3.0支援一種per instance步進讀取的vbo特性,來實現不同的instance得到不同的頂點資料,這種技術對於繪製大量的相同模型的物體由於有硬體實現,所以效率最高,最為靈活,避免合批的記憶體浪費,並且原則上可以做gpu skinning來實現骨骼動畫的instancing。

2.底層邏輯,為什麼能夠加速渲染,提高效能?
針對同網格同材質的模型多個物件進行渲染時,有一下幾種渲染方式:
原始模式,每個材質和模型都呼叫一次渲染,這樣會導致的後果是,每次渲染一個物件CPU就會向GPU提交一次渲染相關的所有資源.很明顯這裡面有很多重複資源的提交造成了很大的浪費,也讓渲染速度大大降低.

動態合批模式,這個很好理解,把最近相同的模型進行合併成一個模型,然後一次提交一次渲染,爽快利落,典型的空間換速度,也很划算,最大化的提高渲染效率.但是,當網格數量和網格的頂點數超過一定數量時,動態合批就不能在進行了因為這個時候就會拉低CPU的執行效率,以及記憶體空間的暴漲.所以動態合批有較多的限制.

靜態合批模式,這個也很好理解,離線把模型全部給合併到一個網格(合併後的網格頂點數量有限制:65535),這樣能夠解決動態合批的問題,但是也有問題,會導致一下幾個問題:

重複網格的副本會被複制很多份,導致資源包體和執行時記憶體都會有很大的增長.
一些不需要渲染的頂點也被提交給GPU,增大了GPU的頂點處理器的壓力,.
在邏輯處理上,靜態合批也有一個問題,就是合併完後的模型物件不能再被位移,旋轉,縮放等處理了.
然後就是GPUInstance,他也是針對相同模型的網格和材質只提交一次,然後他組合這些模型物件的不同之處打成一個陣列提交給GPU,這樣既能夠減少提交的次數,有不會讓記憶體暴漲.CPU端也不會因為合併網格而各種計算,增加消耗.這樣他的特點就出來了:

在CPU端進行模型裁剪,只合並看見的模型物件.這樣提交給GPU渲染的例項會更少更有效.在某些場景下,這個相對於靜態批處理來說優勢很足.
只組織和提交模型物件之間的不同之處,記憶體的消耗也能夠控制.這個相對於動靜兩種合批來說都是優勢巨大.
不需要做網格的合併處理,這方面也CPU沒有消耗.這個相對於動態合批來說優勢巨大.
在CPU端的例項不同點的合併處理,需要一定的消耗,這個對於靜態批處理來說沒有優勢.
在GPU端要增加一個索引和快取的讀取處理,這個也算是額外的消耗,這個對於靜態批處理和動態批處理都沒有優勢.
因為一個批次渲染,只提交一個網格副本,所以對於網格的大小就沒有了限制.適應範圍更廣泛,這個對於動態合批來說優勢巨大.
綜上幾個渲染方式的對比之後,在針對這種大量的同網格,.同材質的模型時,數量越大效能提高程度就越明顯.
物體的重複數量必須達到一個static baching(大約6萬多個頂點)無法容納的程度或者基於更加節省記憶體的考慮才有必要使用gpu instancing。

全屏不超過10萬個頂點和200個draw call左右,不然對中端機器會有一定壓力。
DrawMeshInstance一次性最大提交數量為1023