Unity_AssetBundle筆記_(一)(俗稱AB包_個人筆記歡迎指正)


AssetBundle_介紹   (基於unity 2017 版本 --- 如要知曉最新資料建議去看官方文檔)

(最近看到的一篇AB不錯的文章:https://blog.csdn.net/Mars___Z/article/details/90199004。簡明扼要)

一: AssetBundle的定義和作用

   用處?

   1,AssetBundle是一個壓縮包包含模型、貼圖、預制體、聲音、甚至是整個場景、可以在游戲運行時被加載。

   2,AssetBundle自身保存着相互依賴的關系;---(AB包中后綴為manifest的文件夾中可被文本形式打開)

   3,壓縮包可以使用LZMA和LZ4壓縮算法,減少包大小,更快的進行網絡傳輸;

   4,把一些可以下載的內容放在AssetBundle里面,可以減少安裝包大小。---(便於游戲體驗和更便於實時加載問題)

 

二: 什么是AssetBundle

   可以歸為兩點

   1,他是一個存在於硬盤上的文件。可以稱之為壓縮包,這個壓縮包可以被認為是一個文件夾,里面包含了多個文件,

      這些文件可以分為兩類:Serializad file(序列化文件或流文件)和Resource file (源文件)。

      a) Serializad file 資源是被打碎放在一個對象中,最后統一寫進一個單獨的文件(只有一個 類似Instance);

      b) Resource file 某些二進制文件資源(如:圖片 、聲音等)被單獨保存,方便快速的加載。

   2,他是一個AssetBundle對象,我們可以通過代碼從一個特定的壓縮包加載出來的對象,這個對象包含了所有我們當初添加到這個文件壓縮包里面的內容,我們可以通過這個對象加載出來使用。

   

三: AssetBundle 概念圖

      資源打包流程

      

      資源使用流程

      

   

四 :AssetBundle 使用流程(簡稱AB)---“重要”

 

(基本設置)指定資源的AssetBundle屬性 (xxxa/xxx)這里xxxa會生成目錄,名字為xxx ;

        如圖:

           選擇一個需要打包的資源。

        

  關於AB打包的面板和設置方法(圖片內有說明)

        

 

//-----------------------------------------------------------------------------------------------------

 

A_使用編譯器擴展---直接Build所有以及設置好要打包成AssetBundle的資料

  當設置好后可以使用這個編譯器擴展進行一次性全部打包模式

using UnityEngine;
using UnityEditor;
using System.IO;
 
public class CreateAssetBundles : MonoBehaviour
{
    [MenuItem("AssetBundles/Build AssetBundles")] //特性
    static void BuildAssetBundle()
    {
        string dir = "AssetBundles"; //相對路徑
        if(!Directory.Exists(dir))   //判斷是否存在
         {
            Directory.CreateDirectory(dir);
         }
         BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);

    }
     
}

//-----------------------------------------------------------------------------------------------------

B_AssetBundle包_結構。

   當設置好面板屬性后,直接使用編譯器(AssetBundle/Build AssetBundle)按鍵進行生成文件。創建后的樣式

   ---本地項目文件夾下創建AB包文件夾

                      

                       

   文件夾下的文件格式-----采取的是歸類方式 (即 scene/map 這種形式)

                      

 

   最后AssetBundle的文件格式 ,因后綴沒添加則只有文件名(注意manifest后綴的文件為管理文件,用於管理記錄,為打包后自動生成的)

      

 

//-----------------------------------------------------------------------------------------------------

