天天看點

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

Unity中的批處理優化與GPU Instancing【轉】

我們都希望能夠在場景中投入一百萬個物體,不幸的是,渲染和管理大量的遊戲對象是以犧牲CPU和GPU性能為代價的,因為有太多Draw Call的問題,最後我們必須找到其他的解決方案。

在本文中,我們将讨論兩種優化技術,它們可以幫助您減少Unity遊戲中的Draw Call數量以提高整體性能:批處理和GPU Instancing。 

批處理

開發者在日常工作中遇到的最常見的問題之一是性能不足,這是由于CPU和GPU的運作能力不足。一些遊戲可以運作在PC上,但是在移動裝置上不行。遊戲運作時運作是否流暢受Draw Call數量的影響很大。有幾個解決方案能幫助您解決這個問題。最常見的是批處理,包括Static Batching和Dynamic Batching。

Static Batching可以讓引擎降低任何尺寸網格的Draw Call,如下圖所示:

<ignore_js_op>

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

要讓場景中的物體使用Static Batching,需要将其标記為Static,并在Mesh Renderer中共享相同的材質,因為Static Batching不會在CPU上做頂點轉換,是以它通常比Dynamic Batching更有效。不過它會使用更多的記憶體,例如你的場景中有相同物體的多個副本,Unity會将它們組合成一個大網格并可能會增加記憶體使用。Unity将盡可能多的網格結合到一個靜态網格中,并将其作為一個Draw Call送出。這種方法的缺點是:标記為Static的物體在其生命周期中不能移動。

Dynamic Batching啟用時,Unity将嘗試自動批量移動物體到一個Draw Call中。要使物體可以被動态批處理,它們應該共享相同的材質,但是還有一些其他限制:

  • 頂點數量:Dynamic Batching場景中物體的每個頂點都有一定的開銷,是以批處理隻适用于少于900個頂點屬性的網格物體。舉個例子,如果你的着色器使用頂點位置,法線和一個UV,那麼你可以動态批處理多達300個頂點;而如果你的着色器使用頂點位置,法線,UV0,UV1和切線,那麼隻有180個頂點。值得注意的是,屬性計數限制可能會在将來更改。
  • 鏡像資訊:如果物體包含的Transform具備鏡像資訊,例如A物體的大小是(1f, 1f, 1f),而B物體的大小則是(-1f, -1f, -1f),則無法做批處理。

    材質:如果物體使用不同的材質執行個體,即使它們本質上相同,也不會被批量處理。而Shadow Caster Rendering是個例外。

  • 渲染器:擁有光照貼圖的物體有其他渲染器參數,例如光照貼圖索引或光照貼圖的偏移與縮放。一般來說,動态光照貼圖的遊戲對象應該指向要批量處理的完全相同光照貼圖的位置。
  • 不能使用Multi-pass着色器的情況:幾乎所有的Unity着色器都支援多個燈光的正向渲染模式(Forward Rendering),這要求額外的渲染次數,是以繪制 “額外的每像素燈”時不會被批處理;Legacy Deferred(Light Pre-Pass)渲染路徑不能被動态批處理,因為它必須繪制物體兩次。

Dynamic Batching通過将所有物體的頂點轉換為CPU上的世界空間來工作,是以它隻能在渲染Draw Call的工作量小于CPU頂點轉換工作量的時候,才會起到提高性能的作用。當用遊戲機或如Metal這樣的現代API,Draw Call的開銷通常低得多,Dynamic Batching就無法提高性能了。了解到以上限制後,如果明智地使用批處理,可以顯著提高您遊戲的性能。

GPU Instancing

提高圖形性能的另一個好辦法是使用GPU Instancing。GPU Instancing的最大優勢是可以減少記憶體使用和CPU開銷。當使用GPU Instancing時,不需要打開批處理,GPU Instancing的目的是一個網格可以與一系列附加參數一起被推送到GPU。要利用GPU Instancing,您必須使用相同的材質,且可以傳遞額外的參數到着色器,如顔色,浮點數等。

Unity從5.4版本開始支援GPU Instancing。 唯一的限制是在遊戲物體上要使用相同的材質和網格。 目前支援以下平台:

  • Windows DX11/DX12 和 SM 4.0 或更高/OpenGL 4.1 或更高
  • OS X and Linux:OpenGL 4.1 and above
  • 移動:OpenGL ES 3.0 或更高/Metal
  • PlayStation 4
  • Xbox One

如果您想要進行進一步的優化,例如減少管理場景物體的開銷,您也可以使用Graphics.DrawMeshInstanced方法。 您隻需要傳遞您的網格,材質和附加屬性來繪制您的物體。現在的限制是一次最多1023個執行個體。在Unity 5.6中,我們添加了Graphics.DrawMeshInstancedIndirect的新方法,可以用來指定需要渲染的執行個體數量。

GPU Instancing案例

要建立支援GPU Instancing的基本标準表面着色器,可以在您的項目裡面點選:

Create->Shader->StandardSurfaceShader(Instanced)。

<ignore_js_op>

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

然後,在材質屬性中選擇新建立的着色器。

<ignore_js_op>

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

雖然執行個體化的物體共享相同的網格和材質,但您可以使用MaterialPropertyBlock API為每一個物體設定單獨的着色器屬性。

如果一個遊戲對象被标記為“Static”并且打開了Static Batching,那麼這個遊戲對象就不能進行GPU Instancing,檢視器中會出現一個警告框,提示“靜态批處理”标志可以在播放器設定(Player Settings)中取消。如果遊戲對象支援Dynamic Batching,但是它使用的某個材質可以進行執行個體化,那麼這個遊戲對象将不會被批處理,并且将被自動執行個體化。

當使用Forward Rendering渲染模式,受多個燈光影響的物體無法有效地執行個體化。隻有Base Pass可以有效地利用執行個體化,而不是添加的Pass。此外,使用光照貼圖或受不同光或Reflection probe影響的物體無法執行個體化。如下圖所示,您可以在Frame Debug中發現和GPU Instancing相關的Draw Call被标記為“Draw Mesh(Instanced)”。    

<ignore_js_op>

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

GPU Instancing是一個非常強大的功能。在Unity 5.6中,您可以使用Graphics.DrawMeshInstancedIndirect繪制大量網格。在Mac Pro中,我們能夠畫出約68萬個具有不同顔色的移動立方體并保持穩定的60幀每秒的幀率。    

下圖是一個示例場景,超過6千個包子在天空中圍繞一個大碗飛翔,它們都投射和接收陰影。由于使用了GPU Instancing,幾乎沒有性能開銷。這裡的包子模型使用了StandardSurface Shader(Instanced)。

<ignore_js_op>

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

總結

在本文中,我們描述了用于優化渲染性能的兩種最流行的技術:批處理和GPU Instancing。我們向您展示了如何在實踐中使用它們并讨論可能的應用。正因為有諸如批處理和GPU Instancing等優化技術的存在,我們能夠繪制大量的對象并保持穩定的性能。

想要及時獲得更多有關Unity的技術分享,請掃描下方二維碼,關注“Unity官方平台”微信公衆号!

<ignore_js_op>

轉載:優化:Unity中的批處理優化與GPU Instancing【轉】Unity中的批處理優化與GPU Instancing【轉】

轉載請注明來源:Unity官方中文社群 (forum.china.unity3d.com)。請勿私自更改任何版權說明資訊。