優(yōu)化圖形性能
良好的性能對(duì)很多游戲的成功至關(guān)重要。以下幾條簡(jiǎn)單法則有助于將游戲的渲染速度最大化。
找出影響圖形性能的主要因素
游戲的圖形部分主要影響計(jì)算機(jī)的兩個(gè)系統(tǒng):CPU 和 GPU。找到性能問(wèn)題所在是一切優(yōu)化的首要法則,因?yàn)?GPU 與 CPU 的優(yōu)化策略大不相同(甚至相反;例如,通常在優(yōu)化 CPU 時(shí)讓 GPU 做更多工作,反之亦然)。
常見(jiàn)瓶頸及檢查方法:
GPU 通常受填充率或內(nèi)存帶寬制約。
降低顯示分辨率并運(yùn)行游戲。如果顯示分辨率降低后游戲運(yùn)行更快,表明 GPU 填充率可能是限制因素。
CPU 通常受到需要渲染的批次數(shù)的限制。
檢查?Rendering Statistics?窗口中的“batches”。渲染的批次越多,CPU 成本越高。
不太常見(jiàn)的瓶頸:
GPU 有太多頂點(diǎn)需要處理。可接受的能確保良好性能的頂點(diǎn)數(shù)量取決于 GPU 和頂點(diǎn)著色器的復(fù)雜程度。一般來(lái)說(shuō),移動(dòng)端應(yīng)不超過(guò) 100,000 個(gè)頂點(diǎn)。另一方面,即使有數(shù)百萬(wàn)個(gè)頂點(diǎn),PC 也能管理到位,不過(guò)最好還是通過(guò)優(yōu)化盡可能減少此數(shù)量。
CPU 有太多頂點(diǎn)需要處理。這些頂點(diǎn)可能位于蒙皮網(wǎng)格、布料模擬、粒子或其他游戲?qū)ο蠛途W(wǎng)格中。如上所述,通常較好的做法是在不影響游戲質(zhì)量的情況下盡可能降低此數(shù)量。有關(guān)如何執(zhí)行此類操作的指導(dǎo),請(qǐng)參閱下面有關(guān)?CPU 優(yōu)化的部分。
如果渲染在 GPU 或 CPU 方面不是問(wèn)題,則可能在其他地方存在問(wèn)題,例如在腳本或物理系統(tǒng)中。請(qǐng)使用?Unity Profiler?找出問(wèn)題。
CPU 優(yōu)化
為了在屏幕上渲染對(duì)象,CPU 需要做很多處理工作:確定哪些光源影響該對(duì)象,設(shè)置著色器和著色器參數(shù),向圖形驅(qū)動(dòng)程序發(fā)送繪制命令,而圖形驅(qū)動(dòng)程序隨后將準(zhǔn)備發(fā)送到顯卡的命令。
所有這種基于“每個(gè)對(duì)象”的 CPU 使用率都是非常消耗資源的,所以如果有很多可見(jiàn)對(duì)象,影響就會(huì)累加起來(lái)。例如,如果有一千個(gè)三角形,如果它們都在一個(gè)網(wǎng)格中,而不是每個(gè)三角形在一個(gè)網(wǎng)格中(這種情況下加起來(lái)就有 1000 個(gè)網(wǎng)格),則 CPU 處理起來(lái)就比較容易。兩種方案的 GPU 成本非常相似,但 CPU 完成渲染一千個(gè)對(duì)象(而不是一個(gè))的工作要高得多。
減少可見(jiàn)對(duì)象數(shù)量。要減少 CPU 需要執(zhí)行的工作量,請(qǐng)執(zhí)行以下操作:
通過(guò)手動(dòng)方式或使用 Unity 的繪制調(diào)用批處理將近處對(duì)象組合在一起。
通過(guò)將單獨(dú)的紋理放入更大的紋理圖集,在對(duì)象中使用更少的材質(zhì)。
減少可能導(dǎo)致對(duì)象多次渲染的因素(例如反射、陰影和每像素光照)。
將對(duì)象組合在一起,使每個(gè)網(wǎng)格至少有幾百個(gè)三角形,并使整個(gè)網(wǎng)格只使用一種__材質(zhì)__。請(qǐng)注意,組合兩個(gè)不共享材質(zhì)的對(duì)象根本不會(huì)提高性能。需要多種材質(zhì)的最常見(jiàn)原因是兩個(gè)網(wǎng)格不共享相同的紋理;為了優(yōu)化 CPU 性能,請(qǐng)確保組合的所有對(duì)象共享相同的紋理。
在前向渲染路徑中使用大量像素光照時(shí),有些情況下組合對(duì)象可能沒(méi)有意義。請(qǐng)參閱下面的光照性能部分,了解如何管理此情況。
GPU:優(yōu)化模型幾何體
優(yōu)化模型幾何體有兩個(gè)基本規(guī)則:
除非必要,否則不要使用三角形
盡可能降低 UV 貼圖接縫和硬邊(雙倍頂點(diǎn))的數(shù)量
請(qǐng)注意,圖形硬件必須處理的實(shí)際頂點(diǎn)數(shù)通常與 3D 應(yīng)用程序報(bào)告的數(shù)量不同。建模應(yīng)用程序通常顯示的是構(gòu)成模型的不同角點(diǎn)的數(shù)量(稱為幾何頂點(diǎn)數(shù))。但是,對(duì)于顯卡,為了進(jìn)行渲染,需要將一些幾何頂點(diǎn)拆分成兩個(gè)甚至更多個(gè)邏輯頂點(diǎn)。如果頂點(diǎn)具有多個(gè)法線、UV 坐標(biāo)或頂點(diǎn)顏色,則必須將其拆分。因此,Unity 中的頂點(diǎn)計(jì)數(shù)通常高于 3D 應(yīng)用程序給出的計(jì)數(shù)。
雖然模型中的幾何體數(shù)量主要與 GPU 相關(guān),但 Unity 中的某些功能也要在 CPU 上處理模型(例如,網(wǎng)格蒙皮)。
光照性能
速度最快的方案是始終創(chuàng)建根本不需要計(jì)算的光照。要做到這一點(diǎn),使用光照貼圖只需一次“烘焙”靜態(tài)光照,而無(wú)需每幀計(jì)算。生成光照貼圖環(huán)境的過(guò)程只比在 Unity 場(chǎng)景中放置光源稍久一點(diǎn),但是:
運(yùn)行速度要快得多(每像素 2 個(gè)光源的情況下,速度快 2–3 倍)
視覺(jué)效果要好得多,因?yàn)榭梢院姹喝止庹?,使光照貼圖顯得更平滑
在許多情況下,可運(yùn)用簡(jiǎn)單的技巧,無(wú)需添加多個(gè)額外的光照。例如,無(wú)需添加直接照入攝像機(jī)的光源來(lái)提供__邊緣光照__效果,而是直接在著色器中添加專用的?Rim Lighting
?計(jì)算(請(qǐng)參閱表面著色器示例以了解如何執(zhí)行此操作)。
前向渲染中的光照
另請(qǐng)參閱:前向渲染
對(duì)于所有像素,動(dòng)態(tài)光照會(huì)為每個(gè)受影響的像素增加渲染工作,可能導(dǎo)致對(duì)象在多個(gè) pass 中被渲染。避免在性能較弱的設(shè)備(如移動(dòng)端或低端 PC GPU)上使用多個(gè)__像素光照__來(lái)照射單個(gè)對(duì)象,應(yīng)使用光照貼圖實(shí)現(xiàn)靜態(tài)對(duì)象的光照,而不是每幀計(jì)算其光照。每頂點(diǎn)動(dòng)態(tài)光照可能會(huì)為頂點(diǎn)變換增加顯著的工作量,因此盡量避免多個(gè)光源照射單個(gè)對(duì)象的情況。
避免組合距離足夠遠(yuǎn)而需要受到不同像素光照影響的網(wǎng)格。使用像素光照時(shí),每個(gè)網(wǎng)格必須渲染多次,因?yàn)橹灰l(fā)生像素光照就要進(jìn)行渲染。如果組合兩個(gè)相距很遠(yuǎn)的網(wǎng)格,則會(huì)增加組合對(duì)象的有效大小。照射該組合對(duì)象任何部分的所有像素光照在渲染期間都要考慮在內(nèi),因此需要?jiǎng)?chuàng)建的渲染 pass 的數(shù)量可能增加。通常情況下,為渲染組合對(duì)象而必須創(chuàng)建的 pass 數(shù)為每個(gè)單獨(dú)對(duì)象的 pass 數(shù)之和,因此進(jìn)行網(wǎng)格組合并不會(huì)獲得任何好處。
在渲染過(guò)程中,Unity 會(huì)查找網(wǎng)格周圍的所有光源,并計(jì)算出哪些光源對(duì)網(wǎng)格的影響最大。使用質(zhì)量設(shè)置 (Quality Settings)?可修改多少個(gè)光源用于像素光照以及多少個(gè)用于頂點(diǎn)光照。每個(gè)光源根據(jù)它與網(wǎng)格的距離以及它的光照強(qiáng)度來(lái)計(jì)算其重要性;純粹從游戲背景而言,有些光源比另一些光源更重要。鑒于此原因,每個(gè)光源都有?Render Mode?設(shè)置,可設(shè)置為?Important?或?Not Important__;標(biāo)記為?Not Important__ 的光源具有較低的渲染開(kāi)銷。
示例:假設(shè)有一個(gè)駕駛游戲,玩家的汽車在黑暗中行駛,前照燈已打開(kāi)。前照燈可能是游戲中視覺(jué)上最重要的光源,因此它們的?Render Mode?應(yīng)設(shè)置為?Important。游戲中可能還有其他不太重要的光源,比如其他汽車的尾燈或遠(yuǎn)處的燈柱,這些光源不能通過(guò)像素光照來(lái)大幅改善視覺(jué)效果。這種情況下,可放心地將這些光源的?Render Mode?設(shè)置為 __Not Important__,從而避免將渲染能力浪費(fèi)在無(wú)用之處。
通過(guò)優(yōu)化每像素光照可以節(jié)省 CPU 和 GPU 工作量:CPU 的繪制調(diào)用將減少,而 GPU 要處理的頂點(diǎn)將減少,同時(shí)為所有其他對(duì)象渲染柵格化的像素也將減少。
GPU:紋理壓縮和 Mipmap
使用壓縮紋理可減小紋理的大小。這種做法可加快加載時(shí)間、減小內(nèi)存占用并顯著提高渲染性能。與未壓縮的 32 位 RGBA 紋理所需的內(nèi)存帶寬相比,壓縮紋理使用的內(nèi)存帶寬要小得多。
紋理 Mipmap
對(duì)于 3D 場(chǎng)景中使用的紋理,應(yīng)始終啟用?Generate mipmaps?選項(xiàng)。Mipmap 紋理使 GPU 能夠?yàn)檩^小的三角形使用較低分辨率的紋理。這一點(diǎn)類似于紋理壓縮可以幫助限制 GPU 渲染時(shí)傳輸?shù)募y理數(shù)據(jù)量。
此規(guī)則的唯一例外是當(dāng)已知紋理像素將 1:1 映射到渲染的屏幕像素時(shí)(與 UI 元素或在 2D 游戲中一樣)。
LOD(細(xì)節(jié)級(jí)別)和每層剔除距離
剔除對(duì)象涉及使對(duì)象不可見(jiàn)。這是減輕 CPU 和 GPU 負(fù)載的有效方法。
在許多游戲中,在不影響玩家體驗(yàn)的情況下快速有效地執(zhí)行此操作的方法是,相對(duì)于大對(duì)象,更激進(jìn)地剔除小對(duì)象。例如,可讓遠(yuǎn)處的小巖石和碎片不可見(jiàn),而大型建筑物仍然保持可見(jiàn)。
有多種方式實(shí)現(xiàn)此目標(biāo):
使用細(xì)節(jié)級(jí)別系統(tǒng)
手動(dòng)設(shè)置攝像機(jī)上的每層剔除距離
將小對(duì)象放入單獨(dú)一層,并使用?Camera.layerCullDistances?腳本函數(shù)設(shè)置每層剔除距離
實(shí)時(shí)陰影
實(shí)時(shí)陰影很不錯(cuò),但它們對(duì)性能有很大影響,同時(shí)會(huì)增加 CPU 的繪制調(diào)用次數(shù)和 GPU 的處理量。有關(guān)更多詳細(xì)信息,請(qǐng)參閱光照性能頁(yè)面。
GPU:編寫高性能著色器的技巧
不同的平臺(tái)具有截然不同的性能;與低端移動(dòng)端 GPU 相比,高端 PC GPU 在圖形和著色器方面的處理能力要高得多。即使在單一平臺(tái)上也是如此;快速的 GPU 比慢速的集成 GPU 快幾十倍。
移動(dòng)平臺(tái)和低端 PC 上的 GPU 性能可能遠(yuǎn)低于開(kāi)發(fā)機(jī)器上的 GPU 性能。建議手動(dòng)優(yōu)化著色器以減少計(jì)算和紋理讀取,從而在低端 GPU 機(jī)器上獲得良好的性能。例如,某些內(nèi)置的 Unity 著色器具有速度快得多但存在一些限制或近似處理的“移動(dòng)端”等效項(xiàng)。
以下是移動(dòng)端和低端 PC 顯卡的一些指導(dǎo)原則:
復(fù)雜的數(shù)學(xué)運(yùn)算
超越數(shù)學(xué)函數(shù)(例如?pow
、exp
、log
、cos
、?sin
、tan
)都很消耗資源,所以盡量避免使用它們。如果可能,請(qǐng)盡量考慮使用查找紋理作為復(fù)雜數(shù)學(xué)計(jì)算的替代方法。
避免編寫自己的運(yùn)算(如?normalize
、dot
、inversesqrt
)。Unity 的內(nèi)置選項(xiàng)確保驅(qū)動(dòng)程序可以生成好得多的代碼。請(qǐng)記住,Alpha 測(cè)試 (discard
) 運(yùn)算通常會(huì)使片元著色器變慢。
浮點(diǎn)精度
雖然浮點(diǎn)變量的精度(float
?與?half
?與?fixed
) 在桌面平臺(tái) GPU 上很大程度上會(huì)被忽略,但在移動(dòng)端 GPU 上 對(duì)于獲得良好性能非常重要。有關(guān)詳細(xì)信息,請(qǐng)參閱?著色器數(shù)據(jù)類型和精度?頁(yè)面。
有關(guān)著色器性能的更多詳細(xì)信息,請(qǐng)參閱著色器性能頁(yè)面。
用于提高游戲運(yùn)行速度的簡(jiǎn)單核對(duì)表
在針對(duì) PC 平臺(tái)進(jìn)行構(gòu)建時(shí),保持頂點(diǎn)數(shù)量低于 200K 和 3M/幀(具體值取決于目標(biāo) GPU)。
如果要使用內(nèi)置著色器,請(qǐng)從?Mobile?或?Unlit?類別中選取。這些類別也適用于非移動(dòng)平臺(tái),但它們是更復(fù)雜著色器的簡(jiǎn)化和近似版本。
保持每個(gè)場(chǎng)景使用較少的不同材質(zhì),并盡可能在不同對(duì)象之間共享材質(zhì)。
在非移動(dòng)對(duì)象上設(shè)置?
Static
?屬性以便允許內(nèi)部?jī)?yōu)化,如靜態(tài)批處理。只有一個(gè)(最好是方向性的)
pixel light
?影響幾何體(而不是有多個(gè))。烘焙光照而不是使用動(dòng)態(tài)光照。
盡可能使用壓縮紋理格式,并使用 16 位紋理而非 32 位紋理。
盡可能避免使用霧效。
如果復(fù)雜的靜態(tài)場(chǎng)景具有大量遮擋,使用遮擋剔除減少可見(jiàn)幾何體數(shù)量和繪制調(diào)用次數(shù)。設(shè)計(jì)關(guān)卡時(shí)注意遮擋剔除。
使用天空盒“偽造”遠(yuǎn)處的幾何體。
使用像素著色器或紋理組合器來(lái)混合多個(gè)紋理而不是使用多 pass 方法。
盡可能使用?
half
?精度變量。最大限度減少在像素著色器中使用復(fù)雜的數(shù)學(xué)運(yùn)算,例如?
pow
、sin
?和?cos
。每個(gè)片元使用更少的紋理。