Unity性能優化
大的方面來說,通過Unity對于專案的性能優化大概可以分為下面幾個部分:
- 資源
- 渲染
- 程式
- 專案配置
而在這個部分中,資源的性能優化屬于最基礎、最有效的優化手段,也是游戲開發者日常開發最需要注意的一部分,所以本篇文章就簡單的介紹一下對資源進行操作時需要關注哪些點
一、紋理(簡單來說就是圖片)
紋理的資源優化主要集中于下面的幾點:
- 紋理大小
- 壓縮格式
- 匯入設定
通常,在游戲運行時,大部分記憶體都是用在了紋理上,因此你的匯入設定非常關鍵,我們可以在Inspector面板看到圖片資源的資訊,類似于下面這張圖:

從性能優化的角度看,紋理匯入需要遵循如下的原則:
- 降低最大解析度
- 采用二次冪壓縮格式:
- 制作紋理圖集
- 取消勾選
Read/Write Enabled - 禁用多余的
Mip Map:Mip Map貼圖在2D精靈和UI圖形這類大小始終一直的紋理上并無用處
1、降低最大解析度
很好理解,紋理解析度越大,在游戲運行時,占用的記憶體資源越大,并且占用的記憶體量是與其解析度的平方成正比的,也就是說,解析度變為原來的二倍,那么記憶體量就需要消耗四倍,因此需要從資源優化的角度來講,需要對其進行一定的限制,簡單的來說,一個Button的紋理通常低于128X128,如果使用1024X024規格的大小就造成了性能的浪費
如下面的圖,我們可以在圖片資源的Inspector面板中最下面的屬性中看到它:Max Size,同時可以看到可以根據不同平臺來選擇不同的最大解析度:
第一張圖片:Max Size調整為1024,紋理資源大小為4.9MB

第二張圖片:Max Size調整為512,圖片資源大小為1.3MB

2、對于紋理的壓縮
在你主動選擇壓縮格式之前,Unity本身會對圖片做一些處理,無論你放入的是PNG、JPG、PSD或者TGA,Unity都會手動幫助我們調整為Texture 2D,這是一種簡單的調度策略:

那么既然Unity本身都已經智能轉換好了,為什么還要給予開發者選擇壓縮格式的選擇呢,直接對Texture 2D封裝好壓縮方法不就可以了嗎?
其實Unity相對于其他開發引擎有一個很明顯的優勢,就是多適配性,那么為了實作這種多適配性,對于單一平臺的針對性就會相對減弱,而不同平臺的性能表現又不盡相同,就需要開發者來根據平臺特點來選擇針對游戲平臺的壓縮格式,
同樣,即使在同一平臺,也會根據不同的情況有著不同的壓縮需求,比如有一些關鍵的主頁面圖片,玩家感知強的地方,就對圖片的質量要求高些,一些邊角的輔助圖片,可能要求就低一些,如果都使用高質量壓縮,性能方面就造成了浪費,但若都是用低質量壓縮,質量又跟不上,所以,同樣需要根據實際需求選擇不同的壓縮格式,
在說到Unity圖片壓縮時,經常會看到這樣一張圖,來介紹不同壓縮格式的特點與適用場景,我也是百度圖片直接爬取的這張圖片,大家可以參考著來看(如果有侵權,請告知我,我會立刻洗掉)

