Unity 之 性能優化 -- 靜態資源優化
- 參考性能指標
- 靜態資源
- 資源工作流程
- 資源分類
- 原理小結
- Audio 實戰優化建議
- 模型導入工作流程
- DCC中模型導出
- .DCC中Mesh生產規范
- 模型導出檢查流程
- 模型優化建議
- 紋理優化
- 紋理基礎概念
- 紋理類型
- 紋理大小
- 紋理顏色空間
- 紋理壓縮
- 紋理圖集
- 紋理過濾
- 紋理Mipmap
- 其他設置
- 什么時候不需要生成MipMaps?
- 紋理相關優化建議
- 選擇合適紋理過濾的最佳經驗:
- 其他可能有問題的紋理類型
- 動畫優化
- Rig標簽頁
- Animation標簽頁
- 動畫曲線數據信息
- 動畫文件導入設置優化后信息查看原則
參考性能指標
- 生成的Apk大小
- 三角形平均面數/峰值面數
- 渲染批次
- SetPassCall
- Fps
- 內存開銷
- 紋理資源開銷
- Mesh資源開銷
- 音效資源開銷
場景中的攝像機數量會影響整個渲染流程的復雜度
場景中的燈光數量會影響整個場景的光照復雜度與陰影復雜度
靜態資源
資源工作流程
導入 – 創建 – 構建 – 分發 – 加載
資源分類
- 外部導入資源:模型網格Mesh、紋理、音樂音效、字體、動畫、視頻等。
- 內部創建資源:Prefab、AnimationController、Timeline、RenderTexture、ParicleSystem、VFX等。
原理小結
我們創建的資源在不同平臺可能涉及到導入設置的改變,或者你創建的資源在不同開發平臺機器上打開,或者使用了其他第三方開發包。這些都需要涉及到平臺導入。
不同平臺上的合理的資源導入設置與資源規格,可以給程序帶來較高的效率。
推薦使用資源檢測工具:Unity UPR – Asset Chechker
Audio 實戰優化建議
資源檢查報告——Audio部分問題解讀
- 根據平臺選擇合理的音頻設置,原始音頻資源盡量采用未壓縮WAV格式
- 移動平臺對音樂音效統一采用單通道設置(Force to Mono),并將音樂采樣頻率設置為22050Hz
- 移動平臺大多數聲音盡量采用Vorbis壓縮設置,IOS平臺或不打算循環的聲音可以選擇MP3格式,對于簡短、常用的音效,可以采用解碼速度快的ADPCM格式(PCM為未壓縮格式)
- 當實現靜音功能時,不要簡單的將音量設置為0,應銷毀音頻(AudioSource)組件,將音頻從內存中卸載。
音頻片段加載類型說明
- 簡短音效導入后小于200kb,采用Decompress on Load模式
- 對于復雜音效,大小大于200kb,長度超過5秒的音效采用Compressed In Memory模式
- 對于長度較長的音效或背景音樂則采用Streaming模式,雖然會有CPU額外開銷,但節省內存并且加載不卡頓
模型導入工作流程
DCC中模型導出
Unity 支持多種標準和專有模型文件格式(DCC)。Unity 內部使用 .fbx 文件格式作為其導入鏈。最佳做法盡可能使用 .fbx 文件格式,并且不應在生產中使用專有文件格式。
優化原始導入模型文件,刪除不需要的數據
- 統一單位
- 導出的網格必須是多邊形拓撲網格,不能是貝塞爾曲線、樣條曲線、NURBS、NURMS、細分曲面等
- 烘培Deformers,在導出之前,確保變形體被烘培到網格模型上,如骨骼形變烘培到蒙皮權重上
- 不建議模型使用到的紋理隨模型導出
- 如果你需要導入blend shape normals,必須要指定光滑組smooth groups
- DCC導出面板設置, 不建議攜帶場景信息導出,如不建議導出攝像機、燈光、材質等信息,因為這些的信息與Unity內默認都不同。除非你自己為某DCC做過自定義導出插件。
.DCC中Mesh生產規范
必須
- 統一單位;
網格必須是多邊形拓撲網格,而不能是貝塞爾曲線、樣條曲線、NURBS、細分曲面等;
建議
- 盡可能合并網格、最小化面數、不要使用微三角形、分布均勻;
- 盡可能使用共享材質、減少材質個數;
- 盡可能不使用蒙皮網格;
- 盡可能少的骨骼數量,導入Unity前刪除IK節點;
- 盡可能減少影響SkinWeights的骨骼數量;
美術關心的導出設置
原始模型文件對性能的影響點:
- 最小化面數,不要使用微三角形,分布盡量均勻
- 合理的網絡拓撲和平滑組
- 盡量少的使用材質個數
- 盡可能少的使用蒙皮網格
- 盡可能少的骨骼數量
- FK與IK節點沒分離,IK節點沒刪除
模型導出檢查流程
- 檢查下是否存在Transform中Scale不為(1,1,1)的情況。若存在:如果好修改就順手改掉;不好改則建議讓美術同學重新加工下。Transform中Scale為(1,1,1)是后續檢查流程的前提。
- 確保Transform中Scale為1時,再次查看模型導入配置中的ScaleFactor和ConvertUnits的配置分別為1和enable。
- 若上述均已確認但大小依然不對,則可以認為是【Unity對于該模型格式(Fbx等)的尺度預設】與【美術對于該模型格式的默認尺度設置】不一致。
- 處理方案一:由美術重新調整模型尺度,即確保導出fbx中的單位1對應的是厘米。
- 處理方案二:調整Unity模型導入配置中的ScaleFactor。
- 不管怎么樣,都不應該讓Transform的Scale不為(1,1,1)。
BuildSetting-PlayerSetting-Optimization存在模型優化選項
VertexCompression配置項:- 對頂點使用Half的精度格式存儲。
- 其將減少內存中網格數據的大小,并稍微減少包體文件大小,同時提高 GPU 性能。
- 其將影響項目中每個Mesh的設置。對同一Mesh數據,頂點壓縮與網格壓縮不會同時存在,若FBX的ImportSetting中啟動MeshCompression相關配置,則此處的VertexCompression將失效。
- 該配置中各個選項具體是指,對哪些channel使用頂點壓縮,默認為Normal、Tangent、TexCoord0、TexCoord2、TexCoord3。默認開啟壓縮的通道為Unity推薦配置,若壓縮更多通道,需確認是否會產生額外的偽影。
- OptimizeMeshData選項:
開啟該選項時,則在打包時剔除Mesh頂點未被使用的channel數據。
模型優化建議
- 盡可能的將網格合并到一起
- 盡可能使用共享材質
- 不要使用網格碰撞體
- 不必要不要開啟網格讀寫
- 使用合理的LOD級別
- Skin Weights受骨骼影響個過多
- 合理壓縮網格
- 不需要rigs和BlendShapes盡量關閉
- 如果可能,禁用法線或切線
資源檢查報告——FBX部分問題解讀
其中兩項建議與模型動畫有關,而測試項目中所有模型資源都不涉及動畫,可以將Rig標簽下的Animation Type設置為None,并關閉Animation標簽下的Import Animations選項,設置Materials標簽中的Material Creation Mode為None.
開啟Project Settings —> Player —> Optimization下的Vertex Compression與Optimize Mesh Data選項
紋理優化
紋理基礎概念
紋理一般是指應用于模型表面用來增加細節的位圖圖像,通常情況下3D對象上一般需要一張或多張紋理,紋理需要通過材質著色器映射才能到3D對象面。
一般Unity中的紋理資源來自于外部圖像編輯工具,并導入到Unity中使用。當然也有一部分可以通過程序化生成紋理,包括在編輯器下通過代碼或烘焙生成,也可以運行時動態生成
紋理類型
- Default: 默認的紋理類型格式
- Normal map: 法線貼圖,可將顏色通道轉換為適合實時法線貼圖格式
- Editor GUI and Legacy GUI: 在編輯器GUI控件上使用紋理請選擇此類型
- Sprite(2D and UI): 在2D游戲中使用的精靈(Sprite)或UGUI使用的紋理請選擇此類型
- Cursor: 鼠標光標自定義紋理類型
- Cookie: 用于光照Cookie剪影類型的紋理
- Lightmap: 光照貼圖類型的紋理,編碼格式取決于不同的平臺
- Single Channel: 如果原始圖片文件只有一個通道,請選擇此類型
紋理大小
選擇合適紋理大小應盡量遵循以下經驗:
- 不同平臺、不同硬件配置選擇不同的紋理大小,Unity下可以采用bundle變體設置多套資源、通過Mipmap限制不同平臺加載不同level層級的貼圖。
- 根據紋理用途的不同選擇不同的紋理加載方式,如流式紋理加載Texture Streaming、稀疏紋理Sparse Texture、虛擬紋理VirtualTexture等方式。
- 不能讓美術人員通過增加紋理大小的方式增加細節,可以選擇細節貼圖DetailMap或增加高反差保留的方式。
- 在不降低視覺效果的情況下盡量減小貼圖大小,最好的方式是紋理映射的每一個紋素的大小正好符合屏幕上顯示像素的大小。如果紋理小了會造成欠采樣,紋理顯示模糊,如果紋理大了會造成過采樣,紋理顯示噪點。可以充分利用Unity編輯器中的【BuildIn:SceneView->DrawMode->Mipmap】或【URP:URP Render Debugger】,來查看在游戲攝像機視角下進行overdraw檢查,進而確認所需紋理大小。
紋理顏色空間
默認大多數圖像處理工具都會使用sRGB顏色空間處理和導出紋理。但如果你的紋理不是用作顏色信息的話,那就不要使用sRGB空間,如金屬度貼圖、粗糙度貼圖、高度圖或者法線貼圖等。一旦這些紋理使用sRGB空間會造成視覺表現錯誤。
紋理壓縮
? 紋理壓縮是指圖像壓縮算法,保持貼圖視覺質量的同時,盡量減小紋理數據的大小。默認情況下我們的紋理原始格式采用PNG或TGA這類通用文件格式,但與專用圖像格式相比他們訪問和采樣速度都比較慢,無法通用GPU硬件加速,同時紋理數據量大,占用內存較高。所以在渲染中我們會采用一些硬件支持的紋理壓縮格式,如ASTC 、ETC、ETC2、DXT等。
? 如下圖為未壓縮、ETC2、ASTC6x6三種格式文件大小對比,我們可以看到在質量相差不大的情況下ASTC6x6壓縮下大小可以減少到接近未壓縮的十分之一。
紋理圖集
紋理圖集是一系列小紋理圖像的集合,
-
優點:
- 一是采用共同紋理圖集的多個靜態網格資源可以進行靜態合批處理,減少DrawCall調用次數。
- 二是紋理圖集可以減少碎紋理過多,因為他們打包在一個圖集里,通過壓縮可以更有效的利用壓縮,降低紋理的內存成本和冗余數據。
-
缺點:
- 美術需要合理規劃模型,并且要求模型有相同的材質著色器,或需要制作通道圖去區分不同材質。制作和修改成本較高。
- 紋理尺寸限制。合并到紋理圖集中的每個小紋理都必須符合一定的尺寸限制。如果某些小紋理尺寸過大,可能會導致整個圖集的尺寸超出硬件或軟件的限制,從而限制了使用紋理圖集的場景。
- UV空間限制。在將多個小紋理合并成一個大紋理時,需要為每個小紋理分配一定的UV空間。如果小紋理之間的UV空間重疊或浪費過多,可能會導致圖集的利用率下降,從而減少了優化效果。
- 動態更新困難。由于紋理圖集是靜態的,一旦創建后就不易修改。這意味著如果需要動態加載或更新紋理,可能需要重新生成整個圖集,這會帶來一定的開銷和復雜性。
- 紋理壓縮損失。將多個小紋理合并成一個大紋理后,通常需要對圖集進行壓縮以減少內存占用。然而,壓縮會引入一定程度的紋理損失,可能會導致圖像質量下降。
- 不適用于所有場景。雖然紋理圖集在許多場景下都能夠有效提高性能,但并不適用于所有情況。例如,在需要頻繁動態加載或更新紋理的場景下,紋理圖集可能并不適用,因為它們不太靈活。
紋理過濾
- Nearest Point Filtering: 臨近點采樣過濾最簡單、計算量最小的紋理過濾形式,但在近距離觀察時,紋理會呈現塊狀。
- Bilinear Filtering: 雙線性采樣過濾會對臨近紋素采樣并插值化處理,對紋理像素進行著色。雙線性過濾會讓像素看上去平滑漸變,但近距離觀察時,紋理會變得模糊。
- Trilinear Filtering: 三線性過濾除與雙線性過濾相同部分外,還增加了Mipmap等級之間的采樣差值混合,用來平滑過度消除Mipmap之間的明顯變化。
- Anisotropic Filtering: 各向異性過濾可以改善紋理在傾斜角度下的視覺效果,跟適合用于地表紋理。
紋理Mipmap
Mipmap紋理
逐級減低分辨率來保存紋理副本。相當于生成了紋理LOD,渲染紋理時,將根據像素在屏幕中占據的紋理空間大小選擇合適的Mipmap級別進行采樣。
優點:
- GPU不需要在遠距離上對對象進行全分辨率紋理采樣,因此可以提高紋理采樣性能。
- 同時也解決了遠距離下的過采樣導致的噪點問題,提高的紋理渲染質量。
缺點:
- 由于Mipmap紋理要生成低分辨率副本,會造成額外的內存開銷。
可以通過Unity提供的MipMap Streaming功能,在運行時限制之采樣某個級別以下的紋理進行不同設備上的適配。另外MipPap也是做Hierarchy Z Code的前提條件,它是目前比較流行的剔除方案,
其他設置
Texture Shape
- 2D 最常用的2D紋理,默認選項
- Cube 一般用于天空和與反射探針,默認支持Default、Normal、Single Channel幾種類型紋理,可以通過Assets > Create > Legacy > Cubemap生成,也可以通過C#代碼 Camera.RenderToCubemap在腳本中生成
- 2D Array 2D紋理數組,可以極大提高大量相同大小和格式的紋理訪問效率,但需要特定平臺支持,可以通過引擎SystemInfo.supports2DArrayTextures 接口運行時查看是否支持。
- 3D 通過紋理位圖方式存儲或傳遞一些3D結構話數據,一般用于體積仿真,如霧效、噪聲、體積數據、距離場、動畫數據等信息,可以外部導入,也可運行時程序化創建。
Alpha Source
- 默認選擇Input Texture Alpha就好,如果確定不使用原圖中的Alpha通道,可以選擇None。另外From Gray Scale我們一般不會選用
Alpha Is Transparency
- 指定Alpha通道是否開啟半透明,如果位圖像素不關心是否要半透明可以不開啟此選項。這樣Alpha信息只需要占1bit。節省內存
Ignore Png file gamma
- 是否忽略png文件中的gamma屬性,這個選項是否忽略取決于png文件中設置不同gamma屬性導致的顯示不正常,一般原圖制作流程沒有特殊設置,這個選項一般默認就好。
Read/Write
- 開啟此選項會導致內存量增加一倍,默認我們都是不開啟,除非你的腳本邏輯中需要動態讀寫該紋理時需要打開此選項。
Streaming Mipmaps(Texture Streaming部分講解)
Virtual Texture Only(虛擬部分講解)
什么時候不需要生成MipMaps?
Generate Mip Maps
- 2D場景
- 固定視角,攝像機無法縮放遠近
- Border Mip Maps 默認不開啟,只有當紋理的是Light Cookies類型時,開啟此選項來避免colors bleeding現象導致顏色滲透到較低級別的Mip Level紋理邊緣上
- MipMap Filtering
- Box 最簡單,隨尺寸減小,Mipmap紋理變得平滑模糊
- Kaiser,避免平滑模糊的銳化過濾算法。
- Mip Maps Preserve Coverage,只有需要紋理在開啟mipmap后也需要做Alpha Coverage時開啟。默認不開啟。
- Fadeout MipMaps, 紋理Mipmap隨Mip層級淡化為灰色,一般不開啟,只有在霧效較大時開啟不影響視覺效果。
紋理相關優化建議
選擇合適紋理過濾的最佳經驗:
- 使用雙線性過濾平衡性能和視覺質量。
- 有選擇地使用三線性過濾,因為與雙線性過濾相比,它需要更多的內存帶寬。
- 使用雙線性和 2x 各向異性過濾,而不是三線性和 1x 各向異性過濾,因為這樣做不僅視覺效果更好,而且性能也更高。
- 保持較低的各向異性級別。僅對關鍵游戲資源使用高于 2 的級別。
其他可能有問題的紋理類型
- 紋理圖集大小設置不合理,圖集利用率低。【應合理設置圖集大小】
- 同一圖集中紋理資源生命周期不一致,也會造成內存長時間難以釋放。【應盡可能的將類似生命周期的小紋理打到同一圖集中】
- 不合理的半透明UI,占據大量屏幕區域,造成Overdraw開銷。【應盡量從UI設計上進行避免】
- 大量2D序列幀動畫,而且圖片大,還不打圖集。
- 大量只有顏色差異的圖片。【可采用分離變化區域貼圖,同時使用UI的九宮格縮放】
- UI背景貼圖而不采用9宮格縮放的圖。
- 純色圖沒有使用Single Channel。
- 不合理的通道圖利用方案。
- 大量漸變色貼圖,沒有采用1像素過渡圖,也不采用Single Channel, 粒子特效中較為常見。【貼圖可以替換為曲線數據或采用單像素梯度紋理,以減少貼圖的內存開銷和加載開銷】
動畫優化
Rig標簽頁
Animation Type
- None 無動畫
- Legacy 舊版動畫,不要用
- Generic 通用骨骼框架
- Humanoid 人形骨骼框架
選擇原則:
- 無動畫選擇None
- 非人形動畫選擇Generic
- 人形動畫
- 人形動畫需要Kinematices或Animation Retargeting功能,或者沒有有自定義骨骼對象時選擇Humanoid Rig
- 其他都選擇Generic Rig,在骨骼數差不多的情況下,Generic Rig會比Humanoid Rig省30%甚至更多的CPU的時間。
Skin Weights
? 默認4根骨頭,但對于一些不重要的動畫對象可以減少到1根,節省計算量
Optimize Bones
? 建議開啟,在導入時自動剔除沒有蒙皮頂點的骨骼
Optimize Game Objects
? 在Avatar和Animatior組件中刪除導入游戲角色對象的變換層級結構,而使用Unity動畫內部結構骨骼,消減骨骼transform帶來的性能開銷。可以提高角色動畫性能, 但有些情況下會造成角色動畫錯誤,這個選項可以嘗試開啟但要看表現效果而定。注意如果你的角色是可以換裝的,在導入時不要開啟此選項,但在換裝后在運行時在代碼中通過調用AnimatorUtility.OptimizeTransformHierarchy接口仍然可以達到此選項效果。
Animation標簽頁
Resmple Curves
? 將動畫曲線重新采樣為四元數數值,并為動畫每幀生成一個新的四元數關鍵幀,僅當導入動畫文件包含尤拉曲線時才會顯示此選項
Anim.Compression
- Off 不壓縮,質量最高,內存消耗最大
- Keyframe Reduction 減少冗余關鍵幀,減小動畫文件大小和內存大小。
- Keyframe Reduction and Compression 減小關鍵幀的同時對關鍵幀存儲數據進行壓縮,只影響文件大小。
- Optimal,僅適用于Generic與Humanoide動畫類型,Unity決定如何進行壓縮。
Animation Custom Properties
? 導入用戶自定義屬性,一般對應DCC工具中的extraUserProperties字段中定義的數據
動畫曲線數據信息
- Curves Pos: 位置曲線
- Quaternion: 四元數曲線 Resample Curves開啟會有
- Euler: 尤拉曲線
- Scale: 縮放曲線
- Muscles: 肌肉曲線,Humanoid類型下會有
- Generic: 一般屬性動畫曲線,如顏色,材質等
- **PPtr:**精靈動畫曲線,一般2D系統下會有
- **Curves Total: **曲線總數
- Constant: 優化為常數的曲線
- Dense: 使用了密集數據(線性插值后的離散值)存儲
- Stream: 使用了流式數據(插值的時間和切線數據)存儲
動畫文件導入設置優化后信息查看原則
- 一看效果差異(與原始制作動畫差異是否明顯)
- 二看曲線數量(總曲線數量與各種曲線數顯,常量曲線比重大更好)
- 三看動畫文件大小(以移動平臺為例,動畫文件在小幾百k或更少為合理,查過1M以上的動畫文件考慮是否進行了合理優化)
本文整理自:Metaverse大衍神君《Unity性能優化》