unity中Assetunitybundle压缩问题

 是一种默认的压缩形式这种标准压缩格式是一个单一LZMA流序列化数据文件,并且在使用前需要解压缩整个包体LZMA压缩是比较流行的压缩格式,能使压缩后文件达到最小泹是解压相对缓慢,导致加载时需要较长的解压时间

 Unity支持LZ4压缩,能使得压缩量更大而且在使用资源包前不需要解压整个包体。LZ4压缩是┅种“Chunk-based”算法因此当对象从LZ4压缩包中加载时,只有这个对象的对应模块被解压即可这速度更快,意味着不需要等待解压整个包体LZ4压縮格式是在pressionEnabled属性控制的,它能影响到在磁盘中保存的资源包以及缓存在内存中的资源包

  以下这张表是当使用不同的压缩方式和不同的加載方法时,内存和性能的开销情况比较:

内存:未压缩资源包的大小(+当WWW未被Disposed时未压缩资源包的大小)
性能:没有额外的处理过程
性能:没有額外的处理过程 性能:当下载的时候LZMA解压过程+LZ4压缩过程
内存:没有额外内存占用
性能:从磁盘读取的过程
内存: 没有额外内存占用
性能:从磁盘读取的过程
内存:没有额外内存占用
性能:从磁盘读取的过程
 内存:未压缩的资源包大小
性能:没有额外的处理过程
内存:LZ4高压縮资源包的大小
性能:
没有额外的处理过程
内存:没有额外内存占用
性能:从磁盘读取的过程
内存:没有额外内存占用
性能:从磁盘读取嘚过程
内存:没有额外内存占用
性能:从磁盘读取的过程
内存:LZ4压缩包的大小
 内存:未压缩的资源包大小
性能:没有额外处理过程[+如果缓存则从磁盘中读取的过程]
 内存:LZ4高压缩包的大小
性能:
没有额外处理过程[+如果缓存则从磁盘中读取的过程]
内存:LZ4压缩包的大小
性能:
当下載的时候,LZMA解压过程+LZ4压缩过程[+如果缓存则从磁盘中读取的过程]

*当使用WWW方式下载资源包的时候WebRequest还有一个8*64kb的叠加缓存用来保存来自Socket的数据

总結——在游戏里使用低级加载的API时,有以下建议:

通常应该选择异步的方式进行加载因为这样不会阻塞主线程,并且能对加载操作有效嘚排序千万不要在同一时间里调用同步和异步函数,这可能会引起主线程的停顿

  为了支持新的压缩类型,Assetunitybundle压缩资源包包含的格式改变叻并且为进一步的改善提供了基础。Unity5版本仍然支持Unity4版本打包的资源但是不支持2.x和3.x版本的打包资源了。

一个Assetunitybundle压缩资源包本质上是一组对潒组合成的一个序列化文件这个文件有一个稍微不同的结构,结构的不同取决与这是一个普通资源包还是场景包

    1、非缓存方式下载:通过创建一个WWW类对象来下载(WWW www = new WWW(url)),这种方式不会缓存到本地存储的文件中

    2、缓存方式下载:通过使用WWW.LoadFromCacheOrDownload()进行下载,这种方式会自动缓存在夲地存储设备的Unity缓存文件夹中PC/MAC独立应用程序以及IOS/Android应用程序都有4GB的大小限制。对于其他平台可以查看相关的脚本文档。

下面是官方的非緩存下载的例子脚本:

官方推荐的下载Assetunitybundle压缩s方式是使用WWW.LoadFromCacheOrDownload()它的工作原理是先通过(版本号和下载地址)先在本地去找看有没有这个Assetunitybundle压缩,洳果有直接返回对象如果没有的话,在根据这个下载地址重新从服务器或者本地下载这里版本号起到了很重要的作用,举个例子同┅下载地址版本号为1的时候已经下载到本地,此时将版本号的参数改成2 那么它又会重新下载如果还保持版本号为1那么它会从本地读取,洇为本地已经有版本号为1的这个Assetunitybundle压缩了你不用担心你的资源本地下载过多,也不用自己手动删除他们这一切的一切Unity会帮我们自动完成,它会自动删除掉下载后最不常用的Assetunitybundle压缩 如果下次需要使用的话只要提供下载地址和版本后它会重新下载。脚本例子如下


//等待缓存系統
完成缓存准备

//如果本地缓存中存在相同版本号的Assetunitybundle压缩资源就会从本次返回对象


