天天看點

Unity 繪圖性能優化 - Draw Call Batching

Unity官方連結:http://docs.unity3d.com/Manual/DrawCallBatching.html

轉載出處連結:http://www.cnblogs.com/fly-100/p/5422734.html

Draw Call Batching

在螢幕上繪制一個物體,U3D引擎必須向繪圖API(openGL或者D3D)發起一次DrawCall。這些DrawCall往往是昂貴的,當繪圖API為每個DrawCall做一些重要的事情,引起GPU的性能消耗較高。

這些消耗大部分是因為DrawCall結束的狀态切換引起的(比如,從一個材質切換到另一個材質),因為這會引發昂貴顯示卡驅動的驗證和變換步驟。

Unity使用多種技術來解決這個問題:

  • 靜态Batching:把靜态的物體合并成一個大meshes,然後用更快的方法渲染他們。
  • 動态Batching:對于足夠小的meshesh,變換他們的頂點在CPU上,将一些相似的組合到一起,在一個go中繪制。

内建的Baching相對于手動合并物體到一起有幾個好處(值得注意的是,這些對象仍可以被單獨銷毀)。

但是他也有它的缺點(靜态Batching會導緻記憶體和存儲的開銷,動态Batching會導緻CPU開銷)。

Material Setup For Batching

隻有共享同一個材質的物體才能被Batched在一起。如果,你想達到一個好的batching,你需要竟可能多的在不同物體中共享材質。

如果你有兩個同樣的材質但是他們的textures不同,你可以合并這些textures到一個大texture - 這個過程經常被叫做texture atlasing。一旦textures在同一個圖集中,你就可以使用一個材質來代替了。 

如果你需要在腳本中通路共享了的材質,有一個很重的點需要注意:修改Renderer.material屬性會建立一個目前材質的副本。是以,作為替換方案,你應該使用Rednerer.sharedMaterial以保證材質被共享。

當渲染陰影投射的時候,即使他們的材質是不同的,也經常被batched到一起。隻要材質中的數值在shadow pass是相同的,即使陰影投射有不同的材質,他們也可以使用動态batching。舉個例子,許多箱可以使用具有不同的texture的材質,但對于陰影投射渲染 texture是不相關 - 在這種情況下,他們可以被batched到在一起。

Dynamic Batching

Unity可以自動batch移動物體到相同的draw call,如果它們具有相同的材質和滿足其它标準。動态Batching是自動完成的,不需要你做額外的事情。

  • Batching 動态的物體每個頂點會有某些開銷,是以batching隻适用于定點數小于900的meshes。
    • 如果你得shader使用了頂點位置,法線和單獨的UV,那麼你可以batch 300 個頂點;如果你得shader使用了頂點位置,法線,UV0,UV1,和正切,隻能batch 180個頂點。
    • 這個限制的數量将來有可能會變化。
  • 如果物體包含鏡像變換,他們将不會被batched,例如,object A 的scale 為 +1 object B 的scale 為-1,就不能batched到一起。
  • 使用不同材質的執行個體,即使他們實質上是相同的,也會導緻兩個物體不能被batched到一起。陰影投射除外。
  • 具有光照貼圖的對象有額外的渲染參數:光照索引和 偏移/放縮 的光照。是以一般動态lightmapped對象應指向完全相同的光照貼圖位置然後再進行batch。
  • 多通道的shader将不會被batching
    • 幾乎所有的Unity shader都支援前置渲染幾個燈光,有效的為他們做更多的通道。“額外的逐像素的燈光”的draw call 将不會被batched。
    • 傳統的延遲渲(逐通道光照)染通道禁用了動态batching,因為它必須繪制兩次。

由于它的工作原理是變換所有的物體的頂點到CPU的世界坐标中,是以它僅僅在它的工作(變換到cpu的世界坐标)比做一次“draw call”小的時候才能起到好的作用。究竟一個DrawCall有多昂貴取決于諸多因素,主要是所用的繪圖API。例如,在控制台或目前流  

行的APIs 例如Apple Metal DrawCall的開銷一般比較低,是以一般動态batching不會達到好的效果。

Static Batching

靜态batching允許引擎減少draw call适用于任何大小的幾何(假設沒有移動和共享材質)。大部分情況下他比動态batching更高效 ,但是它會占用更多的記憶體。

為了使靜态batching更好的獲益,你需要明确的指定遊戲中某些物體是靜态的而且不會移動,旋轉或者縮放。這樣做,你可以在Inspector界面中的“Static”選項(chekbox)标記物體為static:

Unity 繪圖性能優化 - Draw Call Batching

使用靜态batching将需要額外的記憶體來存儲合并後的幾何資訊。如果幾個物體在靜态batching之前共享同一個幾何圖元,那麼這個幾何圖元将會為每個物體複制一份,無論在Editor中還是runtime中都是如此。這不是一個好方法 - 有時候為了保持更小的記憶體占用量,你必須犧牲渲染性能為了避免一些物體的靜态batching。例如,在一個稠密的森林中,标記樹木為static會産生嚴重的記憶體影響。

在内部,靜态batching的原理是變換這些靜态物體到世界控件然後為他們建立一個很大頂點+索引 緩沖區。然後所有顯示的物體都放到一個batch,一系列“便宜的”draw call就完成了,這期間幾乎沒有狀态切換(state change)。是以 從技術上來講 這并沒有節省“3D API draw call”,但是他節省了他們之間的狀态切換(狀态切換才是罪魁禍首)。

Other Batching Related Tips

目前,隻有網格渲染才被batched。像 skinned meshes,cloth,拖尾渲染器(Trail Renderer)和其他類型的渲染元件是不被batched的。半透明shader為了做透明度的工作,經常需要物體以從後到前的順序進行渲染。Unity首先會對物體進行排序,然後試着batch他們 - 因為這個順序是嚴格限制的,這就意味着 相對于不透明物體來說,會有很少的batching産生。相對調用draw call來說,手動合并比較近的物體可能是一個非常不錯的選擇。例如,許多抽屜的靜态櫃子合并成一個mesh經常是有道理的,無論是在3D模組化軟體中還是使用Mesh.CombineMeshaes.