AssetBundle AB包

最后更新于 2022-10-20 490 次阅读


参考

http://t.csdn.cn/7G1wY

http://t.csdn.cn/fBueH

Unity资源管理

在Unity中,一般来说,资源加载方式主要分为Resources加载和AssetBundle加载。

Unity有个特殊文件夹Resources,放在这个文件夹下的资源可以通过Resources.Load()来直接加载。即Resources加载资源方式。

当获得AssetBundle之后,也可以调用AssetBundle对应的API来加载资源。

AssetBundle的概念

AssetBundle又称AB包,是Unity提供的一种用于存储资源的资源压缩包。

Unity中的AssetBundle系统是对资源管理的一种扩展,通过将资源分布在不同的AB包中可以最大程度地减少运行时的内存压力,可以动态地加载和卸载AB包,继而有选择地加载内容。

AssetBundle的优势

  • AB包存储位置自定义,继而可放入可读可写的路径下便于实现热更新
  • AB包自定义压缩方式,可以选择不压缩或选择LZMA和LZ4等压缩方式,减小包的大小,更快的进行网络传输。
  • 资源可分布在不同的AB包中,最大程度减少运行时的内存压力, 可做到即用即加载,有选择的加载需要的内容。
  • AB包支持后期进行动态更新,显著减小初始安装包的大小,非核心资源以AB包形式上传服务器,后期运行时动态加载,提高用户体验。

AssetBundle的特性

  • AB包可以存储绝大部分Unity资源但无法直接存储C#脚本,所以代码的热更新需要使用Lua或者存储编译后的DLL文件。
  • AB包不能重复进行加载,当AB包已经加载进内存后必须卸载后才能重新加载。
  • 多个资源分布在不同的AB包可能会出现一个预制体的贴图等部分资源不在同一个包下,直接加载会出现部分资源丢失的情况,即AB包之间是存在依赖关系的,在加载当前AB包时需要一并加载其所依赖的包
  • 打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)

打包流程

AssetBundleBrowser面板的使用

  • Configure面板 :能查看当前AB包及其内部资源的基本情况(大小,资源,依赖情况等)
  • Build面板:负责AssetBundle打包的相关设置 按Build即可进行打包

三种压缩方式

  1. NoCompression:不压缩,解压快,包较大,不建议使用。
  2. LZMA: 压缩最小,解压慢,用一个资源要解压包下所有资源。
  3. LZ4: 压缩稍大,解压快,用什么解压什么,内存占用低,更建议使用。
  • Inspect面板:主要用来查看已经打包后的AB包文件的一些详细情况(大小,资源路径等)

设置资源所属的AssetBundle包

在需要打包的资源的Inspector面板下方即可选择其应放在哪个AB包下,也可通过New新建AB包将资源放入,放入后再次Build打包即可将此资源打入相应的AB包中。

AssetBundle管理器

利用AssetBundleBrowser可以轻松实现AB包的打包工作,更重要的是如何将AB包中的资源加载出来并使用它们,Unity已经提供了一组API能够实现AB包的加载和资源的加载。

AB包管理器的主要需求:加载指定AB包下的指定资源,基本步骤如下:

  1. 加载资源所在AB包及其的所有依赖包(根据主包的manifest信息找依赖包名称)
  2. 从AB包中加载指定的资源(根据名称,类型)
  3. 不再使用时卸载已经加载了的AB包
//AB包加载所需相关API
//1. 根据路径进行加载AB包 注意AB包不能重复加载
AssetBundle ab = AssetBundle.LoadFromFile(path);
//2. 加载ab包下指定名称和类型的资源
T obj = ab.LoadAsset<T>(ResourceName); //泛型加载
Object obj = ab.LoadAsset(ResourceName); //非泛型加载 后续使用时需强转类型
Object obj = ab.LoadAsset(ResourceName,Type); //参数指明资源类型 防止重名
T obj = ab.LoadAssetAsync<T>(resName); //异步泛型加载
Object obj = ab.LoadAssetAsync(resName); //异步非泛型加载
Object obj = ab.LoadAssetAsync(resName,Type); //参数指明资源类型 防止重名
//3. 卸载ab包 bool参数代表是否一并删除已经从此AB包中加载进场景的资源(一般为false)
ab.UnLoad(false); //卸载单个ab包
AssetBundle.UnloadAllAssetBundles(false); //卸载所有AB包

内存占用

这是从网络中下载资源的内存占用情况。

下载的资源包括AB包、图片、材质、动画、音频等,以Stream的形式存储在内存中。(AB包中也可以有图片、材质、动画、音频等资源)

之后通过加载AB包的方法,将AB包加载到内存中去。

AB包内的资源需要通过AssetBundle.Load()来加载到内存中。

对于GameObject来说,通常情况下需要对其进行改动,所以它是完全复制一份该资源来进行的实例化。也就是说,当AB包中的GameObject从内存中卸载后,实例化的GameObject不会因此丢失。并且对实例化对象的修改不会影响到GameObject资源。

对于Shader和Texture来说,通常情况下不需要对其进行改动,所以它是通过引用来进行的实例化。也就是说,当AB包中的Shader和Texture资源从内存中卸载后,实例化的Shader和Texture会出现资源丢失的情况。并且对实例化对象的修改会影响到Shader和Texture资源。

对于Material和Mesh来说,有时候可能需要对其进行改动,所以它是通过引用+复制来进行的实例化。也就是说,当AB包中的Material和Mesh资源从内存中卸载后,实例化的Material和Mesh会出现资源丢失的情况。并且对实例化对象的修改不会影响到Material和Mesh资源。

总结大致流程为:

AB包先要从硬盘或者网络中加载到内存中,然后将AB包内的每一份资源加载到内存中,再之后在内存中实例化这些资源。每种资源有其自己不同的实例化方式,卸载资源的时候需要注意。

依赖问题

依赖问题,通俗的话来说就是A包中某资源用了B包中的某资源。然而如果A包加载了,B包没有加载,这就会导致A包中的资源出现丢资源的现象。

在Unity5.0后,BuildAssetBundleOptions.CollectDependencies永久开启,即Unity会自动检测物体引用的资源并且一并打包,防止资源丢失遗漏的问题出现。

因为这个特性,有些情况下,如果没指定某公共资源的存放在哪个AB包中,这个公共资源就会被自动打进引用它的AB包中,所以出现多个不同的AB包中有重复的资源存在的现象。这就是资源冗余。

这种情况下,哪怕资源是一模一样,也无法进行合并优化。

要防止资源冗余,就需要明确指出资源存放在哪个AB包中,形成依赖关系。所以对于一些公共资源,建议单独存放在一个AB包中。

在加载的时候,如果AB包之间相互依赖,那么加载一个AB包中的资源时,先需要加载出另一个AB包的资源。这样就会导致不必要的消耗。所以说尽可能地减少AB包之间的依赖,并且公共资源尽量提前加载完成。