Unity5的AssetBundle修改比較大,所以第一條建議是:忘掉以前的用法,重新來!要知道,Unity5已經沒辦法加載2.x 3.x的bundle包了…
體會一下Unity5 AssetBundle的優勢:
Cube引用Material,給Cube和Material設置不同的assetBundleName,分開打包,兩個包各自只包含自己,各自獨立。如需修改Material,只需要重打包Material即可。
對於4.x版本,要么Cube包中會包含這個Material,導致需要重打整個Cube,要么需手動關聯Cube和Material的引用關系,在代碼中手動賦值。
那么改進之處就是:不需要我們來管理引用關系了,不需要我們來管理引用關系了,不需要我們來管理引用關系了!可以分開打包而不需要額外的關聯代碼,對於公用資源,只需要將公用資源分開打包即可。
測試案例:Cube1和Cube2同時引用texture,shader使用自帶的Standard
打包方式 |
結果 |
分析 |
Cube1、Cube2分別打包 |
Cube1.assetbundle 53k Cube2.assetbundle 53k |
texture重復打包 |
Cube1、Cube2分別打包 texture單獨打包 |
Cube1.assetbundle 9k Cube2.assetbundle 9k Texture.assetbundle 48k |
texture只有一份,而且不需要代碼手動給Cube1設置使用texture, 資源撕開了,引用還在,Cool~ |
一、資源打包
(1)給要打包的資源設置標記,表示對應的包名:
可以使用代碼批量設置包名(只支持小寫),大致如下:
AssetImporter ai = AssetImporter.GetAtPath(assetPath); i.assetBundleName = xxx; ai.assetBundleVariant = xxx;
(2)生成assetbundle資源包,打包函數簡化,主要參數只需要一個輸出地址:
AssetBundleManifest BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform);
調用該函數,unity會自動根據資源的標簽進行打包,而且是增量打包,
a.對於資源沒有變更的bundle包,不會觸發重新打包;
b.資源沒變,即使生成目錄下的bundle包被刪除了,unity也不會重新打包;
c.生成目錄下的bundle包對應的manifase被刪了,會重新打包;
d.可以使用BuildAssetBundleOptions.ForceRebuildAssetBundle參數觸發強制重新打包。
另外,unity提供了另一個版本的打包函數:
AssetBundleManifest BuildAssetBundles(string outputPath, AssetBundleBuild[] builds, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform);
該函數提供了不依賴資源標簽、通過代純代碼的方式打包生成資源的能力。
(3)生成的bundle包資源目錄解析:
下圖是針對Cube.prefab生成的資源目錄結構:
StreamingAssets:一個AssetBundle包,內含AssetBundleManifest類型的Asset,記錄了所有bundle包及相互間的依賴關系。
運行時需要首先加載這個AssetBundleManifest,然后根據其提供的depence信息加載依賴的bundle包。
StreamingAssets.manifest:全局manifest,全局manifest的名字和打包生成的目錄同名,不是固定的,這里是生成在StreamingAssets目錄下。
Cube.assetbundle:資源bundle。
Cube.assetbundle.manifest:每個資源自己的manifest,與bundle一一對應,只是用來做增量build,運行時根本不需要。
二、壓縮格式
(1)LZMA:默認壓縮格式,壓縮比大,省空間,使用前需要解壓整個壓縮包;
(2)LZ4:5.3版本新增, 40%–60% 的壓縮率,開啟BuildAssetBundleOptions.ChunkBasedCompression打包參數即可。
LZ4算法是“基於塊”的,因此當對象從一個LZ4壓縮包加載時,僅用於該對象的相應塊會被解壓,不需要解壓整個包。
所以LZ4和不壓縮資源一樣,都可以不解壓,而直接讀取包中的資源的。
(3)UnCompress:不壓縮,訪問最快,費空間。
一組測試數據:
LZMA:1.45M |
LZ4:2M |
UnCompress:4M |
LZ4格式壓縮比還可以,而且加載速度也很快,是大多數情況下的最優解。
三、AssetBundle加載方式對比
主要的加載方式有以下四種,前兩種還兼具下載的功能,后兩種都有對應的異步接口:
(1)WWW:只走內存,內存解壓、不緩存;
(2)LoadFromCacheOrDownload:走本地cache,沒有就下載並解壓(然后再LZ4壓縮),有就用;
如果沒有緩存,對於未壓縮的和LZ4壓縮的AssetBundle包,unity會直接把它們拷貝到緩存目錄里面,對於LZMA壓縮的,會先解壓然后重新壓縮成LZ4格式,然后緩存它。可以通過Caching.compressionEnabled控制是否壓縮緩存。
(3)LoadFromFile:最快的方式,區別於4.x版本,可以直接使用壓縮資源;
如果是UnCompress或LZ4,直接從disk讀取
如果是LZMA,會先解壓到memory,然后讀取
(4)LoadFromMemory:從內存加載,一般用於加密資源。
使用方式建議:
(1)隨包資源StreamingAssets:
未壓縮或LZ4壓縮:LoadFromFile;
LZMA壓縮:可使用 WWW.LoadFromCacheOrDownload解壓縮到本地磁盤。
(2)熱更新資源:LZMA+WWW.LoadFromCacheOrDownload+Caching.compressionEnabled;
(3)加密資源:LZ4+LoadFromMemory;
(4)自己壓縮的資源:UncompressAssetBundle的AssetBundle包+自己的算法壓縮+LoadFromFileAsync。
四、資源卸載
AssetBundle.Unload(false):干掉壓縮包,bundle不再可用,即不能再通過bundle.Load加載資源;
AssetBundle.Unload(true):干掉壓縮包,和所有從中加載(load)出來的資源。
所以卸載資源一般有兩種玩法:
(1)AssetBundle.Unload(false)結合Resource.UnloadUnusedAssets()
(2)碎片化使用AssetBundle.Unload(true)
具體怎么用要結合游戲本身的數據特點來定制。關於要不要Unload釋放AssetBundle本身的內存,也有兩種主流玩法,一種是即用即卸(LoadAsset以后立馬釋放AssetBundle),一種是緩存AssetBundle不卸載,兩種方法各有優劣,需結合使用。
五、項目建議
(1)對於bundle中的shader,需要避免重復打包:
場景:Cube1使用自帶的shader Standard
打包方式 |
結果 |
分析 |
Cube1單獨打包,shader不進包 |
Cube1.assetbundle 9k |
|
Cube1單獨打包,shader進包 |
Cube1.assetbundle 118k |
可以看到Standard這個shader編譯后也是相當大的 |
對於shader一定要注意重復打包,要么將使用的shader配置在Always Included Shaders,要么將shader也單獨打包(這種方案還沒試過)
(2)內存分析:
一個AssetBundle壓縮包並不大,所以同時緩存100個不釋放也沒多大(4.x這個東西還是很大的,不能緩存太多)。
AssetBundle創建,會在Not Saved/AssetBundle分組下多出一個bundle,大小4.1k:
LoadAsset(cube1)后,會在Assets下多處cube1產生的asset:
經測試,AssetBundle所占用的相關內存,只要管理好引用,是可以完全回收的。
(3)資源LOD
一個資源可以設置兩個標簽,第一個參數assetBundleName 表示包的名字,第二個參數assetBundleVariant 用來做資源的LOD。
假設本地有兩套貼圖資源,一套高清,一套普通,然后給他們設置同樣的assetBundleName為MyAsset,高清資源的assetBundleVariant 設置為LD,普通資源設置為SD,那么就可以根據不同設備通過選擇加載MyAsset.LD或MyAsset.SD來切換資源庫,這樣依賴MyAsset的Prefab就可以動態切換版本了。
注意,兩套資源集的asset必須完全一一對應,對於unity來說LD和SD是同一個bundld,同一時刻只能加載其中一個。
(4)由於打包極大地簡化了,沒有指定mainAsset的過程,所以AssetBundle.mainAsset已經不能用了,很憂桑。
(5)WWW.LoadFromCacheOrDownload一幀只會有一個bundle完成下載
AssetBundle bundle = www.assetBundle;
訪問www.assetBundle屬性就是同步從www中抽取並創建AssetBundle