Unity AssetBundle筆記

1.入門:

Resources:表示U3D自動將資源打成一個AssetBundle包,全部放在Resources下的文件夾都會打成一個AssetBundle包,資源很是大,Resources文件夾在真機上最大隻有2G的內存(專業版會增大內存)html

AssetBundle包:其實能夠當作一個壓縮包(有固定格式的),默認狀況下使用LZMA壓縮方式壓縮的資源文件;和壓縮ZIP同樣的,只不過裏面的格式變了算法

   Unity3D引擎爲咱們提供了三種壓縮策略來處理AssetBundle的壓縮,即:json

    一、LZMA格式:服務器

        在默認狀況下,打包生成的AssetBundle都會被壓縮。在U3D中,AssetBundle的標準壓縮格式即是LZMA(LZMA是一種序列化流文件),所以在默認狀況下,打出的AssetBundle包處於LZMA格式的壓縮狀態,在使用AssetBundle前須要先解壓縮。使用LZMA格式壓縮的AssetBundle的包體積最小(高壓縮比),可是會相應的增長解壓縮的時間網絡

    二、LZ4格式:異步

        Unity5.3以後的版本增長了LZ4格式壓縮,因爲LZ4的壓縮比通常,所以通過壓縮後的AssetBundle包體的體積較大(該算法基於chunk)。函數

    三、不壓縮工具

Resources和AssetBundle的區別:性能

  一、Resources:有2G的限制,不支持動態更新(拿Android爲例)測試

    a、上線後,Resources裏面的資源都在APK裏面,只能讀不能寫

    b、StreamingAssets和dataPath都是在Apk中,Apk爲一個壓縮包,裏面的東西只能讀不能寫,所以這個限制就決定了Resources不能支持熱更新

  二、PersistPath(支持熱更):

    a、只能手動打包

    b、打包方式:

      一、4.0之前,打包的依賴關係都必須手動

      二、5.0之後,這種依賴關係所有自動

建立AssetBundle:AssetBundle能夠將任何資源打包成assetbundle(若是是unity不能識別的文件,能夠經過改變後綴進行打包)

  一、在任何一個遊戲物體的右下角有AssetBundle,第一個爲包名,第二個爲後綴(不能識別的物體不能修改,修改後綴變成能識別的物體)

更新流程:

  一、代碼的更新:熱更新

  二、資源的更新:AssetBundle更新

    a、建立assetbundle

    b、將assetbundle打成一個zip文件,放進streamingAssetPath裏面

    c、把須要更新的AssetBundle先上傳到Server,若是Server有更新(與服務器版本進行比對),把server的assetbundle包下載下來(zip文件),而後解壓到persistentPath裏

    d:加載:判斷PersistentPath裏是否有這個資源,若是沒有就讀取StreamingAssetPath裏面的,若是有,就直接讀取PersistentPath裏的

        一、LoadAsset:從資源包中加載指定的資源

        二、LoadAllAsset:加載當前資源包中因此的資源

        三、LoadAssetAsync:從資源包中異步加載資源

  三、資源卸載:資源卸載部分使用的是Unload方法

     Unload:

        a、該方法會卸載運行時內存中包含在bundle中的全部資源。

        b、當傳入的參數爲true,則不只僅內存中的AssetBundle對象包含的資源會被銷燬;根據這些資源實例化而來的遊戲內的對象也會銷燬

        c、當傳入的參數爲false,則僅僅銷燬內存中的AssetBundle對象包含的資源

    

BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.AppendHashToAssetBundleName|BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);

  

  AssetBundle的適用平臺與跨平臺性

    AssetBundle適用於多種平臺,包括網頁應用、移動應用、桌面應用等,能夠動態更新,但不一樣平臺所使用的AssetBundle並不相同,在建立離線AssetBundle的時候須要經過參數來指定目標平臺,相關關係如表所示:

    

     IOS:在Mac版本的Standlone打包

    Windows:打Android、PC、WebPlayer

 

