AssetBundle打包策略

来源:互联网 发布:新田惠海 知乎 编辑:程序博客网 时间:2024/05/21 22:41
本文转自http://liweizhaolili.blog.163.com/blog/static/162307442015112024417742/   【阿赵的博客】
自从Unity5出来以后,我写了这么几篇博客介绍unity5的新AssetBundle打包方法,也说了一些坑:
http://liweizhaolili.blog.163.com/blog/static/1623074420159118398457/
http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/
http://liweizhaolili.blog.163.com/blog/static/162307442015282017852/
    这几篇文章都比较的受到关注,说明了关心新AssetBundle用法的朋友还是很多的。下面我将会针对各位关心的比较多的问题,来分析一下自己的一些做法。
    在说策略之前,首先说一个比较令人高兴的事情,就是之前我说到的一些AssetBundle重复打包的bug,在unity5.3.0版本已经全部的修复了。所以现在可以比较放心的去使用这个新的AssetBundle了。于是之前我自己做的一些东西,比如自己打图集、自己拆分UI依赖图片等的操作就变得有点没有意义了。这好像是有点白花力气的感觉,但对于我来说,这些手段都只是因为官方提供的方法出问题时的一些临时补救方法,现在官方的变得可靠之后,肯定首选是用官方的。这也是我为什么弃NGUI不用而转用UGUI的原因。
    接下来说说打包策略的问题
一、关于打包时的依赖细分程度
    对于AssetBundle的打包策略,最多人关系的一个问题是,究竟要把资源的依赖细分到什么级别。
    在我写第一篇介绍AssetBundle的文章的时候,我写了一个小例子,通过查找所有资源的依赖,为每一个依赖的资源设置了AssetName。其实我当初写那个例子的目的,只是为了介绍一下怎样用工具自动化的为资源设置AssetName,而不需要手动的一个个去设置。不过这个例子似乎对很多人造成了误导,以为阿赵教大家必须把每一个资源都单独的设置AssetName而打包成单独的AssetBundle。
    不过在后来很多人针对这个问题和我交流的时候,我发现真的有一部分人是坚持这样做的,所谓的把拆分力度做得最大,把所有依赖拆分了之后,让冗余重复资源变得最小。
    这样的想法,从理论上来说是没什么问题的,这样做看起来冗余是最小的,资源也将会是最省的。但我只能说坚持这样做的人,似乎较为欠缺实际的项目经验。
    为什么这么说呢?首先我们先来看看如果我们把每一个依赖的东西都拆分得最细单独打包之后,我们需要做什么样的工作:
举一个小例子,比如我们需要加载模型A,它依赖于材质B和材质C,然后材质B用到了图片1、2、3,材质C用到了图片4、5、6。
那么假设我们把依赖都拆分得很细,我们就会得到了9个单独的AssetBundle,当我们需要加载模型A的时候,我们需要做的事情是:
1、下载所有依赖的保存文件
2、从依赖信息里面查找到该模型所有的依赖列表
3、逐个文件的去下载或者本地加载
4、逐个文件加载完之后放到内存里面
5、确保每个依赖的AssetBundle都加载完之后,最后加载该模型
实际上在我们加载到模型A的时候,我们已经进行了多次的检查依赖和9次的实际加载。
    再来看看如果我不拆分资源,只是把模型A单独打包成一个AssetBundle,那么我们加载这个模型的步骤,就变成了:
1、下载依赖信息文件
2、找不到依赖列表
3、直接加载模型A
是不是两者之间的差距就很明显了?
    由这个过程可以看出,如果文件拆得非常的散,在加载一个文件的时候,你消耗在过程步骤里面的时间将会增多很多,而且由于加载都是需要进行外部读取的,例如网络加载。这样多次的加载,造成出错的机会更加增多了。这种情况我们一般称为碎片文件增多了。
    
