Unity 3D-新版AssetBundle(API介绍&基本分析)

之前介绍了Unity4.x时代的AssetBundle的基本API和简单应用,主要分析一下Unity5.x后新版本的AssetBundle的一些API用法,以及新版AssetBundle系统的优点。

一、AssetBundle系统的新功能

1.新增AssetBundleName属性概念

  • 选中资源,在Inspector下的小窗口通过编辑器的UI界面即可方便的将资源标记为AssetBundle资源,并且一个资源和它对应的AssetBundle的映射将会在资源数据库(AssetDatabase)中被创建。

Unity 3D-新版AssetBundle(API介绍&基本分析)

图中的绿色箭头指向的就是AsssetBundle的名字,也就是新增的assetbundleName属性

后面红色箭头指向的选项(variant),其实就是一个后缀,比如你有相同的图片资源,只是分辨率不同,你就可以分别设置为hd,normal加以区分,在打包时,variant会作为后缀添加在assetbundleName之后。相同assetbundleName,不同variant的Bundle是可以相互替换的。

特别的一点是:assetbundleName可以带有 /,也就是说,编辑好的AssetBundle在创建的时候会按照assetbundleName的名字自带目录结构,把不同的资源按照我们预先的想法分目录,分类别创建,是不是很nice,就像下图一样,这也是我最喜欢的一点

Unity 3D-新版AssetBundle(API介绍&基本分析) Unity 3D-新版AssetBundle(API介绍&基本分析)

2.API新增属性

  • AssetImporter.assetBundleName

设置AssetImporter.assetBundleName的值,即可为该资源指定它所属的AssetBundle。上文中在UI中设置的AssetBundle的名字便是为该值赋值,在资源有了assetBundleName之后,实际上它的信息就已经存在于AssetDataBase里面了。

  • BuildPipeline.BuildAssetBundles()

只需要提供一个输出AssetBundle的相对地址即可。引擎将自动根据资源的assetbundleName属性(即在上文中UI中设置的值)批量打包,自动建立Bundle以及资源之间的依赖关系,这个函数具体的用法下面会继续详细的讲

同时这个API还增加了一些新的打包策略,如下表所示

属性 说明
CompleteAssets 用于保证资源的完备性,默认开启
CollectDependencies 用于收集资源的依赖项,默认开启
DeterministicAssetBundle 用于为资源维护固定ID,默认开启
ForceRebuildAssetBundle 用于强制重打所有AssetBundle文件,新增
IgnoreTypeTreeChanges 用于判断AssetBundle更新时,是否忽略TypeTree的变化,新增
AppendHashToAssetBundleName 用于将Hash值添加在AssetBundle文件名之后,开启这个选项可以直接通过文件名来判断哪些Bundle的内容进行了更新(4.x下普遍需要通过比较二进制等方法来判断,但在某些情况下即使内容不变重新打包,Bundle的二进制也会变化),新增。
ChunkBasedCompression 用于使用LZ4格式进行压缩,5.3新增。

3.新增manifest文件

  • 单个AssetBundle对应的manifest文件

每一个AssetBundle打包后都会生成一个对应的manifest文件包含CRC,Hash,ID,AssetPath以及Dependencies等AssetBundle信息,可以用来做增量更新.

  • 整个资源文件夹打包后的manifest文件

在整个资源文件夹打包后会在AssetBundle打包目录下生成一个和目录名字相同的mainfest文件,存贮了整个文件夹内所有的assetbundle的信息,以及它们之间互相依赖的信息,所以我们加载assetbundle的时候,需要先把总的manifest文件加载进来,以确认各个bundle之间的依赖关系。

二、API汇总详解

1.AssetBundle文件的创建

新版系统统一了打包函数提供唯一的API(BuildPipeline.BuildAssetBundles)来打AssetBundle包,如下

public static AssetBundleManifest BuildPipeline.BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform)

  • 第一个参数是一个相对路径,一定注意,后面的除了新增的几个属性,基本和4.x一样,可以参考我之前的博客,或者百度。
  • 在脚本中调用BuildPipeline.BuildAssetBundles,Unity 3D将自动根据资源的assetbundleName属性批量打包,自动建立Bundle和资源之间的依赖关系。
  • 每个assetbundleName对应一个assetbundle,即assetbundleName相同的资源会打在一个Bundle中。 如果所依赖的资源设置了不同的assetbundleName,则会自动与之建立依赖关系,避免出现冗余,从而减小Bundle包的大小。
  • 除了可以指定的assetbundleName,还有我们上面提到的variant,进一步区分。