C_加載AB包和包里面的資源。----(需要注意的是帶Async的API即是異步的方法不帶則是同步方式)

    首先介紹一下主要加載AB包的四種方式(即四種類型的API) :

   1,  從文件中加載 AssetBundle.LoadFromFile 。 

 

 1 using System.Collections;
 2 using UnityEngine;
 3 using UnityEngine.Networking;
 4 
 5 public class LoadFromFileExample : MonoBehaviour
 6 {
 7     private IEnumerator Start()
 8     {
 9         //這里需要注意的是,如果你想加載的資源有依賴的資源 如貼圖等資源,則必須先加載依賴資源后加載你所想加載的資源。
10         //即A依賴B 則必須先加載B到內存中,然后再加載A 並實例化---這里注意依賴項一般可以不用實例化只需要在內存中即可。
11         AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12 
13         AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/scene/map_001");
14 
15         16          17 
18         //這里需要注意的是 單獨加載和加載所有壓縮包內的對象處理方式
19 
20         //加載單獨的
21         GameObject panelPrefab = ab.LoadAsset<GameObject>("Plane"); //注意名字不能寫錯了
22 
23         Instantiate(panelPrefab);//實例化資源
24 
25         ////加載所有
26         //Object[] panelPrefab = ab.LoadAllAssets();
27 
28         //foreach (var obj in panelPrefab)
29         //{
30         //    Instantiate(obj);//實例化資源
31         //}
32 
33         yield return null;
34     }
35 }

 

    2、從內存中加載 AssetBundle.LoadFromMemoryAsync(注意是異步,去掉Asyns既是同步方法)

 

 1 using System.Collections;
 2 using UnityEngine;
 3 using UnityEngine.Networking;
 4 
 5 public class LoadFromFileExample : MonoBehaviour
 6 {
 7     private IEnumerator Start()
 8     {
 9         //這里需要注意的是,如果你想加載的資源有依賴的資源 如貼圖等資源,則必須先加載依賴資源后加載你所想加載的資源。
10         //即A依賴B 則必須先加載B到內存中,然后再加載A 並實例化---這里注意依賴項一般可以不用實例化只需要在內存中即可。
11         AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12 
13 
14         string path = "AssetBundles/scene/map_01";
15         
16         //LoadFromMemoryAsync 和 LoadFromMemory --內存讀取
17         AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); //異步的方式
18         yield return request; //異步的方式 必須等待完成后才繼續執行
19         AssetBundle ab = request.assetBundle;
20 
21         //AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));//同步的方式
22 
23         //使用資源
24         GameObject gameObj = ab.LoadAsset<GameObject>("map_001");
25         Instantiate(gameObj);
26 
27         yield return null;
28     }
29 }

 

 

 

    3、第三種加載AB包的方式WWW(萬維網) --WWW(萬維網)對象方法可以從本地讀取,也可以從服務器讀取。

     ---需要注意的是這個方法在2017以后基本被UnityWebRequest(這個方法代替的是WWW遠程讀取)代替。做了一定程度的封裝。

 

 1 using System.Collections;
 2 using UnityEngine;
 3 using UnityEngine.Networking;
 4 
 5 public class LoadFromFileExample : MonoBehaviour
 6 {
 7     private IEnumerator Start()
 8     {
 9         //這里需要注意的是,如果你想加載的資源有依賴的資源 如貼圖等資源,則必須先加載依賴資源后加載你所想加載的資源。
10         //即A依賴B 則必須先加載B到內存中,然后再加載A 並實例化---這里注意依賴項一般可以不用實例化只需要在內存中即可。
11         //AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12 
13         //注意!!!
14         //www.LoadFromCacheOrDownload 這個方法是先下載存到cache的緩存空間內 然后在進行提取。
15         //如果第二次也進行下載一樣的 則會在這個緩存空間內提取之前已經下載的數據
16         //開始下載前必須先判斷是否准備好了,否則一直循環下去,等待准備好
17         while (!Caching.ready) //檢查cache 緩存是否准備好了
18             yield return null;
19 
20         //完整的路徑---本地下載
21         //string allPath = @"E:/03_TestDemo/01_UnityDemo/ShowMap_ABPackageTest_001/AssetBundles/scene/map_01";
22         //WWW www = WWW.LoadFromCacheOrDownload(allPath, 1);
23         
24         //遠程服務器下載
25         WWW www = WWW.LoadFromCacheOrDownload(@"http://localhost/AssetBundles/scene/map_01", 1); //從遠程服務器上下載AB包
26         yield return www;
27         
28         //因萬維網是非常復雜的,經常容易出現非常意外的錯誤,所以必須加入一個判斷。
29         if(!string.IsNullOrEmpty(www.error)) //當什么都沒有時
30         {
31             Debug.Log(www.error);
32             yield break; //跳出協程
33         }
34 
35         AssetBundle ab = www.assetBundle;
36 
37         //使用資源
38         GameObject gameObj = ab.LoadAsset<GameObject>("map_001");
39         Instantiate(gameObj);
40 
41         yield return null; //上述下載時沒有加載相應的貼圖材質。。。注意!!!
42     }
43 }

   4、第四種Unity封裝的UnityWebRequest對象---(專用於替代WWW的遠程加載方式)

 1 using System.Collections;
 2 using UnityEngine;
 3 using UnityEngine.Networking;
 4 
 5 public class LoadFromFileExample : MonoBehaviour
 6 {
 7     private IEnumerator Start()
 8     {
 9         //這里需要注意的是,如果你想加載的資源有依賴的資源 如貼圖等資源,則必須先加載依賴資源后加載你所想加載的資源。
10         //即A依賴B 則必須先加載B到內存中,然后再加載A 並實例化---這里注意依賴項一般可以不用實例化只需要在內存中即可。
11         //AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials");
12 
13         //第四種遠程加載方式---(專門用於替換WWW的遠程加載方式)
14         //string uri = @"E:/03_TestDemo/01_UnityDemo/ShowMap_ABPackageTest_001/AssetBundles/scene/map_001";
15         string uri = @"http://localhost/AssetBundles/scene/map_001";
16         UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri);
17         yield return request.SendWebRequest();  //注意是異步方式所以必須等待他完成后再執行
18         
19         //兩種獲取ab對象的方式
20         //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); //第一種方法
21         AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; //第二種方法
22 
23         //使用資源
24         GameObject gameObj = ab.LoadAsset<GameObject>("map_001");
25         Instantiate(gameObj);
26 
27         yield return null; //注意上述的遠程加載方式是沒有加載其依賴的資源
28     }
29 }

     5_加載<AB包依賴項> ---(根據AB包文件夾下的 "AssetBundle文件以及AssetBundle.manifest文件")

 1 using System.Collections;
 2 using UnityEngine;
 3 using UnityEngine.Networking;
 4 
 5 public class Load : MonoBehaviour
 6 {
 7    //第一種是服務端加載AB資源包 和依賴包
 8     private IEnumerator Start()
 9     {
10         //從一個服務器下載一個AB包的管理文件AssetBundles 和 AssetBundles.manifest 
11         string uri = @"http://localhost/AssetBundles/AssetBundles";
12         UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri);
13         yield return request.SendWebRequest();
14 
15         //AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; //第一種方法
16         AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);//第二種方法
17         AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
18 
19         string[] str = manifest.GetAllAssetBundles();
20 
21         foreach(string s in str )
22         {
23 
24             UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(@"http://localhost/AssetBundles/" + s);
25             yield return uwr.SendWebRequest();
26             AssetBundle TmpAB = DownloadHandlerAssetBundle.GetContent(uwr);//第二種方法
27             Object[] obj = TmpAB.LoadAllAssets();
28 
29             foreach (Object o  in obj)
30             {
31                 if(o is GameObject)
32                 {
33                     Instantiate(o);
34                 }
35 
36                 print(obj.Length);
37             }
38             
39         }
40 
41 
42 
43         yield return null;
44     }
45 
46 
47 
48     //第二種本地加載AB資源包 和依賴包
49     #region  LoadAB.manifest
50     //private void Start()
51     //{
52     //    //加載得到Manifest文件
53     //    AssetBundle ab = AssetBundle.LoadFromFile("Assets /AssetBundle/AssetBundle");
54     //    AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
55 
56     //    //從Manifest文件中得到所有的AB包的路徑(包括依賴項)
57     //    string[] str = manifest.GetAllAssetBundles();
58     //    foreach (string s in str)
59     //    {
60     //        AssetBundle assetBundle = AssetBundle.LoadFromFile("Assets/AssetBundle/" + s);
61     //        Object[] o = assetBundle.LoadAllAssets();
62     //        foreach (Object temp in o)
63     //        {
64     //            if (temp is GameObject)
65     //            {
66     //                Instantiate(temp);
67     //            }
68     //        }
69     //    }
70     //}
71     #endregion
72 }

 

