unity5.X AssetBundle使用(一 )

之前曾經寫了一篇博客介紹Unity5的AssetBundle,結果似乎很受關注。不過似乎很多人看了之後都不懂,主要是因爲不太明白AssetBundle是什麼,它的依賴關係和結構是什麼的,就直接想拿代碼去用,而導致了很多人說看不懂啊,說什麼有錯誤啊,諸如此類。我想了一下,還是應該從最基礎的東西說起,不厭其煩的說,纔會省去大家加我QQ問問題了,畢竟平時上班忙,看到一些人把我當翻譯詞典查,我肯定會態度不好的。

一、什麼是AssetBundle
估計很多人只知道Unity的模型之類的東西可以導出成一種叫做AssetBundle的文件,然後打包後可以在Unity程序運行的時候再加載回來用。
那麼AssetBundle是一個什麼樣的東西呢?其實AssetBundle只是一種使用LZMA壓縮方式壓縮的資源文件。具體LZMA是什麼請百度,你可以理解成就是一種壓縮文件就行了,至於它的後綴名是什麼,一點關係都沒有,你可以自己定。
AssetBundle打包的時候,你可以指定一個mainAsset,那麼加載完之後就可以通過AssetBundle.mainAsset來獲取到了。你也可以不指定mainAsset,直接打包一堆內容進去,然後加載後通過AssetBundle.LoadAsset指定名字的讀取出來。
在資源之間,存在着依賴的關係。你可以把資源拆分得很細,比如一個模型,由網格模型、材質、貼圖構成,你可以把每一個小部分都拆開,各自打包成壓縮文件。當Unity需要加載使用的時候,把該模型的所有依賴的小資源都加載起來,然後根據依賴關係組裝,就變回了我們看到的資源了。

二、AssetBundle的依賴結構
要說明依賴關係結構,我們還是使用上面的例子,一個模型,分爲了網格模型、材質、貼圖。那麼他們是怎樣依賴的呢?然後在Unity5的打包裏面,他們是怎樣表現出依賴關係的呢?
接下來做一個小小的實驗:
我準備了4張貼圖,分別叫做t1、t2、t3、t4,然後建立了兩個材質球,分別是m1、m2,m1材質使用了t1、t2、t3三張貼圖,m2材質使用了t4貼圖。
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
最後建立兩個模型,我就使用unity內置的模型了。obj1是一個cube,obj2是一個quad。obj1使用了m1材質,obj2使用了m2材質。然後obj1和obj2都做成了預設,放在了Assets/Resources/Obj/下面
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
那麼現在他們的結構應該是這樣的:
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
接下來,先只設置obj1的assetBundleName,然後導出
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
導出之後,我們看看AssetBundle.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
裏面只有一個Info,就是剛纔我們命名的obj1.ab,而obj1.ab下面的Dependencies是空的,也就是它沒有任何依賴了。
再看看obj1.ab.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 它裏面包含了類型的哈希碼、Assets資源的路徑,和依賴。這裏它的依賴還是空的。

接下來把obj2也賦予AssetBundleName:
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
再導出,會發現除了剛纔的文件以外,會多了2個文件,就是obj2.ab和obj2.ab.manifest。

還是打開AssetBundle.manifest看看,會發現
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
這次的Info變成了2個,分別是obj1.ab和obj2.ab

打開obj1.ab.manifest
 再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
發現和剛纔沒什麼變化。
再看看obj2.ab.manifest
  再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 它的結構和obj1.ab.manifest差不多。

剛纔只是把2個模型設置了導出AssetBundle,接下來我會把兩個材質和四張貼圖都設置導出
不厭其煩的把圖貼上來:
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
這時候導出,我們的所有依賴關係都應該存在了。導出之後,多了很多文件,是這樣的:
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再來看AssetBundle.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 這次看到的Info有7個了,其實我們設置了多少個AssetBundleName導出,它就應該有多少個Info。

obj1.ab.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 這次看到它的Dependencies,會看到有依賴了,寫的是一個本地的地址。有人會說,這個絕對路徑有問題啊,我把這個文件放到cdn上面,路徑就會不對啊。這個先不急,下面會說明是什麼回事。

看m1.ab.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
會發現結構差不多,但依賴列表裏面會有三個地址,就是我們三張貼圖的地址了。

看obj2.ab.manifest 和 m2.ab.manifest情況會差不多
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙

接下來,要做最後一步試驗了,比如剛纔我已經是整個項目的導出了,現在我突然需要改動其中的一個小部分,現在我就把t4不導出了。
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
那麼現在我們再整個項目的AssetBundle導出,會怎樣?
導出完之後,看目錄,會發現文件和剛纔是一樣多的,t4.ab並沒有被刪掉。
再看AssetBundle.manifest
 再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
Info變成6個了,而裏面某些項的依賴列表變了
看obj1.ab.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 和剛纔沒有變化

看obj2.ab.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 和剛纔也是沒有變化的
看m2.ab.manifest
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 這裏的依賴列表沒有了。