二、阿赵正在使用的打包策略
    
    首先,对于拆分的看法是,能不拆就尽量不拆,当出现冗余必须拆的时候,只拆有共用的资源。
    然后,消除冗余我一般分成了两步走:1、通过文件夹来区分不同的打包策略,2、写个小工具来检查冗余
    1、通过文件夹来区分不同的打包策略
    阿赵是一个很懒的人,所以能写自动化工具的地方,阿赵从来不会手动去操作的。所以阿赵会在项目里面规定了一个文件夹,然后写了一个小工具。只要是放到这个文件夹内的所有资源,阿赵都会给他设置一个AssetName,然后打包出去。不过这个AssetName却不一定是每个文件都不一样的。这个文件夹里面会分成几个大类:
    1.无脑型直接每个不同文件设置一个不同的AssetName的,例如一般的散图和模型
    2.需要把几个文件同时打包到一个AssetBundle里面的,比如一些模型组合之类
    3.需要把几个文件同时打包到一个AssetBundle里面,还顺便有一些其他规则的,例如图集,需要批量设置图集标签等
    根据这几个类别,把模型放到不同的文件夹,然后根据不同的文件夹规则来进行批处理。
    这样的做法,好处就是制作游戏的人不需要关系他的AssetBundle需要怎样打包,只需要把文件放到相应的文件夹,然后根据文件夹加载就行了。而且如果以后规则增多了,只需要再增加不同的文件夹就可以满足新的需求而不影响旧的规则,扩展性还是不错的。
    然后所谓的批处理,其实也就是根据不同的文件夹,做了不同的设置AssetName的规则处理而已了。最后统一调用一个生成的方法,所有设置了AssetName的文件,就会被打包成对应的AssetBundle了。
    
    2、写个小工具来检查冗余
    看到上面的方法,有些人还是会心存顾虑的,如果我的散模型各自都引用了相同一个材质或者图片,不就还是会出现了重复冗余吗?是的,所以还需要第二步,检查冗余。
    之前介绍的方法有点漏洞,经网友指出,我做了点修改,写了另外一篇文章介绍:
http://liweizhaolili.blog.163.com/blog/static/162307442016159334513/
最后得到的列表,就是被引用了2次以上的公用资源,只需要把这些资源设置一下AssetName,打包的时候,冗余就会完全消失了。
    打包的策略说完了,最后说说我对AssetBundle加载的一些看法:
1、官方提供了多种方法给我们从外部加载AssetBundle,比如WWW加载、本地文件加载、从内存加载等。在很多Unity老用户的心里面,WWW加载才是正常首选的方法,但实际上现在很多人做项目已经不选这种方法了,都是通过自己的http加载方法把资源加载到本地,然后再从本地文件加载的。这样可以做到同步加载,而且可控性也会更高。
2、关于是否加密。在5.3.0之前,使用本地加载,包括了CreateFromFile或者CreateFromMemory,都必须是选用不压缩的方式打包AssetBundle的。但在5.3.0开始,unity官方做了一件好像很牛逼的事情,就是那些本地加载的方法,完全支持了压缩打包的AssetBundle。对于这种情况,阿赵我的选择是:仍然不压缩AssetBundle打包。原因有几:
    1.在打包AssetBundle时选择压缩方式,对比先不压缩AssetBundle再在打包出AssetBundle后用自己的zip方法压缩,资源的容量基本上是一样的。
    2.读到内存,之前打包压缩的AssetBundle其实也是先解压缩,然后再保存到内存的,占用是一样的。
    3.如果AssetBundle是压缩的,那么只能选择在加载的时候通过unity自带的方法来解压缩,耗时肯定会比不压缩的AssetBundle加载时多,而且每次加载都必须解压缩一次。
    4.如果不压缩AssetBundle而用zip后期压缩,那么可以自己自由选择什么时候解压缩都可以,而且只需要解压缩一次保存在本地,就不需要再次解压缩了。
    
    当然了,也不是说先压缩一点好处都没有。
    首先,如果你是WWW下载的使用者,你就只能选择直接打包时压缩AssetBundle了,zip方法和你没什么关系。
    然后,如果你是把资源直接保存在本地的,那么压缩过的AssetBundle直接的容量就会比从zip包解压出来的AssetBundle小,造成的影响就是占用玩家手机的硬盘空间小了。这种情况就要看究竟是玩家的硬盘重要,还是你的游戏运行效率重要了。阿赵我是一个比较没有道德的人,所以优先选择了拿玩家的硬盘换我的效率了。
    以上就是阿赵现在在项目里面用到的AssetBundle相关的打包策略和加载方法。欢迎大家继续讨论,之前一位朋友在讨论这个问题的时候给了我挺多的启发,阿赵感觉很高兴。