在理解上面這張圖之前做一個簡單的計算,一張1024乘1024的RGBA32格式圖片的占用存盤空間為:
由于RGBA32一個像素每一個顏色值是由兩個16進制的陣列成,也就是8位,那個一個像素就是8位乘以4個顏色值R、G、B、A得到的是4個位元組,即4B,然后乘上1024*1024個像素,最終得到的大小為4MB,也就是4兆,很明顯這是很恐怖的一個數字,要知道現在移動端手機的運行記憶體大概6G,除去系統的占用記憶體,真正給游戲用的最多也就4G`,再分配給GPU|的顯存就更少了,而若這些記憶體被用來大量加載貼圖很明顯是不能被接受的,同時,這樣資料量的圖片加載也會給記憶體
基于上面原生紋理帶來的包體與記憶體問題,就需要根據不同的情況采取一些壓縮策略,由于本人基本沒有美術功底,所以對與各種壓縮格式的美術呈現效果不是很了解,主要是從功能性與性能的角度來分析各種壓縮格式的適用場景:
-
高品質壓縮格式:
RGBA32作為一種高保真的壓縮格式,能夠極大的保證圖片質量 -
中品質壓縮格式:
RGBA16+Dithering一聽就是RGBA32的閹割版,簡單來說,相比于RGBA32其色彩細分程度大,可以明顯的看出階梯感,視覺表現相對于RGB32不夠平滑 -
低品質壓縮格式:
ETC1+Alpha/PVRTC4這些壓縮格式往往是移動段最常用的壓縮格式,其相對于其他壓縮格式有著無可比擬的性能優勢
注意:
- 除了由于壓縮邏輯不同帶來的加載帶寬減少之外,同時還需要了解像
ETC1、PVRTC4等這類在記憶體中不需要進行解壓,而是可以直接被GPU支持,所以相比其他壓縮格式通常會有最好的性能表現
3、取消勾選Read/Write Enabled
該功能是為了使得游戲開發者可以通過C#腳本呼叫對與圖片的讀取與寫入的控制,很明顯,這是由CPU來控制實作的,所以為了可以使得CPU獲取資料,需要在記憶體中備份一份讓CPU訪問,同時為了圖形渲染與顯示,又會將其加載到顯存中為GPU提供資料,
簡單來說,該選項會在游戲運行時,分別在CPU記憶體與GPU記憶體中備份出一張貼圖,如果你并不需要對于紋理進行讀寫操作,可以嘗試關閉該選項,這樣就可以避免游戲運行時占用多余的記憶體
4、禁用多余的Mip Map
Mip Map類似于模型的LOD,同樣是一種基于渲染距離改變渲染貼圖精度的技術,其優勢是在物體距離渲染距離比較遠時,可以節省性能,但是使用Mip Map時會增大記憶體占用量,
Mip map的技術原理是根據原始圖進行2的冪次方的遞減來生成一組不同精度的圖片,當游戲運行時,會將這組圖片加載到記憶體中,然后根據渲染的距離不同,來使用不同精度的圖片,
Mip map會增大多大的記憶體占用量呢
- 在我們使用
Mip map時,假設大小為256X256,并且會生成8張不同精度的圖片,根據2的冪次方進行遞減計算每張貼圖大小并累加,這樣最終得到的圖片組的體積大概比原來的單張貼圖大33%
通過一個實體來驗證,假設原始圖片大小為8M,生成的第一張低精度圖片的大小為2M(解析度減少一半,大小就會變為原來的四分之一,很好理解)這樣大概遞減8次,然后累加,就會獲取最終的圖片組大小,通過一個簡單的遞回方法來計算一下:
public void Awake()
{
Debug.Log(GetMipmapSize(8, 8)/8);
}
// index:處理總層級數 imageSize:初始大小 回傳增大的記憶體量
float GetMipmapSize(int index,float imageSize)
{
float lastSize = 0;
if (index == 1)
{
lastSize = imageSize*0.25f;
}
if (index > 1)
{
lastSize = imageSize * 0.25f + GetMipmapSize(index - 1, imageSize * 0.25f);
}
return lastSize;
}
執行程式,得到的結果為:

可以看到,求到的結果是接近于33%,當然如果Mip Map對一張紋理的處理不是八次,計算的結果會有偏差但是實際上,從三次往上,記憶體占用量的增加比例已經非常少了,基本都維持在33%左右,將上面的代碼稍微修改,做個小驗證:
public void Awake()
{
for (int i = 3; i < 15; i++)
{
Debug.Log(string.Format("處理 {0} 次記憶體占用量為: {1}",i,GetMipmapSize(i, 8) / 8));
}
}
float GetMipmapSize(int index,float imageSize)
{
float lastSize = 0;
if (index == 1)
{
lastSize = imageSize*0.25f;
}
if (index > 1)
{
lastSize = imageSize * 0.25f + GetMipmapSize(index - 1, imageSize * 0.25f);
}
return lastSize;
}
得到的日志為:

可以發現,從三層開始,基本就維持在33%的記憶體占用量,并且在層數逐漸增大的時候,記憶體占用量增加量就非常非常少了,
而Unity所支持的紋理最小為32X32,也就是最小的紋理也會額外的產生三層低精度紋理:16X16、4X4、1X1,這就是為什么很多文章介紹到使用Map mip會說其大約會增加33%的記憶體占用量
雖然Mip map本身是一種性能優化的技術,但是在2D精靈或者UI元素這些不會改變渲染精度的紋理上,只會占用多余的記憶體,所以在2D精靈或者UI元素上使用紋理時記得不要勾選Mip map,
5、打包圖集
圖集的打包主要是優化UI圖形渲染程序中Draw call的數量,其基本原理也是通過UI元素合批來減少Draw Call,進入提升CPU的性能表現,關于其具體細節,可以查看我之前的文章:
圖集打包文章:
- Unity 將Sprite打包進圖集
二、模型
相比與紋理,模型的性能表現更多的取決于美術規范,程式來講沒有更多可以優化的地方,但是在Unity中也有一些選項影響模型加載、渲染等方面的性能表現,我們可以在匯入時看到:

1、禁用掉Reader/Write Enables:
點擊模型,可以在Inspector面板看到這些設定選項,類似于紋理,如果在游戲中,你不需要對模型進行修改,可以禁用掉Reader/Write Enables來避免資料的備份而占用多余的記憶體,我們可以在Unity官方檔案中找到相關介紹:

翻譯過來就是:
-
啟用此選項后,
Unity會將Mesh資料上傳到GPU可尋址記憶體,但也會將其保存在CPU可尋址記憶體中,這意味著Unity可以在運行時訪問Mesh資料,可以從腳本中訪問它, -
而禁用此選項后,
Unity會將Mesh資料上傳到GPU可尋址記憶體,然后將其從CPU可尋址記憶體中洗掉 -
默認情況下,此選項處于禁用狀態,在大多數情況下,要節省運行時記憶體使用量,請禁用此選項
而對于模型本身來說,盡量避免模型留有多余的面數,尤其是移動端,因為高精度模型除了本身所帶來的壓力外,在其他方面也有諸多的性能挑戰
2、盡量不要勾選不需要的功能選項
在Unity中,某些功能即使你未使用到,也會 消耗一定的資源去維護其狀態,類似上面的Reader/Write Enables選項,所以用不到的功能我們可以考慮盡量的去禁用掉
3、設定一些關于質量與性能的選項
Unity提供了一些對模型進行優化的選項,可以查閱Unity官方檔案來閱讀了解他們,這里也簡要的列出:

通過上面一張圖片可以看出,影響模型表現與游戲性能的選項有下面幾個:
Mesh Compression:通過使用網格邊界和每個組件較低的位深度來壓縮網格資料,增加壓縮率會降低網格的精度,最好在Mesh看起來與未壓縮版本沒有太大區別的情況下將其調得盡可能高,這對于優化游戲大小很有用Optimize Mesh:確定三角形在網格中列出的順序以獲得更好的GPU性能,默認都會勾選Normals:如果網格模型既不是法線貼圖也不受實時光照影響,就選用None,這樣也能夠很好的提升性能表現
其實,Unity設定了一些通程序式控制模型質量來改變性能表現的選項,但是不建議使用,預期通過這些選項來調整性能表現,還不如直接讓美術直接處理模型,畢竟他們更加專業,可以更好的保證模型的表現效果與性能表現的平衡,
4、使用LOD
關于LOD,其實應該在渲染這一段來講,但是這個技術又與模型網格有很大的關系,所以提前介紹一下
LOD即Levels of Detail,翻譯過來就是多層次細節,類似與紋理渲染的Mip map技術,同樣是一種根據渲染距離設定渲染精度的一種技術,其實作方式是在游戲開發時,美術根據不同的渲染距離制作一組不同精度的模型,匯入到Unity通過LOD組件連接其這一組模型,并設定相關引數,這樣在游戲運行時,就會在不同的距離有不同的渲染精度:

這是Unity官方檔案的一個案例,可以看出,隨著渲染距離的增加,渲染精度逐漸下降,直到最終被剔除,這樣做的優勢是保證游戲畫面表現的同時,可以最大程度降低渲染壓力,簡單的理解,如果不采用LOD,隨著距離增加,物體占用的螢屏像素就會越少,那么單位像素的三角面數就會越多,單位的渲染壓力就會增大,畫面表現需求不高的地方渲染壓力反而更高,這顯然是不合理的,所以就需要通過LOD來解決這樣的問題,
當然這種技術本身也是有相當大的缺陷的,首先就是會增大包體的體積,同時也會增加美術的作業量,所以在實際開放中,一般只會對一些重要的物件使用該技術
總結
上面所介紹的關于資源影響游戲性能的一些常用的點,都是游戲開發者日常接觸最多的,更深入,更底層的就需要根據專案的特點進行專門的適配與調整,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297931.html
標籤:其他
上一篇:五子棋2pygame代碼