BuildPipeline.BuildAssetBundles():
  一、第一個參數:AssetBundle輸出到哪個文件夾
  二、第二個參數:枚舉類型,能夠選擇多個參數,多個參數之間能夠用「|「隔開
    a、CompleteAssets:保證資源的完備性,默認開啓
    b、CollectDependencies:用於蒐集資源的依賴項,默認開啓
      和完整性有點相像,會把遊戲物體所依賴的資源一塊兒進行打包,防止有些被依賴的資源沒有被打進去
    c、DeterministicAssetBundle:用於爲資源維護固定ID,默認開啓
      因此的資源都有固定的標記的,在資源的mate文件中的guid:64位組成的字符串,電腦裏是隨機生成而且惟一,每個文件的惟一標識
    d、ForceRebuildAssetBundle:用於強制重打全部AssetBundle文件,5.3之後新增
      資源更新了,從新打包,將之前的資源包丟棄
    e、IgnoreTypeTreeChanges:用於判斷AssetBundle更新時,是否忽略TypeTree的變化,新增
      打包時是否忽略父子關係
    f、AppendHashToAssetBundleName:用於將Hash值添加在AssetBundle文件名以後,開啓這個選項能夠直接經過文件名來判斷哪些Bundle的內容進行了更新
      (4.X下廣泛須要經過比較二進制等方法來判斷,但在某些狀況下即便內容不變從新打包,Bundle的二進制也會變化),新增
      在包名後綴名後面添加一個Hash表
    g:ChunkBasedCompression:用於使用LZ4格式進行壓縮,5.3新增
 
 

1、如何組織assetBundle:

unity5之前,打包須要本身去找依賴,而後須要按照拓撲圖順序壓入AB棧,這樣在最後打AB時纔能有效利用依賴(棧內已有的AB才能做爲依賴)。

unity5.x後,打包變得簡單,但如何組織assetBundle依然須要琢磨和規劃。
  首先咱們須要知道:AB、asset和資源的關係:一個AB包括1個或多個asset,一個asset可能沒有依賴其餘asset(即包括了其須要的全部資源),也可能依賴其餘asset(包括一些資源和指向其餘asset所在AB的引用)。
  其次,使用asset和AB:要使用一個asset,須要先加載該asset的全部依賴的asset(迭代下去,把全部相關的AB都加載出來),而後加載本身的AB,最後取出asset來使用。
  因此,要使用一個asset,都須要加載全部相關的AssetBundle鏡像進入內存。這就須要咱們要研究打ab的方案了。而且打ab的方式也影響ab的總大小,即便在Unity5下。
  文檔提供了3種打ab方案:
    1.邏輯實體分類法,即根據功能模塊分類,(大致上意思是不一樣功能不一樣ab,這樣就能夠開一個功能下載一個ab)好比先大層次分:UI模塊,角色模塊,場景模塊等,
     UI模塊又根據具體功能模塊分:好比各個副本的UI是不一樣的,那每一個副本的UI能夠打成單獨ab;
     角色模塊則是每一個角色包括其依賴的東西,如mesh,model,animation,texture等打成一個AB;
     場景模塊能夠一個場景分紅多個片,每一個片至關於一個「子模塊」,單獨成ab,多個場景共享片。
    2.根據資源類型打ab:好比音效打成一個ab,國際化文本打成1個ab等,文檔說這種方法是打多平臺ab的一種好方法,好比音效ab在各個平臺下都同樣則能夠複用,而shader平臺區分則不能複用
     而且在此方法下,由於原始資源(好比Texture)不多改動,因此利於版本更新(增量少)。這種方法我也不是很理解,感受就是把ab粒度細化到原始資源層次(紋理,音效,網格等),他們有的在不一樣平臺保持同樣,有的平臺區分,但基本不會發生改變。
    3.根據「同時加載」來打ab,即把須要同時加載的資源打入同一個ab.好比每一個場景包括其依賴的全部東西打成一個AB。
  不管使用什麼方案(通常是都使用一點點,好比第3種用來打場景,第1種用來打各個系統(即功能)的資源,等),爲了減小AB大小,增量AB大小,加載時間和運行時內存消耗,都須要注意下面細節:
    1.頻繁變更的asset不該該和穩定的asset打入一個AssetBundle;小增量AB
    2.若是穩定的大/多asset中含有頻繁變更的資源,應該把資源單獨打AB;小增量AB
    3.使用時通常同時加載的東西如Model和它的texture,material,animation等應該打入一個AssetBundle中,因此角色通常每一個一個AB;減小加載時間
    4.若是多個AB都依賴某個asset或資源,應該把該asset或資源單獨打AB;小AB,省內存
    5.若是2個asset極少同時加載,那應該分開打AB;省內存
    6.把常常同時加載的小asset的AB合併成大AB;減小加載時間

 