打包基本用法如下

2.AssetBundle的压缩

Unity 3D为我们提供了三种压缩策略处理AssetBundle的打包,如下

  • LZMA压缩格式

默认情况下,打包生成的AssetBundle都会被压缩。在Unity 3D中,AssetBundle的标准压缩格式便是LZMA(LZMA是一种序列化流文件,缺省文件),因此在默认情况下,打出的AssetBundle包处于LZMA格式的压缩状态,在使用AssetBundle前需要先解压缩。

注:使用LZMA格式压缩的AssetBundle的包体积最小(高压缩比),但是相应的会增加解压缩时的时间。

  • LZ4压缩格式

LZ4的压缩比一般,经过压缩后的AssetBundle包体的体积较大(该算法基于chunk)。但是,使用LZ4格式的好处在于解压缩的时间相对要短。

若要使用LZ4格式压缩,只需要在打包的时候开启BuildAssetBundleOptions.ChunkBasedCompression即可,如下

BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.ChunkBasedCompression);

注:Unity 5.3之后的版本才增加了LZ4格式压缩,使用时一定注意

  • 不采取任何压缩

没经过压缩的包体积最大,但是访问速度最快。

若要使用不压缩的策略,只需要在打包的时候开启BuildAssetBundleOptions.UncompressedAssetBundle即可,如下

BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.UncompressedAssetBundle);

3.AssetBundle的加载

使用AssetBundle动态加载资源首先要获取AssetBundle对象,第二步才是从AssetBundle中加载目标资源。因此本小节将主要关注如何在运行时获取AssetBundle的对象,关于如何从AssetBundle中加载资源将在下一小节中分析。

  • 加载函数API的替换
    • 4.x版本中的 AssetBundle.CreateFromFile方法,在5.x版本中变成了 AssetBundle.LoadFromFile方法。
    • 4.x版本中的 AssetBundle.CreateFromMemory方法,在5.x版本中变成了 LoadFromMemoryAsync方法。
    • 4.x版本中的 AssetBundle.CreateFromMemoryImmediate方法,在5.x版本中变成了 LoadFromMemory方法。

注:这儿的5.x貌似是5.3以上,5.1.1的版本API仍然和之前4.x的一致

  • public WWW(string url)

直接调用WWW类的构造函数,目标AssetBundle所在的路径作为其参数,构造WWW对象的过程中会加载Bundle文件并返回一个WWW对象,完成后会在内存中创建较大的WebStream(解压后的内容,通常为原Bundle文件的4~5倍大小,纹理资源比例可能更大),因此后续的AssetBundle.LoadAsset可以直接在内存中进行。

  • public static WWW LoadFromCacheOrDownload(string url, int version, uint crc = 0)

WWW类的一个静态方法,调用该方法同样会加载Bundle文件同时返回一个WWW对象,和上一个直接调用WWW的构造函数的区别在于该方法会将解压形式的Bundle内容存入磁盘中作为缓存(如果该Bundle已在缓存中,则省去这一步),完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.LoadAsset需要通过IO从磁盘中的缓存获取。

在4.x时代,我们可以通过CreateFromFile或CreateFromMemory方法将磁盘上的文件或内存中的流构造成我们需要的AssetBundle对象。但是在5.x版本中,曾经的这两个方法已经被新的LoadFromFile、LoadFromMemory方法所代替(这两个方法还有异步的版本),且机制上也有了一些区别

  • public static AssetBundle LoadFromFile(string path, uint crc = 0)

新的从文件创建加载AssetBundle方法和4.x中的CreateFromFile方法在机制上有了一些分别,旧的CreateFromFile必须使用未压缩的Bundle文件才能在运行时动态创建AssetBundle对象。而新的LoadFromFile方法则没有这个要求,它支持上一节中提到的几个压缩格式,针对LZ压缩格式和未压缩的磁盘上的bundle文件,该方法会直接加载。针对使用默认的LZMA压缩格式压缩的bundle文件,该方法会在幕后先将bundle文件解压后再加载。这是最快的加载AssetBundle的方式。该方法是同步版本,还有异步版本:LoadFromFileAsync。

  • public static AssetBundle LoadFromMemory(byte[] binary, uint crc = 0)

