什么是DrawCall
CPU呼叫GPU進行繪制是一次DrawCall
以 OpenGL 為例,就是調用帶有繪制功能的 API 的次數
如:DrawCall : 10 次,那就意味着調用了 glDrawXXXX 的 API 10 次
啥叫:Batch
Batch 直譯:批量,的意思
在 實時渲染 中,已動態合批為例(Dynamic Batch)一般理解為:為了減少 DrawCall,或是減少 SetPassCall 而將繪制時材質一樣(或是說 shader + shader 參數 + 繪制前狀態,都一樣)的 VBO,IBO,等數據打包到一個大的 VBO,或是 IBO 中,然后在調用一次 DrawCall,從而提升性能:SetPass 的 State 時,或是多次 Draw API 調用產生過多的 CPU 消耗的性能的問題
(另外還有:靜態合批(Static Batch)、Instanced 批量(GPU Instancing Batch)繪制,都算是 Batch 的方式)
所以 Batch 的目的是:將原本需要 多次 SetDrawState + 多次 DrawCall,優化為:1次 SetDrawState + 1次 DrawCall
可以簡單的理解為:批量渲染是通過減少CPU向GPU發送渲染命令(DrawCall)的次數,以及減少GPU切換渲染狀態的次數,盡量讓GPU一次多做一些事情,來提升邏輯線和渲染線的整體效率。但這是建立在GPU相對空閑,而CPU把更多的時間都耗費在渲染命令的提交上時,才有意義。
合批最重要的前提:材質必須相同!!!
Batch ≠ DrawCall
優化方式
相同材質的物體一同繪制
那么如何相同材質的物體一同繪制
就是把相同材質的物體的網格合並一同繪制
Why?
- 底層的圖形api有一個繪制三角形的接口,這個就是CPU調用gpu繪制的接口
- 在調用這個接口前會准備頂點數據,即網格數據
- 把網格合並后只要進行一次繪制三角形的接口調用,減少了DrawCa
為啥要優化DrawCall
上面已經說了,Cpu叫GPU執行一次繪制渲染就是DrawCall。
傳輸數據消耗比較大,GPU的計算能力也相對較強,就可能存在CPU傳遞的指令只讓渲染一小部分,GPU執行完畢以后,但是下一條的指令還沒有過來的時候,
這就好比這條路車多了,堵車了,那么如何梳理交通,讓一次通過的紅綠燈讓更多的車子過去,提供更高效的通行效率和時間呢?關鍵就是在於,這次紅綠燈,我讓多少車過去了。
所以,提高DrawCall的效率非常的重要,就是保證盡量的讓每次的DrawCall能夠渲染更多的內容(讓更多的車子過去)。這樣,即便是紅綠燈通行次數少了(DrawCall的提交次數),但是
通行效率提高了,一次性過去的車子多了,那么也能有效的減少擁堵的情況。
然后如何去提升DrawCall的效率呢,主要的方法就是合批(Batch),,也就是上面解釋的名詞。
Unity中的合批
靜態合批 Static Batching
- Unity中把物體標記為Static,然后開啟靜態合批
- 限制
- 需要保持static,不能改變transform
- 使用相同材質的物體才能合批
- 一個批次上限為~15k個頂點
動態合批 Dynamic Batching
Unity自帶動態合批,需要在Unity中開啟動態合批選項
會導致cpu消耗,如果不是gpu有瓶頸,最好關閉動態合批
前提
使用頂點位置、法線、UV0、UV1和切線為一個着色器提供180個頂點
使用頂點位置、法線和單一UV的着色器的300個頂點
動態合批的限制條件呢?
●材質球相同;
●Mesh頂點數量不能超過300以及頂點屬性不能超過900;
●縮放不能為負值(x、y、z向量的乘積不能為負)等。
靜態合批的利弊
靜態合批采用了以空間換時間的策略來提升渲染效率。
其優勢在於:網格通常在預處理階段(打包)時合並,運行時頂點、索引信息也不會發生變化,所以無需CPU消耗算力維護;若采用相同的材質,則以一次渲染命令,便可以同時渲染出多個本來相對獨立的物體,減少了DrawCall的次數。
在渲染前,可以先進行視錐體剔除,減少了頂點着色器對不可見頂點的處理次數,提高了GPU的效率。
其弊端在於:合批后的網格會常駐內存,在有些場景下可能並不適用。比如森林中的每一棵樹的網格都相同,如果對它采用靜態合批策略,合批后的網格基本等同於:單顆樹網格 x 樹的數量,這對內存的消耗可能就十分巨大了。
總而言之,靜態合批在解決場景中材質基本相同、網格不同、且自始至終都保持靜止的物體上時,很適用。
動態合批與靜態合批的區別
1、動態合批不會創建常駐內存的“合並后網格”,也就是說它不會在運行時造成內存的顯著增長,也不會影響打包時的包體大小;
2、動態合批在繪制前會先將頂點轉換到世界坐標系下,然后再填充進頂點、索引緩沖區;靜態合批后子網格不接受任何變換操作,僅手動合批后的Root節點可被操作,因此靜態合批的頂點、索引緩沖區中的信息不會被修改(Root的變換信息則會通過Constant Buffer傳入);
3、因為2的原因,動態合批的主要開銷在於遍歷頂點進行空間變換時的對CPU性能的開銷;靜態合批沒有這個操作,所以也沒有這個開銷;
4、動態合批使用根據渲染器類型分配的公共緩沖區,而靜態合批使用自己專用的緩沖區。
開啟方法
Player Setting > Other Settings