2、打AB的參數選擇和加載AB的方案:

  1.清單:

    1)打AB時,每一個AB都會額外帶一個.manifest文件,用來描述該AB相關信息,包括
      CRC碼,(file hash)a single hash for all assets in AB,(type tree hash)a single hash for all types in AB,(class types)all class types in AB,(asset names)all asset paths in AB.
      此文件只用於生成增量AB, not necessary for runtime,因此不須要打入安裝包,依賴關係能夠在2)那裏統一查找。
    2)而且在打AB的輸入參數中的「輸出文件夾」那裏生成一個.manifest文件,裏面包括全部AB路徑及其依賴,這個在運行時加載資源時使用,由於加載資源需先加載依賴。

  2.AB的壓縮方式

  AB有3種壓縮方式(固然你也能夠自定義壓縮算法,不過不必),一種是無壓縮UncompressedAssetBundle,一種是塊壓縮LZ4(ChunkBasedCompression),一種是最大壓縮LZMA(None)
加載時無壓縮最快,其次是塊壓縮(只須要解壓AB的一部分就能加載,與無壓縮具備可比性),最後是LZMA(須要徹底解壓AB),固然打出的AB大小就反過來了(LZMA:50-60%,LZ4:70%)。
通常本地AB建議以LZ4格式存儲,較小且快,須要網絡下載的用LZMA並使用LoadFromCacheOrDownload對其加載,這樣到了本地就變成LZ4了(LoadFromCacheOrDownload在接受數據流時就直接解壓,無額外耗時)。

  3.AB加載的幾個接口

    1)加載AB文件(這裏是指build出來後的AB文件,若是build後還進行加密等則不能直接加載)有幾種方式:
    WWW:輸入URL,AB在www.assetBundle裏;PS:若是ab在本地,url用file:///前綴
    WWW.LoadFromCacheOrDownload:輸入URL,AB在www.assetBundle裏;PS:若是ab在本地,url用file:///前綴
    LoadFromMemory(Async):輸入是bytes[],返回的就是AB;PS:bytes的獲取通常用WWW,也能夠直接File.ReadAllBytes,反正得到文件的字節流便可。
    LoadFromFile(Async):輸入是path,AB在AssetBundleCreateRequest.assetBundle裏;

    UnityWebRequest:文檔說此方法比WWW好,用法也相似,但由於WWW比較成熟,並且WWW咱們基本只是用來加載本地bytes資源,並且此方法在5.4之後版本纔有,咱們沒有使用。
在網絡資源下載方面咱們項目用的是C#提供的HttpWebRequest
    2)加載非.assetBundle文件例如.bytes,.jpg,.png,.txt,.ogg,.mp3等文件通常使用WWW加載:
    WWW.bytes,WWW.texture,WWW.text,WWW.audioClip裏分別存加載後的數據。

    若是原先是.assetBundle,加密成.bytes,先www加出bytes,而後loadfrommemory;

    若是原先是.bytes或者其餘自定義數據類型,如xml,json等,打ab成.assetBundle,則先加出assetBundle,而後加載出Asset,最後強轉爲TextAsset類型,而後你的數據就能夠從中取出來了,Unity常常把這些數據當作TextAsset類型;

    簡而言之,對特殊文件格式,咱們使用以前先測試一下其加載方式,基本在WWW和TextAsset這塊考慮,看數據在它們哪一個變量裏,一測便知。

  4.針對2和3介紹的多種方式,按狀況選擇壓縮方式+加載接口

  文檔根據各個函數對內存和CPU消耗的特色作出如下建議:
  1.對於安裝包內的AB,儘可能用LoadFromFile(Async)+ChunkBasedCompression,由於它和ChunkBasedCompression配合起來很快(能夠壓縮30%+並且加載時不須要額外解壓),若是AB的壓縮格式是LZMA(即Option=None),LoadFromFile(Async)須要額外解壓和重壓縮(壓爲LZ4);
  2.對於網絡資源,儘可能用WWW.LoadFromCacheOrDownload,而且資源儘可能用默認的LZMA壓縮法,由於這樣能夠省流量,而且此函數在接收網絡流時就對流進行解壓,爲LZ4(即AB壓不壓對其無區別),而加載LZ4不須要額外解壓。
  3.對於加密的AB,須要用WWW把文件加載成bytes,而後解密,而後用LoadFromMemory[Async]加載出AB(這個大概是LoadFromMemory[Async]使用的惟一場景了)
  4.若是使用自定義壓縮算法,選UncompressedAssetBundle不壓縮來build AB,而後加載時先對數據解壓,而後LoadFromFile(Async)
  總結:本人當前項目是用LZMA build AB(不使用LZ4的緣由多是沒深刻了解,也多是貪圖LZMA的小包體,也多是加載的多半是小ab,LZMA解壓再壓LZ4的消耗能夠忍受),用LoadFromFile(Async)加載.assetbundle,WWW+LoadFromMemory(Async)加載加密過的ab.bytes,用WWW加載原始圖片。

 