pro提供的一种用来存储资源的文件格式它可以存储任意一种Unity引擎能够识别的资源,如Scene、Mesh、Material、

Texture、Audio、noxss等等同时,Assetunitybundle压缩也可以包含开发者自定义的二进制文件只需要将自定義文件的扩展名改

压缩(缺省)、动态载入、本地缓存;

该API功能与a相同,但创建的时候可以为每个Object指定一个自定义的名字(一般不太常鼡)

包含每个Asset依赖的所有其他Asset;

在Assetunitybundle压缩中不包含类型信息。需要注意的是如果将Assetunitybundle压缩发布到web平台上,则不能使用这个选项;

使每个Object具有唯一的、不变的HashID便于后续查找可以用于增量发布Assetunitybundle压缩;

不进行数据压缩。如果使用这个选项因为没有压缩/解压的过程,Assetunitybundle压缩发布和加載会更快但是Assetunitybundle压缩也会更大,导致下载变慢

果游戏中的某个资源被多个资源引用(例如游戏中的Material),单独创建Assetunitybundle压缩会使多个Assetunitybundle压缩都包含被引用的资源

(这里跟flash编译选项中的链接选项有些像)从而导致资源变大,这里可以通过指定Assetunitybundle压缩之间的依赖关系来减少最终

元素依賴栈内的元素(记得要pop!)

Unity引擎提供了两种方式从服务器下载Assetunitybundle压缩文件,分别是缓存机制和非缓存机制

Assetunitybundle压缩下载方式。下载Assetunitybundle压缩的时候该接口会先在本地缓存中查找该文件,看其之前是否被下载过,如果下载过则直接从缓

存中加载,如果没有则从服务器尽享下载。這样做的好处是可以节省Assetunitybundle压缩文件的下载时间从而提高游戏资源的载入速度(还可以节省下载流

越快,但是需要考虑时机的机器火平台嘚承载能力如果一定要从网上下载资源的话,线程数最好设为5个(别人的经验)很多平台也有自己的限制,例如有的浏

览器只能同事加载6个等等

需要注意的是,Unity提供的默认缓存大小是根据发布平台不同而不同的(可以向Unity购买Caching license支持)目前对于web player的网页游戏,默认缓存大尛为50M;对于PC上的客户端或者?上的移动游戏,默认缓存大小为4GB

通过创建一个WWW实例来对Assetunitybundle压缩文件下载,下载后的Assetunitybundle压缩文件将不会进入Unity的缓存区使用这种方法每次都会从远端服务器下载。

7.1、通过WWW类方法和属性

7.2、通过API动态创建

主资源在构建资源boundle时指定(只读)该功能可以方便的找到unitybundle压缩内的主资源。例如你也许想有一个角色的预制体并包括所有纹理、材质、

网格和动画文件。但是完全操纵角色的预设体应該是你的mainAsset并且易于被访问;

//获取指定的主资源并实例化

Application.LoadLevel 该接口可以通过名字或者索引载入Assetunitybundle压缩文件中包含的对应场景当夹在新场景时,所有之前加载的GameObject都会被销毁;

内存一直都是开发者关注的一个重点如果要了解清楚内存的使用情况。

引擎在使用WWW方法时会分配一系列的內存空间来存放WWW实例对象、WebStream数据该数据包括原始的Assetunitybundle压缩数据、解压后的

Buffer,不被系统回收这样做的好处是不用过于频繁的开辟和销毁解壓Buffer,从而在一定程度上降低CPU的消耗

性来获取Assetunitybundle压缩对象,从而可以得到各种Assets进而对这些Assets进行加载或者实例化操作。加载过程中Unity会将

Assetunitybundle压縮中的数据流转变为引擎可以识别的信息类型(纹理、材质、对象等)。加载完成后开发者可以对其进行进一步的操作,比如对象的实唎

化、纹理和材质的复制和替换等

3)对于实例化出来的GameObject,可以调用GameObject.Destory()接口来卸载该接口会延后到一个合理的时机进行处理。

注意:这是沒有处理好的一个环节在WWW加载资源完毕后,对资源进行instantiate后对其资源进行unload,这时问题就发生了,instantiate处理渲染需要一定的时间虽然很短,但吔是需要12帧的时间。此时进行unload会对资源渲染造成影响以至于没有贴图或 者等等问题发生。解决办法:自己写个时间等待代码等待个0.5秒到1秒之后再进行Unload。这样就不会出现instantiate渲染中就运行unload的情况了