小結:上述方法直接在場景中見一個空物體掛載其腳本即可(注意前提是AB包必須已經按相應方式創建好了)。

 

//=============================================================================================================

 五:AssetBundle 打包時的分組(僅供參考)

        1、邏輯實體分組:

      a、一個UI界面或者所有UI界面一個包(這個界面里面所有的貼圖和布局信息一個包);

      b、一個角色或者所有角色一個包(這個角色里面的模型和動畫一個包);

      c、所有場景所共有的部分一個包(包括貼圖和模型);

    2、按照類型分組

        所有的聲音資源打成一個包,所有shader打成一個包,所有模型打成一個包,所有材質打成一個包。

    3、按使用分組

       把在某一時間內使用的所有資源打成一個包,可以按照關卡分,一個關卡所需要的所有資源包,包括角色、

       貼圖、聲音等打成一個包,也可以按照場景分,一個場景所需要的資源一個包。

 

  小結:

     1、把經常更新的資源放在一個單獨的包里、跟不經常更新的包分離。

     2、把需要同時加載的資源放在一個包里面。

     3、可以把其他包共享的資源放在一個單獨的包里面。(做依賴,這樣可以減少很多比較資源占用)

     4、把一些需要同時加載的小資源打包成一個包。

     5、如果對一個同一個資源有兩個版本,可以考慮通過后綴來區分(如:v1 v2 v3 )(如unityAB_V1 、unityAV_V2);

 

