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

  • 相关阅读:
    K3s+Jetson Nano,在边缘端实现实时视频分析!
    15分钟连接Jetson Nano与K8S,轻松搭建机器学习集群
    配置高可用K3s集群完全攻略
    K3s+Sysdig,8分钟部署并保护集群安全!
    1款工具助力Rancher HA快速部署,极速提升研发测试效率
    连刷40道题,告别动态规划,谈谈我的经验
    直通BAT算法精讲视频教程分享
    关于三次握手和四次挥手,面试官想听到怎样的回答?
    Redisson 分布式锁实战与 watch dog 机制解读
    Spring 注解动态数据源设计实践
  • 原文地址:https://www.cnblogs.com/Roz-001/p/11237198.html
Copyright © 2020-2023  润新知