這其實就是AssetBundle的鏈式結構和增量打包了。一個小的部分改變了,它將會改變的地方只有總的AssetBundle.manifest,還有直接依賴於它本身的manifest。其他不依賴的部分是不需要重新打包的。
還有一點需要注意的地方是,除了manifest文件以外,還有一個沒有後綴名稱的AssetBundle文件。這個文件其實才是包含了所有的依賴關係的總的依賴關係配置文件,剛纔我們能用txt打開的manifest文件,都只是用來做本地依賴關係和增量打包的時候用的。我們加載AssetBundle的時候,完全不需要加載那些manifest文件的,只需要那個沒有後綴名稱的AssetBundle文件就行了,它代表的是該項目的所有AssetBundle的依賴關係。
所以,剛纔我們看到manifest裏面用的都是本地的絕對路徑,那是針對你本地打包時用的,和加載無關。 
 

三、導出AssetBundle和自動設置名稱
剛纔我們都是直接的輸入AssetBundleName來導出AssetBundle的,其實這一步可以使用代碼自動完成
在Unity項目內部,每一個小的資源(網格、材質、貼圖、聲音等),都會有一個唯一的哈希Id的,是一串很長的字母和數字組合。我們可以通過AssetDatabase.AssetPathToGUID來獲得這個ID。
那麼自動設置就變得簡單了,可以通過以下的代碼,我們可以設置一個總的prefab的AssetBundleName,然後自動獲得它身上的所有依賴,然後獲得每個依賴資源的唯一Id,再賦予AssetBundleName就行了
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
 

四、加載AssetBundle的步驟
通過上面導出AssetBundle的說明,估計現在想要把它加載起來就變得簡單了。
首先需要明白一個規則,資源的依賴關係組裝是unity本身會自動完成的。比如一個資源A,它是依賴於資源B和資源C的,那麼如果我們需要加載資源A進來並正確的顯示出來,我們必須先把資源B和資源C加載,然後再加載資源A。當資源A加載進來之後,發現內存裏面已經有資源B和資源C了,它會自動的組裝起來。
那麼再看看加載的步驟了:
1、獲得總的依賴配置
剛纔已經說明了,真的有用的依賴配置文件是沒有後綴名稱的AssetBundle文件,所以我們需要加載的就是這個文件了。
string mUrl = Cdn + "AssetBundle";
然後www加載。
之後很多人看不懂,說我這個Cdn是什麼東西,“AssetBundle”又是什麼東西,現在應該明白了吧?Cdn就是你的資源服務器路徑,“AssetBundle”就是文件名,它沒有後綴。
加載後,通過AssetBundle.LoadAsset("AssetBundleManifest"),就可以把剛纔那個沒有後綴名的文件轉成AssetBundleManifest對象mainfest。
2、根據名稱找到目標加載資源的所有依賴
獲得了AssetBundleManifest對象mainfest之後,比如我們實際上是需要加載obj1.ab的,這在剛纔的AssetBundle.manifest裏面可以知道,它的Info裏面就有obj1.ab。然後我們通過
string[] dps = mainfest.GetAllDependencies("obj1.ab");
就可以獲取到obj1.ab的所有依賴了,包括了子依賴,比如它依賴於m1.ab,然後m1.ab依賴於t1.ab、t2.ab、t3.ab,那麼這裏獲取到的就應該是4個依賴了。分別是m1.ab、t1.ab、t2.ab、t3.ab。
3、加載所有依賴的資源
獲取到obj1.ab的所有依賴之後,就應該逐個的去加載他們了。分別www加載他們,然後保存他們的AssetBundle。
4、加載目標加載資源
當加載了所有的依賴資源之後,就可以光明正大 的去加載目標資源了,這裏我們的目標資源就是obj1.ab。
5、實例化顯示
obj1.ab加載完之後,你愛怎樣用都可以,直接實例化出來吧。
再詳細的介紹一下Unity5的AssetBundle - 阿趙 - 窮到掉渣的超級奶爸阿趙
由於AssetBundle是不能重複加載的,如果你需要多次加載一個資源,你有2個選擇,要麼加載了就Unload(false)卸載了它。要麼你可以把它存起來,當需要相同名字的AssetBundle的時候,直接取出來。

五、最後的建議
1、Unity5的新版AssetBundle好像是一套全新的系統,其實和舊系統的差別並沒有很大,只是自動生成了依賴配置文件而已。這一個步驟實際上完全可以自己實現的,那些配置文件可以用自己喜歡的格式生成,然後加載的時候再自己想辦法把依賴關係找回來就行了。
2、個人覺得把AssetBundle拆得太碎並不是一件好事情。爲什麼這麼說呢?用過電腦的人都知道,拷貝文件的時候是一個個碎的文件拷貝快?還是把一堆文件壓縮成一個包,然後拷貝快?如果加載一個模型,需要分別加載十幾次依賴資源,才能顯示,這個過程中發送這麼多的www或者http請求,過程有點危險。至於說冗餘文件的問題,自己考慮一下分佈策略吧。
2、 一般來說,這種東西都需要配合着一套資源管理的系統來用的,所以在上一篇博客裏面,我只是介紹新AssetBundle的特性,不太可能整一套系統都搬出來,只寫了幾句有代表性的關鍵方法當做僞代碼來說明。結果很多人要麼就說亂,要麼就說有錯誤。其實說來說去,就是自己沒搞懂原理,又急着拿別人的代碼來用……做人還是踏實一點的好。 
發佈了43 篇原創文章 · 獲贊 20 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章