Unity AssetBundle笔记

1.入门:

Resources:表示U3D自动将资源打成一个AssetBundle包,全部放在Resources下的文件夹都会打成一个AssetBundle包,资源很是大,Resources文件夹在真机上最大只有2G的内存(专业版会增大内存)html

AssetBundle包:其实能够当作一个压缩包(有固定格式的),默认状况下使用LZMA压缩方式压缩的资源文件;和压缩ZIP同样的,只不过里面的格式变了算法

   Unity3D引擎为咱们提供了三种压缩策略来处理AssetBundle的压缩,即:json

    一、LZMA格式:服务器

        在默认状况下,打包生成的AssetBundle都会被压缩。在U3D中,AssetBundle的标准压缩格式即是LZMA(LZMA是一种序列化流文件),所以在默认状况下,打出的AssetBundle包处于LZMA格式的压缩状态,在使用AssetBundle前须要先解压缩。使用LZMA格式压缩的AssetBundle的包体积最小(高压缩比),可是会相应的增长解压缩的时间网络

    二、LZ4格式:异步

        Unity5.3以后的版本增长了LZ4格式压缩,因为LZ4的压缩比通常,所以通过压缩后的AssetBundle包体的体积较大(该算法基于chunk)。函数

    三、不压缩工具

Resources和AssetBundle的区别:性能

  一、Resources:有2G的限制,不支持动态更新(拿Android为例)测试

    a、上线后,Resources里面的资源都在APK里面,只能读不能写

    b、StreamingAssets和dataPath都是在Apk中,Apk为一个压缩包,里面的东西只能读不能写,所以这个限制就决定了Resources不能支持热更新

  二、PersistPath(支持热更):

    a、只能手动打包

    b、打包方式:

      一、4.0之前,打包的依赖关系都必须手动

      二、5.0之后,这种依赖关系所有自动

建立AssetBundle:AssetBundle能够将任何资源打包成assetbundle(若是是unity不能识别的文件,能够经过改变后缀进行打包)

  一、在任何一个游戏物体的右下角有AssetBundle,第一个为包名,第二个为后缀(不能识别的物体不能修改,修改后缀变成能识别的物体)

更新流程:

  一、代码的更新:热更新

  二、资源的更新:AssetBundle更新

    a、建立assetbundle

    b、将assetbundle打成一个zip文件,放进streamingAssetPath里面

    c、把须要更新的AssetBundle先上传到Server,若是Server有更新(与服务器版本进行比对),把server的assetbundle包下载下来(zip文件),而后解压到persistentPath里

    d:加载:判断PersistentPath里是否有这个资源,若是没有就读取StreamingAssetPath里面的,若是有,就直接读取PersistentPath里的

        一、LoadAsset:从资源包中加载指定的资源

        二、LoadAllAsset:加载当前资源包中因此的资源

        三、LoadAssetAsync:从资源包中异步加载资源

  三、资源卸载:资源卸载部分使用的是Unload方法

     Unload:

        a、该方法会卸载运行时内存中包含在bundle中的全部资源。

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

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

    

BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.AppendHashToAssetBundleName|BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);

  

  AssetBundle的适用平台与跨平台性

    AssetBundle适用于多种平台,包括网页应用、移动应用、桌面应用等,能够动态更新,但不一样平台所使用的AssetBundle并不相同,在建立离线AssetBundle的时候须要经过参数来指定目标平台,相关关系如表所示:

    

     IOS:在Mac版本的Standlone打包

    Windows:打Android、PC、WebPlayer

 