3、若是管理AssetBundle

  1.AssetBundle.unload(true/false)的用法:
  true會把AB,由AB加出來的Asset,由Asset實例化出來的GameObj(也可能只是指向Asset的引用)都銷燬,內存一乾二淨;
  false只是把AB卸載,官方文檔描述爲把AB和Asset,Gobj的link斷開,即後者們本身刪除本身,若是再次加載Asset則是新的Asset,與原來的Asset獨立共存於內存;
  這裏須要明確兩點:
  1.AssetBundle加載出來後沒有Unload則其鏡像一直在內存,再次加載會報錯,能夠unload掉從新加載或者hold住它,不從新加載;
  2.false時要卸掉Asset須要把由它實例化出來的Gobj都銷燬(引用則置空),而後Resource.unloadunusedassets卸載,Gobj則destroy便可;
  官方文檔建議選擇true,true調用的時機能夠是切地圖或者Asset引用爲0時,若是選擇false,那Asset只有在2的狀況下才能卸掉。
  但官方文檔沒說的一點是在調用unload(true)前若是再次加載應該怎麼辦。
    1.其實只需在上層存個Pool便可,Pool裏的元素對應一個AssetBundle,加載AB時先看Pool裏有沒有,有則直接使用它來GetAsset和實例化,並把引用+1,當實例化的東西Destroy時把該AB的引用減一,當引用變爲0時unload(true)便可。
    2.但這種方式主要用來處理實例化的GameObject資源,對某些資源好比AudioClip,Text,場景,自定義數據等通常不多頻繁加載,這樣咱們在加載AB出來後直接unload(false),而後當它不使用時,對應的Asset引用就空了,就能夠在UnloadUnusedAsset時卸載(切場景時默認調用一次,通常在程序中定時調用一次)
    3.官方文檔之因此建議使用unload(true),是想避免內存存多份Asset和Asset不能及時卸載,若是資源是不多加載如2中那些,用unload(false)較好,至於unloadunsedAsset的調用能夠在該資源使用完後手動調用一下(當資源消耗時刻明確時),也能夠交給遊戲卸載系統(定時調用unloadunusedasset)或切場景。

  個人一種方案:

  A.對不頻繁加載的資源(大部分都是),咱們加載完後就unload(false),這樣能夠迅速釋放內存鏡像,而當加載出來的資源再也不被使用(引用爲空)時,Asset就能被識別爲unsedassets而被卸載;

  B.對頻繁加載的資源(小部分),咱們在上層弄一個pool,裏面存着stringtoasset的字典,字典裏只存asset,即即便是頻繁加載的資源咱們也要在加載出asset後用unload(false)把內存鏡像卸載掉,只保留加載出來的資源以便實例化/引用,這裏咱們須要搞個引用計數,由於字典裏永遠引用着該資源,當引用計數爲0時咱們須要從字典中刪除。

  在A,B的指導下+定時調用Resources.UnLoadUnUsedAssets,GC.Collect應該能保持內存的儘可能乾淨了。那哪些資源是頻繁加載哪些是不頻繁加載,標準是咋樣的呢?這個須要具體測試獲得相關標準和性能的關係才能作決定,和遊戲邏輯有關,和資源有關,和體驗有關,須要寫工具來肯定。
  總結:AssetBundle的管理主要抓住幾個接口便可AssetBundle.unload(true/false),Resources.UnLoadUnUsedAssets,GC.Collect,Destroy,但要真正瞭解他們,須要深刻理解Unity對AssetBundle,Asset,資源等的內存管理機制,能夠參考這篇文章:    

  http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html

 

4、Ps(存疑與補充)

  AssetBundle Variant:ab變種,通常用於解決「多態性」問題,好比資源有hd,ld,圖片要適應各類設備須要不一樣壓縮格式等,有空能夠研究一下。

相關文章
相關標籤/搜索