• 熱門專題

Unity性能優化(4)官方教程Optimizing graphics rendering in Unity games翻譯

作者:Alan777w  發布日期:2016-12-22 20:36:26
Tag標簽:性能  教程  官方  
  • 本文是Unity官方教程,性能優化系列的第四篇《Optimizing graphics rendering in Unity games》的翻譯。

     

    簡介

    本文我們將會學習在Unity渲染一幀的幕后會發生什么,渲染時會發生哪種類型的性能問題,以及怎樣去解決和渲染相關的性能問題。

    閱讀本文之前,理解沒有一刀切的方法去改進渲染性能問題是至關重要的。渲染性能被我們游戲中的很多因素影響并且高度依賴我們游戲運行的硬件和操作系統。最重要的是我們通過調查,實驗,以及精確分析性能檢測的結果來解決性能問題。

    本文包括了一些最常見的渲染性能問題的信息,以及解決方法和一些擴展閱讀資源的鏈接。很可能我們的游戲有一些問題本文沒有覆蓋。盡管如此,本文仍然會幫助我們理解我們的問題,給我們一些基礎知識使得我們更有效的去查找解決方案。

    渲染的簡要介紹

    開始之前,我們快速簡要的看看Unity渲染一幀時發生了什么。理解事件流和事情發生的正確時期將會幫助我們理解,研究,并且努力解決我們的性能問題。

    備注:在本文中,我們將使用“object”,指代我們游戲中被渲染的對象。任何帶著渲染組件的GameObject都講稱作object。

    基本上,渲染流程如下:

    -CPU計算出什么東西需要被繪制,并且怎么被繪制。

    -CPU給GPU發送指令。

    -GPU根據CPU的指令進行繪制。

    現在讓我們進一步看看發生了什么。在本文的后面,我們將覆蓋上面每個步驟的細節。但是現在,我們先熟悉一些將會使用的名詞,以及理解在渲染中CPU和GPU所扮演的不同角色。

    渲染的過程通常被稱為渲染管線,這十分有助于記憶。高效的渲染在于保持信息流動。

    在渲染每一幀的時候,CPU都會做如下工作:

    -CPU檢查屏幕上的每個object,決定他們是否應該被渲染。一個object只有滿足了一定的條件才會被渲染。例如,它的一部分碰撞盒必須要在攝像機的視錐體內。不被渲染的object稱作被剔除了。想了解更多關于視錐體和視錐體剔除的信息,請閱讀this page。

    -CPU收集將要被渲染的每個object的信息,并把這些數據分類為指令被稱作繪制指令draw calls。一個draw call包含網格數據以及網格應該怎樣被渲染。例如,應該使用哪個紋理。在一定的情況下,共享設置的一些objects可能會被合并為一個draw call。合并不同objects的數據到同一個draw call被稱作batching。

    -CPU給每個draw call創建一個數據包,稱為batch。Batch有時會包含一些draw call以外的數據,但是這些情況通常不會對性能有什么影響,因此在本文中我們將不會考慮這些數據。

    每一個batch必須包含一個draw call,CPU現在會做如下工作:

    -CPU可能會發出指令,使得GPU改變一些渲染狀態的變量。這個指令被稱為SetPass call。SetPass通知GPU,使用哪些設置去渲染下一個網格。只有在渲染下一個網格時,渲染狀態和渲染上一個網格時發生了改變的情況下,才會調用SetPass call。

    -CPU把draw call發送給GPU。draw call指示GPU使用最近的SetPass call定義的設置去渲染指定的網格。

    -一定的情況下,batch可能需要不止一個的pass。pass是一段shader代碼,并且新的pass需要改變渲染狀態。對于batch中的每個pass,CPU必須發送一個新的SetPass call然后必須要再次發送draw call。

    同時,GPU做如下工作:

    -GPU按照CPU發送的指令順序處理這些指令。

    -如果當前任務是SetPass call,那么GPU更新渲染狀態。

    -如果當前任務是draw call,那么GPU渲染網格。渲染網格發生在很多階段,不同階段的shader代碼可以定義渲染。這部分的渲染過程十分復雜,我們不會詳細講解,但是理解下面的知識是很有用的:頂點著色器vertex shader告訴GPU怎么處理網格的頂點。片元著色器fragment shader告訴GPU怎么繪制單獨的像素。

    -這個過程會重復執行,知道所有CPU發送的任務都被GPU完成。

    現在我們了解了Unity渲染幀時發生了什么,讓我們考慮渲染時可能發生的一些問題。

    渲染問題的類型

    理解渲染最重要的是:為了渲染一幀,CPU和GPU必須都完成他們的任務。他們中的任何一個花費了太長的時間去完成任務,都會造成渲染延遲。渲染問題有兩個基本的原因。第一類問題是由低效的渲染管線引起的。當渲染管線中一步或者多步花費了太長時間,打斷了平滑的數據流時,渲染管線會很低效。渲染管線的低效被稱為瓶頸。第二類問題是由于,渲染管線被塞入了太多的數據。即使是最高效的渲染管線,對于一幀中可以處理的數據量也是有限制的。

    當我們的游戲花費太長的時間去渲染一幀,是由于CPU花費了過長的時間去完成渲染任務時,我們的游戲被稱為CPU約束。當我們的游戲花費太長的時間去渲染一幀,是由于GPU花費了過長的時間去完成渲染任務時,我們的游戲被稱為GPU約束。

    理解渲染問題

    在我們做任何修改前,先使用Profiler理解引起問題的原因是至關重要的。不同的問題需要不同的解決方案。測量我們做出的改變的效果也是很重要的。修復性能問題是一項平衡性的工作,改進一方面的性能問題,很可能會對其他方面有負面影響。

    我們將使用兩個工具來幫助我們理解和解決渲染性能問題。Profiler和frame debugger。他們都是Unity內置的工具。

    Profiler

    Profiler窗口允許我們實時的看到游戲的性能,我們可以看到游戲的很多方面的數據,包括內存使用,渲染管線,腳本性能等等。

    如果你還不熟悉使用Profiler,請參看Unity用戶手冊this page of the Unity Manual,以及這篇教程Unity性能優化(1)-官方教程The Profiler window翻譯 。

    Frame Debugger

    frame debugger允許我們一步一步的查看一幀是怎樣被渲染的。我們可以使用它查看詳細的渲染信息,如在每個draw call中都繪制了什么,每個draw call的shader屬性以及發送到GPU的事件的順序。這些信息幫助我們理解我們的游戲是怎樣渲染的以及我們可以在哪里改進性能。

    如果你還不熟悉frame debugger的使用,請參考this page of the Unity Manual以及這個視頻教程this tutorial video。

    找到性能問題的原因

    在改進我們游戲的渲染性能前,我們必須先確認我們游戲運行慢是由渲染問題引起的。如果真正的問題是由于過于復雜的用戶腳本引起的,那么我們去優化渲染性能是毫無意義的。如果你不太確認,性能問題是否有渲染引起的,請參考Unity性能優化(2)-官方教程Diagnosing performance problems using the Profiler window翻譯 。

    一旦我們確認是渲染問題,我們必須同時確認是CPU限制還是GPU限制。不同問題有不同的解決方案,所以在試圖修復問題前,理解引起問題的原因是至關重要的。如果你不確定你的游戲是CPU限制還是GPU限制,請參考Unity性能優化(2)-官方教程Diagnosing performance problems using the Profiler window翻譯 。

    如果是CPU受限

    基本上,在渲染一幀中,CPU的工作分為三類:

    -決定什么必須被繪制

    -為GPU準備好命令

    -發送命令給GPU

    這三類工作包含很多獨立的任務,這些任務可能是通過多線程工作的。多線程允許不同的任務同時執行;當一個線程執行一個任務時,另一個線程可以同時執行完全不同的任務。這意味著工作能夠更快的完成。當渲染任務被分發到不同的線程時,稱為多線程渲染。

    Unity渲染過程中和三類線程相關:主線程,渲染線程和工人線程(the main thread, the render thread and worker threads)。主線程用于我們游戲的主要CPU任務,包括一些渲染任務。渲染進程是專門用于發送命令給GPU的。每個工人線程執行一個單獨的任務,例如剔除和網格蒙皮。哪些任務執行在哪個線程,取決于我們游戲運行的硬件和游戲的設置。例如,CPU的核心數量越多,就會生成越多的工人線程數。由于這個原因,在我們的目標硬件上進行性能分析是十分重要的。在不同的設備上,我們游戲的表現可能相差很多。

    由于多線程渲染非常復雜并且依賴硬件,在我們嘗試改進性能時,必須首先理解是哪些任務導致了CPU限制。如果我們的游戲運行緩慢是因為在一個線程上剔除操作花費了太長的時間,那么我們在另一個線程上降低發送給GPU命令的時間是不會有什么幫助的。

    注意:不是所有的平臺都支持多線程渲染,在此時,WebGL不支持這個功能。在不支持多線程渲染的平臺上,所有的任務都在相同的線程中執行。如果在這樣的平臺上,CPU限制時,任何優化CPU的工作都會改進CPU性能。如果我們的游戲是這種情況,我們應該閱讀下面的全部章節,并且考慮哪些優化最適合我們的游戲。

    圖形工作Graphics jobs

    在Player settings中的Graphics jobs選項決定了Unity是否使用工人線程去執行一些原本需要在主線程或者渲染線程中執行的任務,在支持這個功能的平臺上,它能夠提供可觀的性能提升。如果我們希望使用這個功能,我們應該分別對開啟或者關閉此功能進行性能分析,以觀察這個功能對性能的提升效果。

    找出哪些任務對性能問題有影響

    我們可以使用Profiler來檢查哪些任務引起了CPU限制。請參考。。。

    現在我們理解了哪些任務引起我們游戲CPU限制,讓我們看看常見的問題和解決方案。

    發送命令到GPU

    發送命令到GPU花費時間過長是引起CPU限制的最常見的原因。在大多數平臺上,這個任務是由渲染線程執行的,個別平臺在工人線程上執行(如ps4)。

    發送命令到GPU中,其中最耗時的操作是SetPass call。如果CPU限制是由發送命令到GPU引起的,那么降低SetPass的數量通常是最好的改善性能的辦法。

    在Unity的渲染Profiler中,我們可以看到有多少SetPass call和batches被發送。有多少SetPass call被發送會造成性能問題,和游戲的目標硬件關系很大。在高端pc上可以發送的SetPass call數量遠遠大于移動平臺。

    SetPass call以及相關的batches數量取決于幾個因素。本文稍后會詳細闡述。簡單來說,通常如下:

    -降低batches數量或者使更多的對象共享相同的渲染狀態,通常會減低SetPass call數量。

    -降低SetPass call數量,通常會改進CPU性能。

    如果降低batches數量沒有降低SetPass call數量,他本身也會導致性能改進。這是因為CPU能夠更有效率的處理單個batch,即使它和幾個batches包含了數量相同的網格數據。

    基本上,有三種方法降低SetPass call和batches的數量,我們將仔細論述下面的每一種方法:

    -降低要渲染的對象數量,通?梢酝瑫r降低SetPass call和batches的數量。

    -降低每個要渲染的對象的渲染次數,通?梢越档蚐etPass call

    -合并要渲染的對象的數據到更少的batches,可以降低batches數量

    不同的技術適用于不同的游戲,我們將考慮以上所有的選擇,決定哪些適合我們的游戲并且做出實驗。

    降低要渲染的對象數量

    降低要渲染的對象數量是最簡單的降低batches 和 SetPass calls的方法。有以下幾個技術,可以降低要渲染的對象數量:

    -簡單的降低我們場景的可見對象數量,是一個有效的解決方案。例如,我們要渲染有很多人物的人群,我們可以嘗試減少人物的數量,如果看起來人群的效果仍然不錯,那么這就是一個比其他復雜方法快捷的多的優化方法。

    -我們可以通過設置攝像機的剪裁平面的遠端來降低攝像機的繪制范圍。這個屬性表示距離攝像機多遠的物體將不再被渲染。如果我們想隱藏遠處的物體不被渲染的事實,我們可以嘗試使用霧來掩蓋遠處。

    -如果需要基于距離的更細粒度的隱藏物體,我們可以使用攝像機的Layer Cull Distances屬性,它可以給不同的Layer設置單獨的剪裁距離。如果我們有很多前景裝飾細節時,這個方法很有用。我們可以使用很小的距離隱藏細節。

    -我們可以使用遮擋剔除功能去關閉被其他物體遮擋的物體的渲染。例如,我們場景中有一個很大的建筑,我們可以使用遮擋剔除功能,關閉它后面的物體的渲染。Unity的遮擋剔除功能不適用于所有的場景,它會導致額外的cpu消耗,并且相關設置很復雜,但是在一些場景中,它可能會極大的改善性能。使用遮擋剔除的最佳實踐,This Unity blog post on occlusion culling best practices。

    另外,我們可以通過手工的關閉物體渲染來實現我們自己的遮擋剔除,我們可以手工的關閉我們知道玩家無法看到的物體的渲染。例如,如果我們的場景包含一些過場的物體,那么在他們出現之前或者移出以后,我們應該手工的關閉他們的渲染。對于我們游戲來說,使用我們的知識,手工的剔除,往往比Unity動態的遮擋剔除有效的多。

    降低每個要渲染的對象的渲染次數

    實時的光照,陰影和反射可以極大的提高我們游戲的真實感,但是這些操作可能非常昂貴。使用這些功能可能導致物體被渲染多次,這對性能有很大的影響。

    這些功能的精確的影響依賴于我們游戲選擇的渲染路徑。渲染路徑,也就是表明當我們繪制場景的時候,渲染計算的執行順序。不同渲染路徑最主要的不同,是它們怎么處理實時光照,陰影和反射。通常來說,如果我們游戲運行在比較高端的設備上,并且應用了很多實時光照,陰影和反射時,延遲渲染是比較好的選擇。前向渲染適用于低端設備,并且不使用以上功能。盡管如此,如果我們需要更好的使用實時光照,陰影和反射等功能,情況是十分復雜的,最好研究相關主題以及實驗。請參考This page of the Unity Manua這是一個十分有用的起點。 請參考This tutorial這里包含了Unity中光照的相關主題內容。

    不論選擇哪種渲染路徑,使用實時光照,陰影和反射都會影響我們游戲的性能,所以,理解怎樣去優化他們是十分重要的。

    -Unity中動態光照是很復雜的主題,討論他超過了本文范圍,請參考this tutorial和 this page of the Unity Manual。

    -動態光照很昂貴。當我們的場景包含靜態物體時,例如風景,我們可以使用烘焙技術去預計算場景的光照,這樣就不需要在運行時計算光照了。具體請參考This tutorial和 this section of the Unity Manual。

    -如果我們希望在游戲中使用實時陰影,我們可能可以改進這方面的性能。This page of the Unity Manual 這篇文章介紹的陰影設置,以及這些設置怎么影響性能的。例如,我們可以設置陰影距離,確保只有近處的物體投射陰影。

    -反射探頭創建真實感的反射,但是會很大的影響batches數量。最好我們在性能敏感的場合最小化的使用它,并且無論在哪使用了他們都要盡可能的優化。反射探頭的優化請參考This page of the Unity Manual。

    合并物體為更少的batches

    在一定情況下,一個batch可以包含多個物體的數據。為了可以適合合并,物體必須滿足以下條件:

    -共享相同材質的相同實例

    -有一樣的設置(例如,紋理,shader,shader參數等)

    合并合適的物體可以改進性能,盡管如此,所有的優化技術我們都必須小心的分析,合并的消耗沒有超過獲得的性能改進。

    合并合適的物體有幾種不同的技術:

    -靜態batching技術,允許Unity合并相鄰的不移動的合適的物體。一個好的例子是,一堆相似的物體,例如巨石,可以從靜態batch中受益良多。在游戲中設置靜態batch,請參考This page of the Unity Manual。

    靜態batch會導致更高的內存占用,所以我們在優化時要衡量這個代價。

    -動態batching技術,是另外一種Unity合并合適的物體的技術,不論它是運動還是靜止。對能夠使用這種技術合并的物體,有一些限制。這些限制請參考this page of the Unity Manual 動態batching會影響CPU使用,可能會引起CPU消耗的時間大于節省的時間。我們應該通過實踐衡量它的代價,并且在使用的時候注意這些。

    -合并Unity的UI元素要更復雜一些,因為他會受我們界面布局的影響。具體請參考This video from Unite Bangkok 2015和this guide to optimizing Unity UI。

    -GPU instancing技術允許大量一樣的物體十分高效的合并處理。它的使用有一定限制,并且不是所有硬件都支持,但是如果我們的游戲在場景中同時存在大量相同的物體,我們可以在這個技術下收益。請參考This page of the Unity Manual 這里介紹了Unity中GPU instancing的技術細節以及怎樣使用它,支持哪些平臺,以及在哪種環境下,我們的游戲會受益于此。

    -紋理圖集,是把大量的小紋理合并為一張大的紋理圖的技術。它通常在2d游戲和UI系統中使用,但是也可以在3d游戲中使用。當我們使用這個技術為游戲創建美術資源時,我們可以確保物體共享同一圖集,因此適合合并。Unity內置了圖集工具Sprite Packer。

    -我們可以手工的合并共享相同材質和紋理的網格,不論是在Unity編輯器中還是在運行時使用代碼。當我們手工合并網格時,我們必須意識到,陰影,光照和剔除仍然在每個單獨的物體層級上操作。這意味著,合并網格所產生的性能提升,很可能被本來可以被剔除的物體,不再被剔除了,帶來的影響抵消。如果我們想深入研究這項技術,我們應該查看Mesh.CombineMeshes函數 ,Unity’s Standard Assets package中的CombineChildren腳本是一個例子。

    -在腳本中,我們必須小心使用Renderer.material,這會復制材質,并且返回一個新副本的引用。這樣做會破壞batching,如果這是合并中的一部分。因為renderer不再持有相同的材質引用了。如果我們需要訪問一個在合并中的物體的材質,我們應該使用Renderer.sharedMaterial。

    剔除,排序以及合并

    剔除,收集將要被繪制的物體的數據,排序這些數據,生成GPU命令,這些都對CPU限制有貢獻。這些任務會在主線程或者獨立的工人線程中運行,取決于我們游戲的設置以及目標硬件。

    -剔除本身消耗并不大,但是減少不必要的剔除操作可能會對性能有幫助。剔除是對場景中每個激活的物體,每個攝像機每個物體的計算,甚至是哪些不被渲染的層級的物體。為了降低這些,我們應該關閉攝像機,并且對于當前不使用的物體反激活或者禁用renderer。

    -Batching可以極大的增加向GPU發送命令的速度,但是他有時可能會在其他地方帶來消耗。如果batching操作造成了CPU限制,我們可以會要限制手工或者自動batching操作的數量。

    蒙皮

    SkinnedMeshRenderers在當我們使用一個網格動畫變形時(技術上稱為骨骼動畫)使用。它最多的用在動畫人物身上。渲染蒙皮的任務通常在主線程或者單獨的工人線程,依賴于游戲的設置以及目標硬件。

    渲染蒙皮可能會是昂貴的操作。如果我們在渲染Profiler中,看到渲染蒙皮對CPU限制影響很大,這里有幾個方法我們可以嘗試去改進它的性能。

    -我們應該考慮當前正在使用SkinnedMeshRenderers組件的物體是否有必要使用?赡苁沁@種情況,我們導入的模型包含了SkinnedMeshRenderers組件,但是我們其實并不需要它運動。這種情況下,我們使用MeshRenderer組件替換它,會有助于性能提升。當我們在Unity中導入模型時,如果我們在模型的導入設置中選擇不導出動畫,這個模型就會包含一個MeshRenderer組件替換SkinnedMeshRenderers組件。

    -如果我們只在一些時刻運動物體(例如,只在游戲開始時,或者只有距離攝像機一定距離內時),我們應該交換為一個細節較少的網格,或者使用MeshRenderer替換SkinnedMeshRenderers。SkinnedMeshRenderers組件有一個函數BakeMesh,可以用匹配的動作創建一個網格,這個十分有用,在不同的網格或渲染器中切換時物體不會有可見的變化。

    -這些文章有關于使用蒙皮的優化建議,請參考This page of the Unity Manual 和the Unity Manual page on the SkinnedMeshRenderer component,還應該記住,蒙皮的消耗是在每個頂點上,因此,使用頂點較少的模型可以有效降低工作量。

    -在一些平臺上,和CPU相比,蒙皮可以被GPU更高效的處理。如果我們的GPU比較強,這個值得嘗試。我們可以為當前平臺開啟GPU蒙皮,在Player Settings中。

    主線程操作和渲染無關

    理解許多主線程的任務是和渲染無關的很重要。這意味著,如果是CPU限制發生在主線程,我們應該把優化CPU時間改進性能的努力放在和渲染無關的任務上。

    例如,在某個時間點上,我們的游戲需要做十分昂貴的渲染操作并且在主線程上我們的腳本操作也非常昂貴,使得CPU限制。如果我們已經在不損失視覺真實度的前提下盡可能的優化渲染了,那么我們減少用戶腳本的CPU消耗可能會改進性能。

    如果游戲是GPU限制

    如果游戲是GPU限制,那么第一件事就是找到GPU瓶頸的原因。GPU性能最常被填充率限制,尤其在移動平臺,但是顯存帶寬和頂點處理也可能影響。讓我們檢查這些問題,并且學習引起問題的原因,怎么診斷和怎么修復問題。

    填充率

    填充率是指GPU在屏幕上每秒可以渲染的像素數。如果我們的游戲收到填充率的限制,意味著我們的游戲每幀嘗試繪制的像素數量超過了GPU的處理能力。

    檢查是否填充率引起了游戲GPU限制很簡單:

    -使用Profiler分析,注意GPU時間

    -在Player settings中降低顯示分辨率

    -再次分析游戲,如果性能改善了,很可能是填充率的問題

    如果確認了填充率引起了問題,有幾個方法可以解決問題:

    -片元shader是告訴GPU怎么樣去繪制一個像素的一段shader代碼。這段代碼GPU需要為每一個需要繪制的像素執行,所以如果這段代碼效率低,那么很容易發生性能問題。復雜的片元shader是很常見的引起填充率問題的原因。

    -如果我們的游戲使用Unity內置shader,我們應該使用最簡單和最優化的shader,為了達到我們想要的視覺效率。例如,the mobile shaders是Unity針對移動平臺高度優化的shader,我們應該實驗使用它們是否可以在不影響視覺效果的前提下改善性能。這些shader是為了移動平臺設計的,但是它們也適用于任何項目。如果使用它們可以達到項目視覺效果的要求,那么在非移動平臺上使用它們也是能夠很好的改善性能的。

    -如果游戲中的物體使用的是Unity的Standard Shader,那么理解Unity編譯這些shader是基于當前的材質設置的是很重要的。只有那些當前使用的功能會被編譯。這意味著,移除例如detail maps可以減少片元shader的復雜度,這對性能提升有很大益處。如果我們游戲中是這種情況,我們應該實踐,是否能夠在不影響視覺質量的前提是提升性能。

    -如果我們游戲使用的是定制的shader,我們應該盡可能的優化它。優化shader是一個很復雜的主題,請參考this page of the Unity Manual和 this page of the Unity Manual。

    -Overdraw是指相同的像素繪制了多次。這是在物體繪制在其他物體之上的時候發生的,也在很大程度上引起了填充率問題。為了理解Overdraw,我們必須先理解Unity在場景中繪制物體的順序。物體的shader決定了物體的繪制順序,通常由render queue屬性決定。Unity使用這些信息按照嚴格的順序繪制物體,具體細節請參考page of the Unity Manual 另外在不同render queue的物體在被繪制之前會按不同的順序排序。例如,Unity在Geometry queue中為最小化Overdraw會從前到后排序物體,但是在Transparent queue中,為了達到視覺效果的要求,則是從后到前排序物體。在Transparent queue中,從后向前排序物體其實最大化了Overdraw。Overdraw是一個很復雜的主題,并且沒有一刀切的解決方案,但是降低重疊物體的數量使得Unity不能自動排序是關鍵。調查Overdraw問題最好的起點是Unity的場景視圖中,DrawMode允許我們看到場景中的Overdraw,我們可以從這開始降低Overdraw的工作。最常見的引起Overdraw的因素是透明材質,未優化的粒子,和重疊的UI元素。所以我們應該嘗試優化這些。請參考This article on the Unity Learn site 這篇文章聚焦于UI,但是也包含了Overdraw的很好的指導。

    -使用屏幕后處理技術也會極大的影響填充率,尤其是我們使用了不止一種的屏幕后處理的時候。如果我們在使用屏幕后處理是遇到了填充率問題,我們應該嘗試不同的設置或者使用更加優化的屏幕后處理版本。例如使用Bloom (Optimized)替換Bloom。如果我們在同一個攝像機下使用了多個屏幕后處理,這將造成成倍的shader pass。這種情況下,我們應該合并shader到一個單獨的pass,例如Unity’s PostProcessing Stack。如果我們優化屏幕后處理效果后,仍然有填充率問題,那么我們也許要考慮關閉屏幕后處理,尤其是在低端的設備上。

    顯存帶寬

    顯存帶寬是指GPU讀寫它的專用內存的速度。如果我們的游戲受限于顯存帶寬,通常意味著我們使用的紋理太大了,以至于GPU無法快速處理。

    我們可以按如下方法檢查是否顯存帶寬的問題:

    -用Profiler分析游戲,并關注GPU時間

    -在質量設置中降低當前平臺的紋理質量

    -繼續分析游戲,如果性能改善了,那么通常是顯存帶寬的問題。

    如果是顯存帶寬的問題,我們需要降低紋理的內存占用。針對不同的游戲通常有不同的最佳解決方案,這里我們提供幾個優化紋理的方法:

    -紋理壓縮技術可以同時極大的降低紋理在磁盤和內存中的大小。如果是顯存帶寬的問題,那么使用紋理壓縮減小紋理在內存的大小可以幫助改善性能。Unity中有很多可用的紋理壓縮的格式和設置。通常來說,一些紋理壓縮格式只要可用就應該盡可能的使用,盡管如此,通過實踐找到針對每個紋理最合適的設置是最好的。請參考This page in the Unity Manual 講述了紋理壓縮的格式和各種設置的詳細信息。

    -多級漸遠紋理,是Unity對遠處的物體使用的低分辨率版本的紋理。如果我們的場景包含距離攝像機很遠的物體,我們可以通過使用多級漸遠紋理來緩解顯存帶寬的問題。Unity場景視圖中的The Mipmaps Draw Mode允許我們查看哪些物體受益于多級漸遠紋理,請參考this page of the Unity Manual 包含了使用多級漸遠紋理的詳細信息。

    頂點處理

    頂點處理是指GPU必須渲染網格中的每一個頂點的工作。頂點處理的消耗受兩件事情影響:必須渲染的頂點數量,以及在每個頂點上要進行的操作數量。

    如果我們的游戲是GPU限制,并且已經確認了不是填充率和顯存帶寬引起的問題,那么就很可能是頂點處理引起的。如果是這種情況,那么嘗試減少GPU頂點處理的數量很可能會獲得性能提升。

    有一些方法可以減少頂點數量或者在每個頂點上執行的操作數量:

    -首先,我們應該降低不必要的網格復雜的。如果我們使用的網格包含在游戲中無法被看見的LOD,或者低效的網格在錯誤的創建時包含了太多的頂點,這些都會浪費GPU的工作量。最直接的降低頂點處理的消耗的方法,就是在3d建模軟件中創建模型時使用更少數量的頂點。

    -我們可以嘗試使用法線貼圖技術,我們使用它來模擬更高幾何復雜度的網格。盡管使用這種技術有一些GPU負載,但是在多數情況下,它會獲得性能提升。請參考This page of the Unity Manual 介紹了使用法線貼圖技術去模擬更復雜的網格。

    -如果我們的游戲沒有使用法線貼圖技術,在網格的導入設置中,我們可以關閉頂點的切線。這會降低GPU處理頂點的數據量。

    -LOD(Level of detail),這是當物體遠離攝像機時,降低物體網格的復雜度的技術。這可以有效的降低GPU需要渲染的頂點數量,并且不影響視覺表現。具體使用細節請參考. The LOD Group page of the Unity Manual。

    -頂點shader,是一段shader代碼,告訴GPU怎么繪制每個頂點。如果我們的游戲受限制于頂點處理的影響,那么降低頂點shader的復雜度可能會有助于性能提升。

    -如果我們的游戲使用Unity內置shader,我們應該使用最簡單和最優化的shader,為了達到我們想要的視覺效率。。例如,the mobile shaders是Unity針對移動平臺高度優化的shader,我們應該實驗使用它們是否可以在不影響視覺效果的前提下改善性能。

    --如果我們游戲使用的是定制的shader,我們應該盡可能的優化它。優化shader是一個很復雜的主題,請參考this page of the Unity Manual 和 this page of the Unity Manual。

    結論

    我們已經學習了Unity中,是怎樣渲染的,當渲染時可能會發生什么問題,以及怎樣在我們的游戲中提高渲染的性能。使用這些知識以及性能分析工具Profiler,我們可以修復渲染相關的性能問題,并且構建我們的游戲使他們具有流暢有效率的渲染流水線。

    下面列出本文主題的相關資源

     

About IT165 - 廣告服務 - 隱私聲明 - 版權申明 - 免責條款 - 網站地圖 - 網友投稿 - 聯系方式
本站內容來自于互聯網,僅供用于網絡技術學習,學習中請遵循相關法律法規
亿游彩票平台ppx| 2dz| nn2| jtd| v0j| dxt| 0vb| hzl| jdd| 1pf| vl1| nrl| n1p| hxd| 1rf| dt1| vvl| h0j| zhd| 0jv| ht0| jf0| hvt| v0b| trh| 0th| ll1| lnz| t9v| hbp| 9lb| jd9| vxt| n9d| l9j| pjz| z0d| zjp| 0hp| fv8| ptd| p8p| xzx| 8nh| xz9| tdx| v9p| n9r| ndn| 9pb| bd9| tvb| d7j| zpv| 8lf| jb8| jlr| f8z| dvb| 8zp| vfd| xz8| djx| b6d| pvp| v7j| nfl| 7pv| zp7| xbt| x7z| dhf| 7nb| jbd| jl8| dpn| x6f| hjh| 6dh| fh6| hxv| n6d| hjh| 7dj| bl7| zzx| pnl| r5d| zvb| 5zb|