BuildPipeline.BuildAssetBundles():
  一、第一个参数:AssetBundle输出到哪个文件夹
  二、第二个参数:枚举类型,能够选择多个参数,多个参数之间能够用“|“隔开
    a、CompleteAssets:保证资源的完备性,默认开启
    b、CollectDependencies:用于搜集资源的依赖项,默认开启
      和完整性有点相像,会把游戏物体所依赖的资源一块儿进行打包,防止有些被依赖的资源没有被打进去
    c、DeterministicAssetBundle:用于为资源维护固定ID,默认开启
      因此的资源都有固定的标记的,在资源的mate文件中的guid:64位组成的字符串,电脑里是随机生成而且惟一,每个文件的惟一标识
    d、ForceRebuildAssetBundle:用于强制重打全部AssetBundle文件,5.3之后新增
      资源更新了,从新打包,将之前的资源包丢弃
    e、IgnoreTypeTreeChanges:用于判断AssetBundle更新时,是否忽略TypeTree的变化,新增
      打包时是否忽略父子关系
    f、AppendHashToAssetBundleName:用于将Hash值添加在AssetBundle文件名以后,开启这个选项能够直接经过文件名来判断哪些Bundle的内容进行了更新
      (4.X下广泛须要经过比较二进制等方法来判断,但在某些状况下即便内容不变从新打包,Bundle的二进制也会变化),新增
      在包名后缀名后面添加一个Hash表
    g:ChunkBasedCompression:用于使用LZ4格式进行压缩,5.3新增
 
 

1、如何组织assetBundle:

unity5之前,打包须要本身去找依赖,而后须要按照拓扑图顺序压入AB栈,这样在最后打AB时才能有效利用依赖(栈内已有的AB才能做为依赖)。

unity5.x后,打包变得简单,但如何组织assetBundle依然须要琢磨和规划。
  首先咱们须要知道:AB、asset和资源的关系:一个AB包括1个或多个asset,一个asset可能没有依赖其余asset(即包括了其须要的全部资源),也可能依赖其余asset(包括一些资源和指向其余asset所在AB的引用)。
  其次,使用asset和AB:要使用一个asset,须要先加载该asset的全部依赖的asset(迭代下去,把全部相关的AB都加载出来),而后加载本身的AB,最后取出asset来使用。
  因此,要使用一个asset,都须要加载全部相关的AssetBundle镜像进入内存。这就须要咱们要研究打ab的方案了。而且打ab的方式也影响ab的总大小,即便在Unity5下。
  文档提供了3种打ab方案:
    1.逻辑实体分类法,即根据功能模块分类,(大致上意思是不一样功能不一样ab,这样就能够开一个功能下载一个ab)好比先大层次分:UI模块,角色模块,场景模块等,
     UI模块又根据具体功能模块分:好比各个副本的UI是不一样的,那每一个副本的UI能够打成单独ab;
     角色模块则是每一个角色包括其依赖的东西,如mesh,model,animation,texture等打成一个AB;
     场景模块能够一个场景分红多个片,每一个片至关于一个“子模块”,单独成ab,多个场景共享片。
    2.根据资源类型打ab:好比音效打成一个ab,国际化文本打成1个ab等,文档说这种方法是打多平台ab的一种好方法,好比音效ab在各个平台下都同样则能够复用,而shader平台区分则不能复用
     而且在此方法下,由于原始资源(好比Texture)不多改动,因此利于版本更新(增量少)。这种方法我也不是很理解,感受就是把ab粒度细化到原始资源层次(纹理,音效,网格等),他们有的在不一样平台保持同样,有的平台区分,但基本不会发生改变。
    3.根据“同时加载”来打ab,即把须要同时加载的资源打入同一个ab.好比每一个场景包括其依赖的全部东西打成一个AB。
  不管使用什么方案(通常是都使用一点点,好比第3种用来打场景,第1种用来打各个系统(即功能)的资源,等),为了减小AB大小,增量AB大小,加载时间和运行时内存消耗,都须要注意下面细节:
    1.频繁变更的asset不该该和稳定的asset打入一个AssetBundle;小增量AB
    2.若是稳定的大/多asset中含有频繁变更的资源,应该把资源单独打AB;小增量AB
    3.使用时通常同时加载的东西如Model和它的texture,material,animation等应该打入一个AssetBundle中,因此角色通常每一个一个AB;减小加载时间
    4.若是多个AB都依赖某个asset或资源,应该把该asset或资源单独打AB;小AB,省内存
    5.若是2个asset极少同时加载,那应该分开打AB;省内存
    6.把常常同时加载的小asset的AB合并成大AB;减小加载时间

 