从内存中获取Bundle的二进制数据,同步地创建AssetBundle对象。该方法一般用在经过加密的数据上,经过加密的流数据经过解密之后我们可以调用该方法动态的创建AssetBundle对象。该方法是同步版本,还有异步版本:LoadFromMemoryAsync。

下面给一个Unity管方的总结,从加载过程中内存消耗的角度来对比一下这几种加载AssetBundle对象的方法

Unity 3D-新版AssetBundle(API介绍&基本分析)

当然为了避免阻塞,在加载AssetBundle对象时,建议使用LoadFromFileAsync方法进行异步加载。

4.从AssetBundle中加载资源

通过一个表来说明

Unoty 4.x Unity 5.x API说明
Load LoadAsset 从资源包中加载指定的资源
LoadAll LoadAllAsset 加载当前资源包中所有的资源
LoadAsync LoadAssetAsync 从资源包中异步加载资源

5.卸载AssetBundle资源

依旧是Unload函数 public void Unload(bool unloadAllLoadedObjects);

该方法会卸载运行时内存中包含在bundle中的所有资源。

当传入的参数为true,则不仅仅内存中的AssetBundle对象包含的资源会被销毁。根据这些资源实例化而来的游戏内的对象也会销毁。

当传入的参数为false,则仅仅销毁内存中的AssetBundle对象包含的资源。

三、新版AssetBundle的优势

  • 由于引擎提供的新功能,我们就不再需要像4.x时代那么复杂的用来打包的脚本了。

同时,资源之间的互相依赖关系不再需要开发者手动维护了,曾经由于不当使用PushAssetDependencies/PopAssetDependencies而可能会造成依赖出现的问题,现在Unity3D已经为我们解决了。

  • 由于引入了清单文件manifest,基于manifest文件,新版的AssetBundle打包后会自动帮我们处理依赖关系,因此我们可以实现增量更新,即只需要更新有变化的部分,而没有变化的则不必更新。

举一个例子:

假设我们有一个cube,它的material有一个材质,我们分别将cube和material打包成cubeBundle和materialBundle,我们现在只需要修改material上的材质。在过去,我们需要分别重新为cube和material打包,而现在只需要对material重新打包即可,cube不受影响。

以上就是关于新版本AssetBundle的一些介绍,具体实战可以看我下一篇博客,欢迎围观~~~

繁夜

发表评论


:[微笑]::[撇嘴]::[色]::[发呆]::[得意]::[流泪]::[害羞]::[闭嘴]::[睡]::[大哭]::[尴尬]::[发怒]::[调皮]::[呲牙]::[惊讶]::[难过]::[酷]::[冷汗]::[抓狂]::[吐]::[偷笑]::[可爱]::[白眼]::[傲慢]::[饥饿]::[困]::[惊恐]::[流汗]::[憨笑]::[大兵]::[奋斗]::[咒骂]::[疑问]::[嘘...]::[晕]::[折磨]::[衰]::[骷髅]::[敲打]::[再见]::[擦汗]::[抠鼻]::[鼓掌]::[糗大了]::[坏笑]::[左哼哼]::[右哼哼]::[哈欠]::[鄙视]::[委屈]::[快哭了]::[阴险]::[亲亲]::[吓]::[可怜]::[笑哭]::[doge]::[泪奔]::[无奈]::[托腮]::[斜眼笑]::[喷血]::[惊喜]::[骚扰]::[小纠结]::[我最美]::[羊驼]::[幽灵]::[吃]::[OK]::[爱你]::[抱拳]::[勾引]::[强]::[弱]::[拳头]::[爱心]::[喝彩]::[西瓜]::[啤酒]::[玫瑰]::[凋谢]::[礼物]::[拥抱]::[月亮]::[菊花]::[棒棒糖]::[蛋]::[刀]::[菜刀]::[炸弹]::[手枪]:

刷新评论