這是一個關于Unity游戲包體優(yōu)化方案的全面介紹
打包規(guī)則
- 所有非editor下的托管代碼會編譯為dll,dll會進入包體。
- 所有StreamingAssets下的文件會被復制到包體。
- 所有Resource下的資源會被無條件打包。
- 所有加入到構建中的場景以及他們所引用的所有資源都會進入包體,如場景使用了模型,模型使用了材質(zhì),材質(zhì)使用了shader和貼圖,這些資源都被引用了。
- 其他一些閃屏,icon等
- plugin下的本地庫等會視情況打包
Unity文檔中的優(yōu)化方案
先看一下Unity文檔中對于優(yōu)化iOS包體的建議:
http://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html
文檔最后最后列出清單如下:
- 最小化資源(assets),對貼圖使用PVRTC壓縮,并且盡可能減小分辨率
- 設置striping level 為 use micro mscorlib
- 設置 script call optimization 為 Fast but no excetions
- 不要在代碼中使用任何System.dll或System.Xml中的東西,這些庫和micro mscorlib不兼容
- 移除不必要的代碼依賴
- 設置API兼容等級為.net2.0 subset,注意.net2.0 subset對一些庫有限制和兼容性問題
- 不要使用JS數(shù)組
- 避免泛型容器使用值類型,包括結構體
可以看出來優(yōu)化大小主要有以下幾個方面、資源大小,代碼優(yōu)化,Unity設置。
Unity設置
先說Unity設置,因為這個最簡單,功能是固定的,使用情況也是固定的,基本只要程序正常執(zhí)行,選擇包最小的設置即可。
Striping Level 裁剪等級
裁剪等級設置的越小,代碼裁剪的越多,包體也就越小,但是會帶來一些限制,所以酌情使用即可。具體可參考Unity文檔。
.net subset .net子集
.net中常用功能均在.net子集中,如果你只使用了這些功能,就可以選用.net子集,.net子集比.net2.0大約小1M-2M
script call optimization (iOS)(不詳)
根據(jù)文檔,選擇Fast but no exceptions會減少大小,但具體減少多少未測試,且選擇這項從字面理解應該是出現(xiàn)異常應用會閃退。
削減架構支持
比如安卓如果只打算支持armv7設備,則不要選擇x86或arm+x86,iOS同理(bitcode待測試)
代碼優(yōu)化
代碼優(yōu)化能帶來的效果有限,簡單說下.
移除不必要的代碼依賴
如果你的代碼中存在一些大型庫的源碼或dll,如json.net,但卻并沒有用到,應該將其移除,這些代碼或dll可能占用比較大的空間(json.net的dll占用1M),如果經(jīng)過il2cpp編譯則可能更大。
JS數(shù)組問題(不詳,一般也不會用到JS腳本)
文檔中提到,具體不詳
避免值類型作為泛型(不詳,且難以避免)
文檔中提到,具體不詳
資源優(yōu)化
資源占用大小最多,資源類型和優(yōu)化方式也非常多,具體選擇優(yōu)化方案也需要根據(jù)實際情況和經(jīng)驗來判斷。
Assets與StreamingAssets的區(qū)別
要理清資源優(yōu)化的關鍵,先搞清Assets與StreamingAssets的區(qū)別
StreamingAssets下的文件,在打包時會直接復制進包里,只能通過IO或者WWW讀取成Assets之后才能使用
Assets是一般的資源,比如拖拽在腳本上的引用的物體,圖片,聲音等,以及放在Resources下的文件。直接訪問代碼的引用或者Resources.load使用。
可以看出來Assets和StreamingAssets的第一個區(qū)別就是StreamingAssets需要IO讀取成Assets,而Assets好像Unity會在引用到時,或者Resources.load時自動載到內(nèi)存中
StreamingAssets打包時是直接復制的文件,jpg還是原來的jpg,png還是原來的png,文件一點也不會變,而Assets是經(jīng)過Unity處理過的,處理成了3D引擎或者硬件可以直接使用的格式,比如圖片在nvidia顯卡中以dds或dxt格式使用。于是,可以理解streamingAssets是磁盤上的資源,assets是內(nèi)存中的資源,需要注意的是并非所有Assets都是內(nèi)存格式打包的。
下面將streamingAssets這類資源成為流資源,將Assets稱為內(nèi)存資源。
圖片
圖片是游戲中使用最多的資源,使用方式繁多,因此將會花大篇幅介紹優(yōu)化理論和技巧。
有了以上理論就可以解釋Unity的Inspector圖片預覽中顯示的大小和磁盤中文件的大小不一致了,預覽窗口顯示的是內(nèi)存格式,所以格式和大小都不一樣。
圖片資源在Unity中以內(nèi)存資源打包,空間占用大小只和尺寸和格式有關,所以你在外部無論如何壓縮圖片質(zhì)量,圖片大小,只要不改變內(nèi)存大小和內(nèi)存格式,那么打包大小始終不變。
閱讀下面之前,請先閱讀Unity文檔中關于圖片導入的部分
http://docs.unity3d.com/Manual/class-TextureImporter.html
圖片內(nèi)存尺寸
通常為了GPU性能3D貼圖資源最好使用2的n次冪,普通2D資源為了使用方便可以沒有這個要求,圖片尺寸優(yōu)化只需要在質(zhì)量可以接受情況下使用越小的越好,直接在Unity中調(diào)節(jié)max size即可。
圖片內(nèi)存格式
顯卡能使用的只能是內(nèi)存格式,Unity中的內(nèi)存格式分為了3類,compressed,16bit,trueColor。
關于Alpha通道,Alpha通道是圖片通道中的一個,通常表示透明,但并不一定表示透明,如果一張圖片有Alpha通道,或者有透明像素,那么這張圖片就帶有Alpha通道。
TrueColor
trueColor,真彩色,顏色值最多,質(zhì)量最好,大小最大,一般只用在追求美術質(zhì)量的2D圖片上。
- RGB24bit 不帶A通道的圖片格式
- Alpha8bit 只帶有Alpha通道信息
- RGBA32bit 同時帶有RGBA通道
- ARGB32bit 同時帶有RGBA通道,與RGBA不同處不詳
帶有通道信息越少的格式,自然同樣尺寸下,大小更小,所以如果一張圖片沒有透明或者不需要alpha通道,則不要保留alpha通道或透明像素,對于沒有alpha的圖片,Unity會自動選擇沒有alpha的格式,能夠節(jié)約1/4的大小。
16bit
16bit,只包含16位色,因為顏色較少,一些漸變會出現(xiàn)過度不均勻,質(zhì)量較差,大小比truecolor小。一般用于16位色質(zhì)量可接受的圖片上,或者需要alpha通道的3D貼圖上。
16bit格式包含rgb16bit,rgba16bit,argb16bit,所包含的通道按照以上名字規(guī)律,需要注意的是格式大小只和bit數(shù)有關,也就是說rgb16bit,argb16bit雖然通道不一樣,但都是16bit,所以大小一樣,但argb16bit顏色更少,質(zhì)量也越差,所以在重復一遍,不需要透明就不要保留alpha,透明不僅帶來空間增大,質(zhì)量也會變差。
Compressed
壓縮格式,根據(jù)顯卡需要的格式進行壓縮,如iOS設備使用PowerVR處理器,則適合的貼圖格式是PVRTC等,Android手機根據(jù)芯片不同有ETC,ATC,DXT,PVRTC等,但一般不會根據(jù)具體的手機打不同的包,所以一般選擇ETC,需要注意最好不要手動選擇壓縮格式,應該選擇auto Compress,Unity會自動選擇最適合該平臺的格式。如果選錯格式,那么在運行時會對貼圖進行轉(zhuǎn)碼,大大拉大加載時間。
壓縮格式的圖片大小,取決于不同的格式,但一般都會比trueColor或16bit小很多,質(zhì)量一般還行,因此是3D貼圖的首選,大部分壓縮格式要求為2的n次冪,且大部分壓縮格式不支持alpha或者支持alpha但效果不好。部分2D圖片使用起來會稍微麻煩,比如強制為2的n次冪時sprite不能用。
Mipmap
有關mipmap的詳細介紹可以參考https://en.wikipedia.org/wiki/Mipmap,簡單的說mipmap是為了優(yōu)化3D中的顯存占用和顯示效果的,開啟這項圖片增大33%,且相機距離較遠時圖片會變糊,因此,2D圖片不能開啟這項,3D中一般的貼圖需要開啟,其他酌情考慮。
圖片優(yōu)化總結
- 不留不必要的A通道,不留不必要的A通道,不留不必要的A通道
- 其實Unity已經(jīng)做得足夠智能了,一般你只需要選擇貼圖類型如texture,還是sprite,還是litmap,他就能自動處理好大多數(shù)了。
- 2D圖片,移除mipmap,質(zhì)量要求高的選用trueColor,要求低的選用16bit或compressed
- 3D貼圖,酌情關閉mipmap,優(yōu)先選用compressed,謹慎使用trueColor。
- 合理選擇圖片大小。
高級優(yōu)化
16bit的優(yōu)化
使用16bit時,會出現(xiàn)明顯的顏色過度不均勻,可以通過RGBA4444和dithering優(yōu)化顯示效果,詳細請看(翻墻才見圖片)
http://electronic-blue.herokuapp.com/blog/2013/05/reduce-memory-usage-by-dithering/?utm_source=tuicool&utm_medium=referral
利用StreamingAssets的優(yōu)化
一張1024x1024 RGB24的圖片內(nèi)存資源大小為3MB,而一張1024 x 1024的JPG圖片如果優(yōu)化得當僅幾百K,可以將JPG圖片放在StreamingAssets下,讓后運行時讀取,這么做確實能夠在保證質(zhì)量的條件下節(jié)省很多大小,但加載十分慢,需謹慎使用。
分離Alpha通道優(yōu)化
壓縮格式能夠做到高質(zhì)量小空間,但壓縮格式一般對Alpha的支持較差,也就是說如果一張ARGB的圖可以去掉A通道,就可以使用壓縮格式來優(yōu)化大小。
可以通過將Alpha通道提取出來作為另外一張圖的R通道,那么我們將得到兩張沒有Alpha通道的圖,且代表Alpha通道的圖可以縮小尺寸,兩張沒有A通道的圖一般可以比一張帶A通道的圖小,所以這個優(yōu)化從原理上可行,也有很多游戲這么做,但是需要額外處理shader,且渲染時需要解析兩張圖等,綜合考慮目前我們沒有采用這種方式。
聲音
聲音資源在Unity打包時以流資源存在(待驗證),也就是說文件大小會影響打包大小,Unity預覽窗口中顯示的大小是內(nèi)存占用。在Unity中調(diào)節(jié)聲音文件參數(shù)不會影響打包大小。
影響聲音文件大小的因素 待補充
模型
選擇模型導入中的mesh compression 可以減少模型占用包體大小,但會出現(xiàn)一些變形和UV精度丟失等,調(diào)節(jié)壓縮到可接受的等級即可,如果是UV精度丟失(常見任務對稱中心出現(xiàn)一條縫)可以將貼圖畫出UV線更多。
動作
選擇動畫導入中的Anim.Compression可以減少動畫占用包體大小,同樣可能出現(xiàn)動畫變形等,調(diào)節(jié)到合適參數(shù)即可,一般選擇keyFrame reducion。
場景
StaticBatch大小優(yōu)化
場景本身在包體大小上并沒有太多可以優(yōu)化,但需要注意如果你的場景大量使用StaticBatch,你會發(fā)現(xiàn)勾選StaticBatch的場景打包后比不勾選StaticBatch要大,估計Unity在打包時把StaticBatch的網(wǎng)格合并成了一個,比如你有一棵樹,這棵樹本身只占一個模型大小,這棵樹在場景中復制很多份仍然只占一個模型大小,但如果這些樹勾選staticbatch,那么打包時會合并為一個樹林,原來的樹模型就不需要了,而是變?yōu)榱艘粋€大樹林模型,大小自然變大了
解決辦法:取消場景的StaticBatch,取消后DrawCall無法合并,通過調(diào)用StaticBatchingUtility.Combine進行批處理即可達到原來的效果。這個做法可能會導致場景加載時間變長,但一般感覺不出來(待測試)。
BuildReport插件
https://www.assetstore.unity3d.com/cn/#!/content/8162
Unity每次打包后會生成一個文件記錄哪些資源被打包了,BuildReport可以解析這個文件讓你非常方便的查看哪些資源占用空間多,針對性的處理。