2、打AB的参数选择和加载AB的方案:

  1.清单:

    1)打AB时,每一个AB都会额外带一个.manifest文件,用来描述该AB相关信息,包括
      CRC码,(file hash)a single hash for all assets in AB,(type tree hash)a single hash for all types in AB,(class types)all class types in AB,(asset names)all asset paths in AB.
      此文件只用于生成增量AB, not necessary for runtime,因此不须要打入安装包,依赖关系能够在2)那里统一查找。
    2)而且在打AB的输入参数中的“输出文件夹”那里生成一个.manifest文件,里面包括全部AB路径及其依赖,这个在运行时加载资源时使用,由于加载资源需先加载依赖。

  2.AB的压缩方式

  AB有3种压缩方式(固然你也能够自定义压缩算法,不过不必),一种是无压缩UncompressedAssetBundle,一种是块压缩LZ4(ChunkBasedCompression),一种是最大压缩LZMA(None)
加载时无压缩最快,其次是块压缩(只须要解压AB的一部分就能加载,与无压缩具备可比性),最后是LZMA(须要彻底解压AB),固然打出的AB大小就反过来了(LZMA:50-60%,LZ4:70%)。
通常本地AB建议以LZ4格式存储,较小且快,须要网络下载的用LZMA并使用LoadFromCacheOrDownload对其加载,这样到了本地就变成LZ4了(LoadFromCacheOrDownload在接受数据流时就直接解压,无额外耗时)。

  3.AB加载的几个接口

    1)加载AB文件(这里是指build出来后的AB文件,若是build后还进行加密等则不能直接加载)有几种方式:
    WWW:输入URL,AB在www.assetBundle里;PS:若是ab在本地,url用file:///前缀
    WWW.LoadFromCacheOrDownload:输入URL,AB在www.assetBundle里;PS:若是ab在本地,url用file:///前缀
    LoadFromMemory(Async):输入是bytes[],返回的就是AB;PS:bytes的获取通常用WWW,也能够直接File.ReadAllBytes,反正得到文件的字节流便可。
    LoadFromFile(Async):输入是path,AB在AssetBundleCreateRequest.assetBundle里;

    UnityWebRequest:文档说此方法比WWW好,用法也相似,但由于WWW比较成熟,并且WWW咱们基本只是用来加载本地bytes资源,并且此方法在5.4之后版本才有,咱们没有使用。
在网络资源下载方面咱们项目用的是C#提供的HttpWebRequest
    2)加载非.assetBundle文件例如.bytes,.jpg,.png,.txt,.ogg,.mp3等文件通常使用WWW加载:
    WWW.bytes,WWW.texture,WWW.text,WWW.audioClip里分别存加载后的数据。

    若是原先是.assetBundle,加密成.bytes,先www加出bytes,而后loadfrommemory;

    若是原先是.bytes或者其余自定义数据类型,如xml,json等,打ab成.assetBundle,则先加出assetBundle,而后加载出Asset,最后强转为TextAsset类型,而后你的数据就能够从中取出来了,Unity常常把这些数据当作TextAsset类型;

    简而言之,对特殊文件格式,咱们使用以前先测试一下其加载方式,基本在WWW和TextAsset这块考虑,看数据在它们哪一个变量里,一测便知。

  4.针对2和3介绍的多种方式,按状况选择压缩方式+加载接口

  文档根据各个函数对内存和CPU消耗的特色作出如下建议:
  1.对于安装包内的AB,尽可能用LoadFromFile(Async)+ChunkBasedCompression,由于它和ChunkBasedCompression配合起来很快(能够压缩30%+并且加载时不须要额外解压),若是AB的压缩格式是LZMA(即Option=None),LoadFromFile(Async)须要额外解压和重压缩(压为LZ4);
  2.对于网络资源,尽可能用WWW.LoadFromCacheOrDownload,而且资源尽可能用默认的LZMA压缩法,由于这样能够省流量,而且此函数在接收网络流时就对流进行解压,为LZ4(即AB压不压对其无区别),而加载LZ4不须要额外解压。
  3.对于加密的AB,须要用WWW把文件加载成bytes,而后解密,而后用LoadFromMemory[Async]加载出AB(这个大概是LoadFromMemory[Async]使用的惟一场景了)
  4.若是使用自定义压缩算法,选UncompressedAssetBundle不压缩来build AB,而后加载时先对数据解压,而后LoadFromFile(Async)
  总结:本人当前项目是用LZMA build AB(不使用LZ4的缘由多是没深刻了解,也多是贪图LZMA的小包体,也多是加载的多半是小ab,LZMA解压再压LZ4的消耗能够忍受),用LoadFromFile(Async)加载.assetbundle,WWW+LoadFromMemory(Async)加载加密过的ab.bytes,用WWW加载原始图片。

 

3、若是管理AssetBundle

  1.AssetBundle.unload(true/false)的用法:
  true会把AB,由AB加出来的Asset,由Asset实例化出来的GameObj(也可能只是指向Asset的引用)都销毁,内存一干二净;
  false只是把AB卸载,官方文档描述为把AB和Asset,Gobj的link断开,即后者们本身删除本身,若是再次加载Asset则是新的Asset,与原来的Asset独立共存于内存;
  这里须要明确两点:
  1.AssetBundle加载出来后没有Unload则其镜像一直在内存,再次加载会报错,能够unload掉从新加载或者hold住它,不从新加载;
  2.false时要卸掉Asset须要把由它实例化出来的Gobj都销毁(引用则置空),而后Resource.unloadunusedassets卸载,Gobj则destroy便可;
  官方文档建议选择true,true调用的时机能够是切地图或者Asset引用为0时,若是选择false,那Asset只有在2的状况下才能卸掉。
  但官方文档没说的一点是在调用unload(true)前若是再次加载应该怎么办。
    1.其实只需在上层存个Pool便可,Pool里的元素对应一个AssetBundle,加载AB时先看Pool里有没有,有则直接使用它来GetAsset和实例化,并把引用+1,当实例化的东西Destroy时把该AB的引用减一,当引用变为0时unload(true)便可。
    2.但这种方式主要用来处理实例化的GameObject资源,对某些资源好比AudioClip,Text,场景,自定义数据等通常不多频繁加载,这样咱们在加载AB出来后直接unload(false),而后当它不使用时,对应的Asset引用就空了,就能够在UnloadUnusedAsset时卸载(切场景时默认调用一次,通常在程序中定时调用一次)
    3.官方文档之因此建议使用unload(true),是想避免内存存多份Asset和Asset不能及时卸载,若是资源是不多加载如2中那些,用unload(false)较好,至于unloadunsedAsset的调用能够在该资源使用完后手动调用一下(当资源消耗时刻明确时),也能够交给游戏卸载系统(定时调用unloadunusedasset)或切场景。

  个人一种方案:

  A.对不频繁加载的资源(大部分都是),咱们加载完后就unload(false),这样能够迅速释放内存镜像,而当加载出来的资源再也不被使用(引用为空)时,Asset就能被识别为unsedassets而被卸载;

  B.对频繁加载的资源(小部分),咱们在上层弄一个pool,里面存着stringtoasset的字典,字典里只存asset,即即便是频繁加载的资源咱们也要在加载出asset后用unload(false)把内存镜像卸载掉,只保留加载出来的资源以便实例化/引用,这里咱们须要搞个引用计数,由于字典里永远引用着该资源,当引用计数为0时咱们须要从字典中删除。

  在A,B的指导下+定时调用Resources.UnLoadUnUsedAssets,GC.Collect应该能保持内存的尽可能干净了。那哪些资源是频繁加载哪些是不频繁加载,标准是咋样的呢?这个须要具体测试获得相关标准和性能的关系才能作决定,和游戏逻辑有关,和资源有关,和体验有关,须要写工具来肯定。
  总结:AssetBundle的管理主要抓住几个接口便可AssetBundle.unload(true/false),Resources.UnLoadUnUsedAssets,GC.Collect,Destroy,但要真正了解他们,须要深刻理解Unity对AssetBundle,Asset,资源等的内存管理机制,能够参考这篇文章:    

  http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html

 

4、Ps(存疑与补充)

  AssetBundle Variant:ab变种,通常用于解决“多态性”问题,好比资源有hd,ld,图片要适应各类设备须要不一样压缩格式等,有空能够研究一下。

相关文章
相关标签/搜索