渲染最佳化01

來源:互聯網
上載者:User

標籤:解決方案   流程   eve   光源   tps   err   com   翻譯   lod   

https://unity3d.com/cn/learn/tutorials/temas/performance-optimization/optimizing-graphics-rendering-unity-games   (官方原文連結) 遊戲中的圖形渲染最佳化
  1. 介紹:
在這篇文章中我們將學習當Unity渲染一幀時,在情境背後到底發生了什麼,會出現什麼樣的問題以及怎麼去解決關於渲染的相關問題。 在讀這篇文章之前,應該要清楚的認識到:提高渲染效能的方案不是唯一的。因為影響渲染效能的因素有很多,包括遊戲自身,硬體和運行平台。我們應該從調查、經驗以及嚴格的分析這些案列。 文章包含了很多普遍的渲染效能問題的解決方案建議以及拓展閱讀,很可能我們的遊戲就存在這些問題或者其他文章沒有提到的問題,但是這篇文章仍然可以協助我們理解這些問題並且給出了有效知識點和詞彙協助我們快速找到解決方案。
  1. 渲染簡介:
開始之前,讓我們簡單快速的瞭解一下Unity渲染時發生的事情,瞭解這個渲染流程將會協助我們理解、研究並且解決效能問題NB:文章中將用“object”來表示在遊戲中被渲染的物體,任何帶有renderer組件的物體就會被叫做object 基本上,渲染可被描述為以下幾點:(1)CPU決定什麼會被繪製以及如何繪製(2)CPU發送指令給GPU(3)GPU根據CPU發送的指令進行繪製 現在,讓我們更進一步的看看到底發生了什麼,在文章的後面將會詳細的介紹這些步驟,但現在先熟悉一下這些詞彙以及瞭解一下CPU和GPU在渲染中扮演的角色。 渲染管線是經常被用來描述渲染的,這是個非常有用的一張腦海圖,有效渲染應該遵循以下幾點:(1)CPU會檢查情境中的每一個物體,決定他們是否會被渲染。只有符合條件(certain criteria)的物體才會被渲染;比如,攝像機的視椎體(view frustum    https://docs.unity3d.com/Manual/UnderstandingFrustum.html?_ga=2.87818000.925366423.1538040429-1156207016.1532919959)可見範圍。物體不會被渲染的情況叫做裁剪(culled),想知道更多關於視椎體和視椎體裁剪知識請移步到該網頁(https://docs.unity3d.com/Manual/UnderstandingFrustum.html?_ga=2.103692168.925366423.1538040429-1156207016.1532919959) (2)CPU將會收集所有會被渲染的物體的資訊並且對這些資料進行排序然後加進到命令集合中,也就是所謂的draw calls。一次drawcall包含的資訊包括:單一網格資料和這個網格將會怎麼被渲染;比如,哪一張圖片會被使用。在某些情況下,那些共用設定的物體會被包含進相同的drawcall中,歸併不同物體的資料到相同的drawcall中的操作叫做合批(batching) (3)CPU為每一個drawcall建立一個被叫做batch的資料包,合批有時候包含的是資料而不是drawcalls,但這些情況不考慮。 對於每個包含drawcall的合批(batch),CPU必須做以下操作:(1)CPU會發送一個改變一系列變數(這些變數統稱為渲染狀態(render state))的指令給GPU。這個指令也叫做 SetPass call,一個SetPass call指令將會告訴GPU哪些設定將會被用來渲染下一個網格(mesh)。SetPass call只有在下一個要被渲染的網格跟上一個網格的渲染狀態不同時才會被發送。(A SetPass call is sent only if the next mesh to be rendered requires a change in render state from the previous mesh) (2)CPU發送drawcall指令給GPU,這個drawcall指引GPU去渲染用了 最近一次SetPass call設定的網格 (3)在某些情況下,合批需要多個pass,一個pass是shader中的一部分,一個新的pass需要一個渲染狀態的改變,對於合批的每一個pass,CPU都必鬚髮送一個SetPass call並且重新發送一次drawcall指令。 與此同時,GPU需要做以下操作:(1)GPU根據CPU按順序發送的指令去處理相應的操作。(2)如果當前的任務(task)是SetPass call的話,GPU就會更新渲染狀態(3)如果當前的任務(task)是drawcall的話,GPU就會渲染網格。這個是分階段發生的,是定義在shader代碼中的(separate sections)。這部分比較複雜,暫且不詳細討論,但能讓我們瞭解到vertex shader(頂點著色器:它告訴GPU怎麼處理網格的頂點)代碼塊和fragment shader(片元著色器:它告訴GPU怎麼去繪製每一個像素)代碼塊。(4)這個處理過程將會一直重複執行,直到GPU處理完所有從CPU發送的指令操作   到此,我們瞭解了當Unity渲染一幀時到底發送了什麼,現在讓我們考慮一下渲染中會發生的一些問題 渲染問題的種類:(1)要瞭解渲染就必須明白這一點:為了渲染一幀,CPU和GPU都必須完成各自的任務,如果任意一個任務的執行時間太長,當前幀的渲染都會被延遲。(2)渲染問題有兩個基本成因,第一類是:低效的管線,這類問題的產生是因為在渲染管線中有至少一個任務的執行時間過長了,中斷了資料流。這類問題也被叫做:bottlenecks(瓶頸)。第二類問題是:塞入太多的資料給管線。即便是再有效管線,在一陣幀內,也有處理資料量的限制。 (3)如果是因為CPU的任務的執行時間過長,這種問題叫做:CPU bound(限制),如果是因為GPU,那就叫做:GPU bound  理解渲染問題:(1)使用效能分析工具能讓我們在做出決策前瞭解到渲染效能問題的成因。不同的問題需要不同的解決方案。衡量方案的有效性也是非常重要的;處理渲染效能問題其實是一個權衡問題,也就是說,最佳化一個可能會給另外一個造成負面影響。 (2)Unity內建效能分析工具:Profiler window ,   Frame Debugger  The Profiler Window:可以觀察到即時的渲染資料。包括:記憶體使用量率,渲染管線和使用者指令碼效能表現。關於The Profiler Window學習文章可以參考下面兩個網址:https://docs.unity3d.com/Manual/ProfilerWindow.html?_ga=2.129883652.925366423.1538040429-1156207016.1532919959     https://unity3d.com/cn/learn/tutorials/temas/performance-optimization/profiler-window?playlist=44069 The Frame Debugger:可以觀察到每幀的渲染情況,step by step。通過The Frame Debugger,我們可以查看很多詳細資料:比如在每一次drawcall中什麼被繪製了,涉及到的shader屬性和從CPU發送過來的指令順序。這些資訊能夠協助我們理解遊戲是怎麼被渲染的以及如何最佳化渲染效能。關於The Frame Debugger的學習文章:https://docs.unity3d.com/Manual/FrameDebugger.html?_ga=2.131396487.925366423.1538040429-1156207016.1532919959https://unity3d.com/cn/learn/tutorials/topics/graphics/frame-debugger  尋找渲染效能問題的原因:(1)在我們嘗試為遊戲提高渲染效能前,我們必須確定由於渲染問題,遊戲會運行緩慢。如果是因為過於複雜的代碼造成的,很抱歉,在這裡沒有這個解決方案。如果你不確定當前的效能問題是渲染方面的,那麼可以查看這篇文章:https://unity3d.com/cn/learn/tutorials/temas/performance-optimization/diagnosing-performance-problems-using-profiler-window?playlist=44069 (2)一旦我們確定了效能問題是渲染方面的,我們應該弄清楚是不是CPU bound或者是GPU bound。不同的問題需要不同的解決方案,所以在修複問題之前應該先搞清楚問題的成因,如果你還不能確定是否是因為GPU bound或CPU bound,你可以查看這篇文章:https://unity3d.com/cn/learn/tutorials/temas/performance-optimization/diagnosing-performance-problems-using-profiler-window?playlist=44069 如果確定了效能問題是渲染方面的,並且也弄清楚了是否是GPU bound或CPU bound,那繼續下面的閱讀: 如果是CPU bound:一般來說,CPU為渲染一幀所做的事情分為以下三種:(1)決定什麼會被繪製(2)指令準備(3)發送指令這些廣義範疇包含了很多獨立的任務,並且這些任務會在多線程中完成。線程允許分離的任務同時執行,當一個線程在執行一個任務時,另外一個線程也能夠同時執行另外一個任務。這意味著可以更快的完成操作。當渲染任務被分到不同的線程中時,也叫做多線程渲染(multithreaded rendering) 在Unity的渲染流程中,有三種不同的線程類型:主線程,渲染線程,背景工作執行緒(或者叫輔助線程)。主線程是負責遊戲的主要任務的,也包括一些渲染任務。渲染線程是專門發送指令給GPU的。背景工作執行緒就是單獨負責各自任務的:比如,裁剪(culling)或網格蒙皮。線程會執行哪個任務取決於遊戲中的設定和遊戲啟動並執行硬體裝置。舉個例子:目標裝置有更多核,那麼就會產生更多的背景工作執行緒。基於此,目標硬體裝置的效能分析也是很重要的,不同的裝置會有不同的表現。 因為多線程渲染是複雜的並且依賴於硬體裝置,所以在進行效能最佳化之前必須要弄清楚哪些任務導致了CPU bound,如果遊戲是因為線程中的裁剪操作(culling operations)的執行時間過長導致運行緩慢的,那麼,在其他線程中發送指令給GPU也不會減少這個執行時間。 NB:並不是所有的平台都支援多線程渲染,至少目前WebGL是不支援的。在那些不支援多線程渲染的平台上,所有的CPU任務都會在相同的線程中完成。如果在這樣一個平台上,最佳化CPU的操作就可以提高CPU的效能表現。如果遊戲中出現這樣的情況,那麼我們應該閱讀接下來的所有部分並且考慮哪一個最佳化方法是最適合我們的遊戲的。  Graphics Jobs(Experimental)   在Unity中的Player Setting中的Graphics Jobs選項是決定Unity是否使用背景工作執行緒完成渲染任務的(不勾選的話就會在主線程完成,在某些情況下,是在渲染線程中完成)。當這個選項被勾選時,能夠極大地提高效能。如果要用到這個特徵屬性,那麼我們就應該去分析勾選和不勾選狀態下的遊戲效能。 --找到導致渲染效能問題的元兇--使用Profiler Window能夠協助我們找到是哪個任務導致了CPU bound, 發送指令給GPU(1)發送指令給GPU所耗費的時間是造成CPU bound的最常見的原因。在大多數平台上,這個任務的執行會在渲染線程中,在某些平台上(ps4)會在背景工作執行緒中執行。(2)最耗時的發送指令操作是SetPass call,如果我們遊戲是因為發送指令給GPU造成CPU bound的話,那麼減少SetPass call的數量是提高效能的一劑良方。(3)我們可以通過Unity的Profiler Window效能分析工具觀察到有多少SetPass call和batches。有多少SetPass call會被發送很大程度上取決於目標硬體,相比行動裝置,高端的PC機上會發送更多的SetPass call(4)SetPass call和與之相關的batches的數量取決於幾個因素,接下來的文章中也會深入的探討這個話題,然而,通常情況下是這樣的:
  1. 減少batches的數量並且/或者讓更多的物體使用相同的渲染狀態,在多數情況下,是能減少SetPass call數量的
  2. 減少SetPass call的數量,在多數情況下,會提高CPU效能
 如果減少了batches卻沒有減少SetPass call,也會使效能提高的。這是因為相比多個batches,CPU能夠更加有效處理單個batch,即使他們包含了相同大小的網格資料。 通常來講,有三種方法可以減少batches和SetPass call。我們將更加深入的探討這幾點:(1)減少需要被渲染的物體的數量可以同時減少batches和SetPass call(2)減少需要被渲染物體的渲染次數能夠減少SetPass call數量(3)合并需要被渲染物體的的資料將減少batches 不同的技術會適應不同的遊戲,所以我們應該考慮所有的可能,以此決定使用哪一些技術。 減少需要被渲染的物體的數量:      減少需要被渲染的物體的數量是減少batches和SetPass call的最簡單的方式,下面給出幾個可以減少需要被渲染的物體的數量的技術
  1. 簡單地減少情境中可見物體的數量是一個非常有效方法。比如,如果我們渲染大量的角色模型,那麼可以實驗一下少量角色模型的情況。如果情境表現有所提升,這將是更便捷的方案,而不是複雜的技術了。
  2. 通過攝像機組件的Far Clip Plane屬性降低攝像機的繪製距離。攝像機的可視距離範圍。如果希望遠處的物體看不見,可以嘗試使用這個:
    fog to hide the lack of distant objects:https://docs.unity3d.com/Manual/GlobalIllumination.html?_ga=2.93584149.925366423.1538040429-1156207016.1532919959 
  1. 基於距離,為了更多細粒度的隱藏物體的方式,可以使用攝像機的Layer Cull Distances屬性,為不同層級的物體提供自訂的裁剪距離,如果有很多前景細節裝飾,那麼這個方式是很有效;我們能夠在更加短的距離上隱藏這些細節。
https://docs.unity3d.com/ScriptReference/Camera-layerCullDistances.html?_ga=2.92118162.925366423.1538040429-1156207016.1532919959   。 
  1. occlusion culling(遮擋裁剪,遮擋剔除)是使那些被其他物體遮擋的物體不被渲染出來的技術。比如情境中有一個比較大的物體,這個物體後面有其他的物體,那麼就可以使用occlusion culling(遮擋剔除)。Unity的遮擋剔除技術(occlusion culling)並不是適合所有的情境,它會造成一定的CPU開銷並且設定起來也比較複雜,但在某些情境中它是可以提高效能的。這有一篇學習occlusion culling的部落格:
https://blogs.unity3d.com/cn/2013/12/26/occlusion-culling-in-unity-4-3-best-practices/?_ga=2.91616146.925366423.1538040429-1156207016.1532919959除了使用Unity的occlusion culling,我們也可以使用自己的occlusion culling:手動地將一些玩家看不到的物體隱藏。就比如一些用來顯示劇情動畫的物體,在播放之前或之後是看不見的,就可以隱藏掉這些物體。這也告訴我們,有時候不一定要在Unity官方找答案,根據具體的遊戲找到適合的解決方式。 減少每個需要被渲染的物體的渲染次數:(1)即時光照技術、陰影和反射等技術提高了遊戲的真實性,但也是非常消耗效能的。使用這些技術將會使物體被渲染多次,這很影響效能。(2)使用這些技術產生的具體影響取決於光照路徑(rendering path),渲染路徑是繪製情境時,計算的執行順序,渲染路徑之間的主要不同點它們怎麼去處理即時光照、陰影和反射。一般情況下,如果遊戲運行在高端的硬體裝置上並且使用了大量的即時光照、陰影和反射,那麼Deferred Rendering是個絕佳的選擇。而Forward Rendering是在相反情況下的更合適的選擇。然而,這是非常複雜的任務並且如果我們希望使用即時光照、陰影和反射這些技術,那麼,研究相關課題和案例是非常有必要的。這個網址:https://docs.unity3d.com/Manual/RenderingPaths.html?_ga=2.159199410.925366423.1538040429-1156207016.1532919959  可以學習到這些技術知識,這裡提供了很多關於Unity可供選擇的渲染路徑之間的不同點的相關知識。而這篇文章:https://unity3d.com/cn/learn/tutorials/topics/graphics/introduction-lighting-and-rendering  提供了非常有用的光照技術知識(3)不管選擇哪種渲染路徑,使用即時光照、陰影和反射這些技術都是會對遊戲造成一定影響的,所以,我們應該瞭解如何去最佳化它們
  •    Unity中的動態光照是非常複雜的課題,所以深入探討這個話題已經超出了本篇文章的範疇。這裡提供兩篇學習文章(https://unity3d.com/cn/learn/tutorials/topics/graphics/introduction-lighting-and-rendering(動態光照介紹),https://docs.unity3d.com/Manual/LightPerformance.html?_ga=2.162255028.925366423.1538040429-1156207016.1532919959 (詳解普通光照最佳化))
  • 動態光照是非常消耗效能的,當遊戲情境存在一些不動的物體:比如,風景,我們可以使用一個叫做baking(烘焙)的技術去預先計算光照,這樣在即時光照時就不會再計算了,學習這個技術請移步:https://unity3d.com/cn/learn/tutorials/topics/graphics/lighting-overview?playlist=17102   而這篇文章:https://docs.unity3d.com/Manual/GIIntro.html?_ga=2.69613336.925366423.1538040429-1156207016.1532919959  詳細介紹了baked lighting (烘焙光源)
  • 如果想要使用即時陰影,這是能提高效能的好去處 。這篇文章 https://docs.unity3d.com/Manual/DirLightShadows.html?_ga=2.167572022.925366423.1538040429-1156207016.1532919959  指引我們在Quality Settings如何調整shadow屬性並且告訴我們這些是如何影響效能的。比如,使用Shadow Distance屬性來確定只有近處物體會計算陰影。
  • Reflection propes(反射探頭)能夠產生真實反射但這也是非常消耗效能的(增加batches)。應該盡量少的使用的反射,並且使用時儘可能的去最佳化。這篇文章https://docs.unity3d.com/Manual/RefProbePerformance.html?_ga=2.131305607.925366423.1538040429-1156207016.1532919959  (反射探頭最佳化)
 合并物體資料,減少batches(1)在條件確定好時,一個batch會包含很多物體資料。為了能夠符合batching的條件,物體應該是:
  • 相同的材質的相同的執行個體共用
  • 材質設定相同(比如texture,shader,shader係數)
(2)批處理合格物體可以提高效能, 雖然我們分析這些確定batching開銷的最佳化技術並不能很好的提高效能。(這句可能翻譯的不是很準確,原文是這樣的:Batching eligible objects can improve performance,although as with all optimization techniques we must profile carefully to ensure that the cost of batching does not exceed the performance gains.)以下有幾點關於批處理合格物體的不同技術
  • Static batching(靜態批處理技術)能使Unity批處理近處且不動的合格物體。比如,一堆相同的物體(比如岩石)就可以使用靜態批處理技術進行最佳化。這篇文章:https://docs.unity3d.com/Manual/DrawCallBatching.html?_ga=2.102928520.925366423.1538040429-1156207016.1532919959 介紹了靜態批處理設定的用法說明。靜態批處理會造成較大的記憶體使用量,所以在分析遊戲效能時不能忘了分析這個
  • 動態批處理是另一個能批處理那些合格物體的技術,不論這些物體是否會動。使用這個技術會有一些限制條件。這些限制會被列舉出來,但與用法說明分開。這篇文章https://docs.unity3d.com/Manual/DrawCallBatching.html?_ga=2.94609172.925366423.1538040429-1156207016.1532919959。   動態批處理會影響到CPU使用量,並且它能節省的時間比開銷的時間更多。所以謹慎使用
  • 批處理Unity UI元素會有些小困難,因為會被UI布局所影響。文章
https://unity3d.com/cn/learn/tutorials/topics/best-practices/guide-optimizing-unity-ui?playlist=30089  ()(3)GPU instancing()技術能夠很有效批處理相同的物體,但有一些限制並且不是所有的硬體都支援。但如果遊戲中存在大量的相同的物體,使用這個技術會是個絕佳選擇。這篇文章:https://docs.unity3d.com/Manual/GPUInstancing.html?_ga=2.158048050.925366423.1538040429-1156207016.1532919959  (詳解GPU instancing)(4)Texture atlasing(圖集打包)技術可以合并大量紋理,在2D遊戲和UI系統比較常見,但也可以用在3D遊戲上。遊戲中製作美術資源時就可以用到這個技術,這樣我們就能確定物體共用紋理並且物體也是符合批處理條件的。Unity內建圖集打包工具(Sprite Packer)(5)手動合并共用相同材質和紋理的網格也是有可以的,要麼是在Unity Editor模式下要麼是在運行時通過程式碼完成。當使用這種方式合并網格時,我們應該要知道陰影,光照和裁剪仍然會逐對象級運行;這意味著通過合并網格實現的效能提升會被那些當不被渲染時就不再裁剪的物體抵消掉(this means that a performance increase from combining meshes could be counteracted by no longer being able to cull those objects when they would otherwise not have been rendered ),如果我們想研究這個方法,那就去測試Mesh.CombineMeshes這個方法(5)在代碼中使用Renderer.material需要注意。它會複製材質並且返回一個複製對象的引用。當這個renderer是合批中的一部分時,這樣做的話就會打破合批,因為這個renderer(渲染器)不再持有當前材質執行個體的引用了。如果想要在代碼中使用合批好的物體的材質,那就用Renderer.sharedMaterial. 裁剪,分類,批處理裁剪,收集將會被繪製的物體的資料,整合這些資料到批處理中並且產生GPU指令都將會促成CPU bound。這些任務要麼在主線程要麼在背景工作執行緒中執行,取決於遊戲設定和目標硬體。
  • 就裁剪本身而言是不太消耗效能的,但是刪減掉不必要的裁剪也是會有助於效能的提升的。對於情境中所有啟用的物體,包括那些不被渲染的層上的物體,都會有逐對象逐相機的日常開銷(per-object-per-camera overhead).我們可以通過disable相機並且deactivate或disable那些當前沒有使用的渲染器來減少開銷。
  • 批處理能夠很大程度上提升發送指令的速度(CPU發送給GPU的指令的速度),但有時候會在別的地方增加一些多餘的開銷。如果批處理操作促成了遊戲的CPU bound,那麼我們就應該限制手動的或自動的批處理操作了。
 蒙皮網格(1)當我們通過網格變形產生骨骼動畫時就會使用到蒙皮網格渲染器,它通常會在動畫角色中使用。渲染蒙皮網格的任務通常是在主線程或獨立的背景工作執行緒中執行,取決於遊戲設定和目標硬體裝置。(2)渲染蒙皮網格是一個很消耗效能的操作。如果因為渲染蒙皮網格促成了遊戲的CPU bound,我們可以嘗試以下幾個方法提升效能:
  • 我們應該考慮是否每一個物體(當前已經用了SkinnedMeshRenderer組件的)都需要使用SkinnedMeshRenderer組件,有個情況就是,我們匯入了一個使用了SkinnedMeshRenderer組件模型,但我們沒有給它動畫,像這樣的話,把SkinnedMeshRenderer組件替換成MeshRenderer組件是可以提升效能的。當我們匯入一個模型時,如果在“the model‘s import Settings”中選擇了不匯入動畫的話,這個模型就會使用MeshRenderer組件,而不是SkinnedMeshRenderer組件。
  • 如果只是在某些時候需要使用動畫(比如,在遊戲啟動時或僅僅在離攝像機一定距離時),我們可以換成網格細節更少的版本或者使用MeshRenderer。SkinnedMeshRenderer組件有一個BakeMesh功能,這個功能能產生匹配姿勢的網格, 能使不同網格或不同渲染器之間進行交換但卻不會造成任何視覺上的物體改變
  • https://docs.unity3d.com/Manual/ModelingOptimizedCharacters.html?_ga=2.87438096.925366423.1538040429-1156207016.1532919959  這篇文章給出了一些最佳化那些使用了蒙皮網格的動畫角色的建議。
  • https://docs.unity3d.com/Manual/class-SkinnedMeshRenderer.html?_ga=2.160772661.925366423.1538040429-1156207016.1532919959   這篇文章介紹SkinnedMeshRenderer,包括了怎麼去調整組件屬性等來提升效能。另外還有一些使用建議,需要記住,蒙皮網格的開銷是逐頂點增加的;減少模型頂點才能減少工作量。
  • 在某些平台上,蒙皮會被GPU處理,而不是CPU,如果GPU有足夠的能力,這樣的選擇是具有實驗研究價值的。我們可以在Player Setting中為當前平台和目標裝置啟用GPU skinning。
 主線程中跟渲染無關的一些操作:(1)許多跟渲染無關的操作會在主線程中執行,這意味著如果在主線程中遇到CPU bound了,我們是可以通過減少CPU花費在這些與渲染無關的任務上的時間來提升效能。(2)舉個栗子,在遊戲中,某些時候主線程可能會執行一些很消耗效能的渲染操作和代碼操作,促成了CPU bound。如果在沒有失真的前提下我們能儘可能最佳化這些渲染操作,那麼就有可能在代碼側減少CPU的開銷以提升效能。 如果我們的遊戲是GPU bound的情況:如果是GPU bound,那麼我們首先要做的就是找出是什麼造成了GPU的瓶頸,GPU效能通常會因為fill rate(填充率)而受限,尤其是在行動裝置上,但跟記憶體頻寬和頂點處理也有關係。下面就測試一下這些問題,瞭解是什麼原因造成的,如何診斷以及如何修補。 Fill rate所謂fill rate就是GPU每秒能夠渲染的像素數量。如果遊戲因為fill rate受限,這意味著遊戲每幀想嘗試繪製的像素超過了GPU能處理的上限。檢查是否是fill rate導致GPU bound是很簡單的:
  • 進行效能分析並紀錄好GPU時間
  • 在Player Setting中降低顯示解析度
  • 再次分析遊戲效能,如果效能有所提升,那麼就可以認為是fill rate造成GPU bound 的
    因為fill rate造成GPU bound的解決方案
  • 片元著色器是shader定義的一段代碼,它告訴GPU應該如何繪製每一個像素,GPU會為每一個需要被繪製的像素執行這部分代碼,所以如果這段代碼是低效的就會很容易增加效能開銷。複雜的片元著色器是造成fill rate問題的非常常見的原因
          -- 如果遊戲中用了Unity內建的著色器,盡量去使用那些最簡單的最佳化的著色器來實現我們想要的視覺效果。比如,https://docs.unity3d.com/Manual/shader-Performance.html?_ga=2.102053897.925366423.1538040429-1156207016.1532919959  the mobile shaders that ship with Unity 是高度最佳化的;嘗試去使用這個著色器看看是否不影響視覺效果並且提升了效能。這些著色器專門為移動平台設計的,但其實也適用其他任何項目。在保證項目視覺效果的基礎山,在非移動平台上使用“mobile”著色器是可以提升效能的。         --如果遊戲中的物體使用了Unity的標準著色器,應該要知道Unity是基於當前material設定去編譯當前著色器的。只有那些當前使用的特徵才會被編譯。這就意味著,去掉那些,比如細節貼圖,能夠使得片元著色器代碼簡單些,進而提升效能。還是一樣,去調整設定看看能不能提升效能。         --如果項目中使用了定製的著色器,要盡量去最佳化。最佳化著色器是非常複雜的,這有兩篇最佳化shader代碼的文章: https://docs.unity3d.com/Manual/SL-ShaderPerformance.html?_ga=2.154442288.925366423.1538040429-1156207016.1532919959             https://docs.unity3d.com/Manual/MobileOptimisation.html?_ga=2.154442288.925366423.1538040429-1156207016.1532919959 
  • 過渡繪製是指相同的像素被繪製了多次。這種情況是在一些物體在另一些物體上面繪製時發生的,並且這個很容易造成fill rate問題。為了搞明白過渡繪製,就要弄清楚Unity繪製情境物體的順序。物體的shader決定了它的繪製順序,通常是通過指定的渲染隊列。Unity利用這些資訊嚴謹繪製物體,文章:https://docs.unity3d.com/Manual/SL-SubShaderTags.html?_ga=2.160756277.925366423.1538040429-1156207016.1532919959        另外,在繪製前,不同渲染隊的物體會使用不同的排序方式。比如,Geometry隊列下,Unity從前往後對物體進行排序,以減少過渡繪製。Transparent隊列下,是從後往前來實現想要的視覺效果的。Transparent隊列下的從後往前的排序是會增加過渡繪製的。過渡繪製是非常複雜的研究課題,沒有唯一的方法解決這個問題,但減少重疊物體的數量是關鍵點,因為Unity不能自動對這些物體排序。在Unity Scene視窗可以很好的研究這個問題,Draw Mode(繪製模式)能讓我們看到情境中的過渡繪製,進而確定怎麼去減少(過渡繪製),造成過渡繪製最常見的罪魁禍首是透明材質(transparent material) 、沒有最佳化過的粒子,重疊的UI元素,所以最佳化或減少這些是可行的。https://unity3d.com/cn/learn/tutorials/topics/best-practices/fill-rate-canvases-and-input?playlist=30089  (關於UI和overdraw指導)
  • 圖片效果也是很容易造成fill rate問題的,尤其是當我們使用多種圖片效果時。如果遊戲使用了圖片效果並且造成了fill rate問題的話,我們應該去調整設定或使用更加最佳化的圖片效果(比如高光(最佳化過的)),如果在相同的相機中使用多種圖片效果,這將造成多次shader pass。在這種情況下,合并這些圖片效果的shader代碼成一個獨立的pass塊是有益的。比如Unity的延遲處理堆棧:https://github.com/Unity-Technologies/PostProcessing/wiki   如果經過最佳化後的圖片效果還是會有fill rate問題,那麼就要考慮不用圖片效果了,尤其是在低端的裝置上。
 記憶體頻寬(1)記憶體頻寬是指GPU從顯存中存取的速率。如果我們遊戲受到記憶體頻寬的限制,這意味著我們使用了太大的圖片,超過了GPU的快速處理能力(2)檢查一下是否是記憶體頻寬的問題:
  • 對遊戲進行效能分析並且紀錄GPU消耗時間
  • 在Quality Setting中設定好目標平台的目標品質,降低紋理品質
  • 重複第一個步驟,如果效能提升,那麼就能確定是記憶體頻寬的問題
如果記憶體頻寬造成效能問題,那麼就要降低紋理的記憶體使用量率了,下面有幾個方法能夠最佳化紋理
  • 紋理壓縮技術:能夠紋理的磁碟儲存大小和記憶體大小。如果記憶體頻寬在我們遊戲中會造成效能問題,使用紋理壓縮技術是可以提升效能的。在Unity中有多種紋理壓縮技術,每一種都有單獨的設定介面。通常來說,某些紋理壓縮是無論何時都是會被用到的,然而,一個實驗和錯誤能夠讓我們找到每一個紋理效能最好的最佳設定。請看這篇文章:https://docs.unity3d.com/Manual/class-TextureImporter.html?_ga=2.191165986.925366423.1538040429-1156207016.1532919959
  • 紋理映射(MipMaps)是最佳化方案中效果沒那麼好的技術,在Unity中可以用在遠處物體上。如果情境中有跟攝像機距離比較遠的物體,使用mipmaps能夠緩解記憶體頻寬帶來的問題。The MipMaps Draw Mode(https://docs.unity3d.com/Manual/ViewModes.html?_ga=2.103665800.925366423.1538040429-1156207016.1532919959)(Scene Mode下),能夠看到使用MipMaps後的好處,還有這篇文章:https://docs.unity3d.com/Manual/class-TextureImporter.html?_ga=2.199507494.925366423.1538040429-1156207016.1532919959   
 頂點處理(1)頂點處理是指GPU必須渲染網格頂點的過程。頂點處理的效能開銷受到以下兩個方面的影響:會被渲染的頂點的數量,在每一個頂點上執行的操作的次數(2)如果遊戲是GPU bound的話並且我們確定不是fill rate或記憶體頻寬的問題,那麼很可能就是頂點處理的問題。在這種情況下,嘗試減少GPU要執行的頂點處理的次數是可以提升效能的。 (3)下面介紹幾個可以減少渲染的頂點的數量或在每一個頂點上執行的操作的次數的方法
  • 首先,要減少那些不必要的複雜網格。如果使用了那些在遊戲中看不見的網格或因為產生時錯誤的有大量頂點的無效網格,這會讓GPU做很多無用功。降低頂點處理的開銷的最簡單的方法就是在我們的3D項目中產生更少頂點的網格
  • normal mapping(法線映射)技術是指紋理用在了可以產生龐大的複雜幾何結構幻覺的網格上的技術。一些GPU的效能開銷使用這個技術是可以提升效能的。https://docs.unity3d.com/Manual/StandardShaderMaterialParameterNormalMap.html?_ga=2.123024131.925366423.1538040429-1156207016.1532919959, 這篇文章指導我們使用normal mapping(紋理映射)來在網格上模仿複雜的幾何結構。
  • 如果網格中沒有使用紋理映射技術,一般會在網格的import settings中將vertex tangents(頂點切線)禁用掉。這種資料上的削減會設定到每一個頂點上
  • LOD(Level Of Detail 細節層次渲染)是一種可以降低遠離攝像機的網格的複雜度的最佳化技術。降低需要渲染的頂點數量且保證不失真。https://docs.unity3d.com/Manual/class-LODGroup.html?_ga=2.200163238.925366423.1538040429-1156207016.1532919959
  • 頂點著色器(shader代碼塊,告訴GPU如何繪製每一個頂點),如果遊戲因為頂點處理受限,那麼降低頂點著色器的複雜度是可以提升效能的
 結論:我們已經學習了在Unity中是如何渲染的,產生的問題的分類還有如何去提升渲染效能。利用這些知識加上效能分析工具,我們可以解決渲染效能問題並且使遊戲在一個高效流暢的渲染管線中構建。 擴充閱讀連結 https://unity3d.com/cn/learn/tutorials/topics/best-practices/guide-optimizing-unity-ui?playlist=30089     

渲染最佳化01

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.