Assetunitybundle压缩中的资源上如果Attach了脚本,打包的时候该脚本是不会被打到Assetunitybundle压缩中的其實这里只是保存了一个类似于指针的关联,如果需要把脚本也动态打到Assetunitybundle压缩中还需要做一番工作。

首先将脚本预先编译成assembly,把assembly保存成.bytes攵件这样Unity会把它识别为TextAsset,就可以将这个TextAsset打包到Assetunitybundle压缩中了载入后可以通过反射机制使用该脚本,代码如下:

需要注意的是IOS平台不支持動态载入脚本。

crc)加载其中的第二个参数-version可以用来做版本控制,该参数强制用户从服务器下载一个更高版本的Assetunitybundle压缩我们可以通过第

件损壞,Unity会重新下载该文件对于crc的获取,(老版本没有提供方法只能通过LoadFromCacheOrDownload传一个错误的

crc,从log中获取)新版本在BuildAssetunitybundle压缩的时候增加了一个out类型的参数,该参数会返回正确的crc码打包的时候可以记

提供了一种可以公用的类——noxssableObject,适用于描述动态划分场景;通过代码划分场景——>咑包多个Assetunitybundle压缩——

>将划分信息记录在ScriptableObject中并保存至Asset——>载入时先载入划分信息,再根据这个划分信息载入

10.4、关于编辑器扩展

可以通过事件觸发来执行你的编辑器代码但是我们需要一些编译器参数来告知编译器何时需要触发该段代码。 [MenuItem(XXX)]声明在一个函数上方告知编译器给Unity3D编輯器添加一个菜单项,并且当点击该菜单项的时候调用该函数触发函数里可以编写任何合法的代码,可以是一个资源批处理程序也可鉯弹出一个编辑器窗口。代码里可以访问到当前选中的内容(通过Selection类)并据此来确定显示视图。与此类似[ContextMenu("XXX")]可以向你的上下文菜单中添加一个菜单项。

Editor目录下的脚本会在其它脚本之后进行编译这方便了你去使用那些运行时的内容。而那些目录下的脚本是不能访问到Editor目录丅的内容的所

以,你最好把你的编辑器脚本写在Editor目录下

10.5、关于差量发布

在5.2中介绍了创建Assetunitybundle压缩的参数,其中的d选项在选中的时候可以使楿同的内容两次发布出来的文件是完全一样的我们在创建Assetunitybundle压缩的时候选择上这个参数,那么就可以做差量了测试数据如下:

10.6、关于项目中应用

项目中使用Assetunitybundle压缩做开发可以使用宏进行隔离,接口封装尽量采用异步接口通过引用计数cache机制,确定ab的释放时机大体流程如下:

a、确定加载ab次数(资源数)

c、成功后根据资源url引用计数减去对应资源数

代码中使用的地方可以通过封装的GetObject获取已经加载的对象,使用完荿后可以调用Resources的UnloadUnUsedAssets释放资源

的粒度越小,差量更新的冗余就会越小粒度越大,差量更新的冗余就会越大但是,并不是说粒度越小就越恏粒度小了,(运行时)加载的时候会增加IO次

数、解压次数(AB一般选择压缩格式)和申请内存的次数导致加载时长变长。因此粒度的控制是一个时间与空间平衡的选择过程经过实验,大体有一个数据可

以用来参考1M左右的Assetunitybundle压缩包加载性能最好,冗余也可以接受

Assetunitybundle压缩壓缩与不压缩的差异主要有两方面:

a、外存(安装包的大小或者安装后占用磁盘空间的大小)

b、加载方式的选择(能否使用同步方法)

里洳果一些对性能要求特别高,资源又不大的AB可以采用非压缩方式通过CreateFromFile加载AB包,性能最高又不会产生大量的内存对于其

他的资源文件,建议压缩处理压缩与非压缩在磁盘占用上会有4倍左右的大小差别,如果都采用非压缩格式有可能会导致你的磁盘占用达到一个非常恐怖的量

装后的磁盘构成基本上是资源的内存值(Resources目录下资源),举个粒子一张真彩色的的图片放到Resources目录下安

装后占用的内存为4M(4*)。如果你的游戏是一个2D的又包含很多的图片资源,这样会使你的安装包在用户机器上安装需要大量的磁盘

空间这里你可以把它们打成AB包放箌用户的手机上,这样就磁盘占用就会小很多了

        Unity的Assetunitybundle压缩系统是对资源管理的一个擴展动态更新,网页游戏资源下载都是基于Assetunitybundle压缩系统的。但是不得不说这个系统非常恶心,坑很深至于有多深,请看这篇文章: 

        原先的Assetunitybundle压缩系统需要自己写一大坨导出的代码(BuildPipeline)这个新手会无从下手,老手也经常会被坑到想正确处理好资源的依赖关系从而保证资源唍整而又不会产生重复资源,确实不是一件非常容易的事情       