//=============================================================================================================

六 : 依賴打包簡介

    

    

    小結:如圖所示,其主要的特點是把模型預制體所使用的材質貼圖進行整合,這樣可以避免占用過多的內存資源,

         在加載時也可以避免包過大使用的時間太長,同時避免了資源的重復加載。在需要加載時也可以通過依賴

         關系進行逆向加載。

 

//=============================================================================================================

 

 七: Build AssetBundle方法參數詳解(BuildPipline.BuildAssetBundle)

    1、Build的路徑(只要是在硬盤上都可以的)

    2、BuildAssetBundleOptions(枚舉類型)

       a)、BuildAssetBundleOptions.None:使用LZMA算法壓縮,壓縮的包更小,但加載時間更長,

          使用之前需要整體解壓 。一旦被解壓,這個包會使用LZ4重新壓縮。使用資源的時候不需要整體解壓

          。在下載的時候可以使用LZMA算法。一旦它被下載了之后,它會使用LZ4算法保存到本地上。

       b)、BuildAssetBundleOption.UncompressedAssetBundle (不壓縮,包大,加載速度快)。

 

       c)、BuildAssetBundleOption.ChunkBasedCompression:(使用LZ4算法,壓縮率沒有LZMA高,

              但我們可以加載指定資源的不用解壓全部);

 

       注意:使用LZ4算法,可以獲得可以跟不壓縮相媲美的加載速度,而且比不壓縮的文件要小。

     3、BuildTarget:(選擇Build出來的AB包需要的平台)

      

     圖解:

 

//=============================================================================================================

 

八:關於AssetBundle的卸載

         首先為什么要把AB 包卸載了?其實也很簡單,內存永遠是有限的,當你轉換一個場景或者關卡時,之前不需要的AB包所占用的內存是需要把它

   釋放掉的,這樣才能讓內存永遠保持着一個健康的容量。

   卸載主要有兩個方面:

     1、 減少內存使用,可以保證一個良好且健康的運行內存。

     2、 有可能導致資源丟失問題。

   所以一般什么時候卸載資源呢?

     AssetBundle.Unload(true)卸載所有資源,即使有資源使用着(1,在關卡切換或場景切換時  2、資源沒被用的時候調用);

     AssetBundle.Unload(false)卸載所有沒有被使用的資源。(這個適用時間比較多 ,可自行把控)。

     個別資源怎么卸載,通過Resources.UnloadUnusedAssets();

     當場景切換時,unity會自行執行(Resources.UnloadUnusedAssets()這個方法);

 

//=============================================================================================================

九:關於AssetBundle的文件效驗(每個AB包中有一個manifest文件中就有一個CRC)

   CRC、DM5、SHA1

   相同點:

   CRC、DM5、SHA1都是通過對數據進行計算,來生成一個效驗值,該效驗值用來效驗數據的完整性。

   不同點:

   1、算法的不同。CRC采用多項式除法,MD5和SHA1使用的替換,輪轉等方法。

   2、效驗值的長度不同。CRC效驗值的長度基本跟其多項式有關系,一般為16位或32位,MD5是16個字節(128位);SHA1是20個字節(160位);

   3、效驗值的稱呼不同。CRC一般叫做CRC值;MD5和SHA1一般叫哈希值(Hash)或散列值。

   4、安全性不同。這里的安全性是指效驗的能力,即數據的錯誤能通過效驗位檢測出來,CRC的安全性跟多項式有很大關系,相對於MD5和SHA1要弱很多;MD5的安全性很高,不過大概在04年的時候被山東大學的王小雲破解了;SHA1安全性最高。

       (算法的過程一般是不可逆的,破解即是逆向根據效驗值推導出算法過程列表)

   5、效率不同。CRC的計算效率很高;MD5和SHA1比較慢。

   6、用途不同。CRC一般用作通信數據的效驗,MD5和SHA1用於安全(Security)領域。比如文件效驗、數字簽名等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM