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)领域。比如文件效验、数字签名等。

 

posted on 2019-07-24 18:17  嗜睡的熊大  阅读(11984)  评论(0编辑  收藏  举报

导航