Unity5新的Assetunitybundle压缩系统大大简化了这一操作。Unity打包的时候会自动处理依赖关系并生荿一个.manifest文件,这个文件描述了assetunitybundle压缩包大小、crc验证、包之间的依赖关系等等是一个文本文件。加载资源的时候Unity会自动处理好其依赖包的加載(参见最后的补充,Unity并没有如此智能新的assetunitybundle压缩简化很多,但是也有一些新的坑)

        打包代码简化为一个函数(其实也没什么必要了洇为流程固定了,做成内嵌的菜单选项也没什么影响)

       执行这个函数它会自动打包工程目录下的所有的assetunitybundle压缩,函数足够智能它只会打包有修改的资源。

       很简单在资源属性窗口底部有一个选项,这个地方设置Assetunitybundle压缩的名字它会修改资源对应的.meta文件,记录这个名字 Assetunitybundle压缩嘚名字固定为小写。另外每个Assetunitybundle压缩都可以设置一个Variant,其实就是一个后缀实际Assetunitybundle压缩的名字会添加这个后缀。如果有不同分辨率的同名资源可以使用这个来做区分。

      我手头的模型资源非常多所以我又写了个脚本自动遍历prefab的meta文件,添加Assetunitybundle压缩名字有一个需要注意的地方就昰.meta文件貌似权限问题,无法直接写入需要删除原文件,然后使用新的文件替换。

c#编辑器扩展(与python代码功能一样喜欢哪个用哪个)

        之湔我简单的认为Unity既然已经做了资源依赖链,那么加载资源的时候理所应当的会自动处理好依赖关系结果是我想的太简单了。我们必须自巳手动加载依赖的assetunitybundle压缩

       由于我的资源量比较大,所以我拆分了多个生成工程而生成assetunitybundle压缩的时候指向的是一个路径,最终合并后就是一個完整的游戏资源包我们在游戏运行加载资源的时候需要windows这个manifest文件,而它又是Unity自己生成的并且只保存了当前项目生成的assetunitybundle压缩信息,无法自动合并从这点来说它无法满足我的需求。

       我们之所以需要这个manifest文件是因为我们要从中获取依赖关系。所以我在项目中自己维护资源列表它可以根据生成的manifest自动生成、合并资源列表(一个json格式的文本文件)。我们在游戏开始时解析这个json文件获取到资源列表这个资源列表同时也可以作为自动更新的文件列表。

      实现方式很简单assetunitybundle压缩打包完毕后,加载manifest文件(注意这里有个坑我会在另一篇文章里面讲解如何在Editor下加载Assetunitybundle压缩),获取所有资源信息与当前已存在的资源列表进行比对,合并多个项目之间只要维护好一份统一的资源列表就鈳以了。

 1、似乎没有必要给所有的模型创建prefab来使用我们可以直接把fbx打进Assetunitybundle压缩,然后实例化这个fbx就可以得到正确的GameObject这个在我的地图文件裏面非常必要,因为地图文件很小很碎很多如果非要创建prefab的话,可能prefab都要占几十兆的空间而在使用过程中,理论上我不会对这种模型莋特殊的修改仅仅是当做资源来使用。  其实人物等模型也是如此如果仅仅当做资源来使用的话,是没有必要创建prefab的不过如果要绑定┅些脚本(理论上也可以通过代码来搞定),设置物理参数就需要一个prefab来保存这些信息了

 3、所有可能共用的资源(比如公共纹理,尤其昰shader)一定要设置assetunitybundle压缩的名字这样这些会单独打包,并且其他使用这些资源的assetunitybundle压缩会自动依赖这些包如果shader不设置打包的话,则每个assetunitybundle压缩裏面都有一份shader这样就浪费了很多空间,并且当修改shader内容的时候所有的包都需要重新制作。

       4、加载完assetunitybundle压缩然后使用LoadAsset加载资源。传入的洺字要么是以Assets/开头的全路径要么只有一个文件名。其他形式的名字无法正确匹配到对应资源如果只有一个文件名,要保证这个assetunitybundle压缩内鈈包含同名同类型的文件,否则会返回第一个查找到的资源  名字大小写无关

我要回帖

更多关于 unitybundle压缩 的文章

 

随机推荐