想问下AssetBundle的基本概念是什么?

2020-08-06 09:41发布

1

1

8条回答
小猪仔
2楼 · 2020-08-06 10:06

AssetBundle是Unity中的一个资源压缩包,它可以包括模型、纹理、预设、场景或者更新文件,它可以在运行的过程中被加载,目的就是减少我们打包后的包体积。

它是一个存在于硬盘上的文件。可以称之为压缩包。这个压缩包可以认为是一个文件夹,里面包含了多个文件。这些文件可以分为两类:serialized file 和 resource files。(序列化文件和源文件)


我是大脸猫
3楼 · 2020-08-06 10:31

AssetBundle系统提供了一种压缩文件的格式,可以把一个到多个文件进行索引和序列化。

Unity项目在交付安装之后,会通过AssetBundle对不包含代码的资源进行更新。这就允许开发人员先提交一个小的应用程序包,将运行时内存压力降到最低,并有选择地加载针对不同终端用户设备优化后的内容。

3.1 AssetBundle结构

总的来说,AssetBundle就像传统的压缩包一样,由两个部分组成:包头和数据段。

包头包含有关AssetBundle的信息,比如标识符、压缩类型和内容清单。清单是一个以Objects name为键的查找表。每个条目都提供一个字节索引,用来指示该Objects在AssetBundle数据段的位置。在大多数平台上,这个查找表是用平衡搜索树实现的。具体来说,Windows和OSX派生平台(包括iOS)都采用了红黑树。因此,构建清单所需的时间会随着AssetBundle中Assets的数量增加而线性增加。

数据段包含通过序列化AssetBundle中的Assets而生成的原始数据。如果指定LZMA为压缩方案,则对所有序列化Assets后的完整字节数组进行压缩。如果指定了LZ4,则单独压缩单独Assets的字节。如果不使用压缩,数据段将保持为原始字节流。

在Unity 5.3之前,是无法对AssetBundle中单独Objects进行压缩的。因此,如果在5.3之前的Unity版本被要求从压缩的AssetBundle中读取一个或多个对象时,Unity必须解压整个AssetBundle。通常,Unity会缓存AssetBundle的解压缩副本,以提高在相同AssetBundle上的后续加载请求的加载性能。

3.2 加载AssetBundles

AssetBundles可以通过四个不同的API进行加载。但受限于两个标准,这四个API的行为是不同的。两个标准如下:

  • AssetBundles的压缩方式:LZMA、LZ4、还是未压缩的。

  • AssetBundles的加载平台。

而四个API分别是:

  • AssetBundle.LoadFromMemory(Async optional)

  • AssetBundle.LoadFromFile(Async optional)

  • UnityWebRequest's DownloadHandlerAssetBundle

  • WWW.LoadFromCacheOrDownload (on Unity 5.6 or older)

下面来详细讲一下4个API的区别。

3.2.1 AssetBundle.LoadFromMemory(Async)
Unity的建议是——不要使用这个API

LoadFromMemory(Async) 是从托管代码的字节数组里加载AssetBundle。也就是说你要提前用其它的方式将资源的二进制数组加入到内存中。然后该接口会将源数据从托管代码字节数组复制到新分配的、连续的本机内存块中。

但如果AssetBundle使用了LZMA压缩类型,它将在复制时解压AssetBundle。而未压缩和LZ4压缩类型的AssetBundle将逐字节的完整复制。

之所以不建议使用该API是因为,此API消耗的最大内存量将至少是AssetBundle的两倍:本机内存中的一个副本,和LoadFromMemory(Async)从托管字节数组中复制的一个副本。

因此,从通过此API创建的AssetBundle加载的资产将在内存中冗余三次:一次在托管代码字节数组中,一次在AssetBundle的栈内存副本中,第三次在GPU或系统内存中,用于Asset本身。

注意:在Unity 5.3.3之前,这个API被称为AssetBundle.CreateFromMemory。但功能没有改变。

3.2.2 AssetBundle.LoadFromFile(Async)
LoadFromFile是一种高效的API,用于从本地存储(如硬盘或SD卡)加载未压缩或LZ4压缩格式的AssetBundle。

在桌面独立平台、控制台和移动平台上,API将只加载AssetBundle的头部,并将剩余的数据留在磁盘上。

AssetBundle的Objects会按需加载,比如:加载方法(例如:AssetBundle.Load)被调用或其InstanceID被间接引用的时候。在这种情况下,不会消耗过多的内存。

但在Editor环境下,API还是会把整个AssetBundle加载到内存中,就像读取磁盘上的字节和使用AssetBundle.LoadFromMemoryAsync一样。

如果在Editor中对项目进行了分析,此API可能会导致在AssetBundle加载期间出现内存尖峰。但这不应影响设备上的性能,在做优化之前,这些尖峰应该在设备上重新再测试一遍。

要注意,这个API只针对未压缩或LZ4压缩格式,因为前面说过了,如果使用LZMA压缩,它是针对整个生成后的数据包进行压缩的,所以在未解压之前是无法拿到AssetBundle的头信息的。

注意:这里曾经有过一个历史遗留问题,即在Unity 5.3或更老版本的Android设备上,当试图从Streaming Assets路径加载AssetBundles时,此API将失败。这个问题已在Unity 5.4中解决。

在Unity 5.3之前,这个API被称为AssetBundle.CreateFromFile。其功能没有改变。

3.2.3 AssetBundleDownloadHandler
DownloadHandlerAssetBundle的操作是通过UnityWebRequest的API来完成的。

UnityWebRequest API允许开发人员精确地指定Unity应如何处理下载的数据,并允许开发人员消除不必要的内存使用。使用UnityWebRequest下载AssetBundle的最简单方法是调用UnityWebRequest.GetAssetBundle。

就实战项目而言,最有意思的类是DownloadHandlerAssetBundle。它使用工作线程,将下载的数据流存储到一个固定大小的缓冲区中,然后根据下载处理程序的配置方式将缓冲数据放到临时存储或AssetBundle缓存中。

所有这些操作都发生在非托管代码中,消除了增加堆内存的风险。此外,该下载处理程序并不会保留所有下载字节的栈内存副本,从而进一步减少了下载AssetBundle的内存开销。

LZMA压缩的AssetBundles将在下载和缓存的时候更改为LZ4压缩。这个可以通过设置Caching.CompressionEnable属性来更改。

如果将缓存信息提供给UnityWebRequest对象,一旦有请求的AssetBundle已经存在于Unity的缓存中,那么AssetBundle将立即可用,并且此API的行为将会与AssetBundle.LoadFromFile相同操作。

在Unity 5.6之前,UnityWebRequest系统使用了一个固定的工作线程池和一个内部作业系统来防止过多的并发下载,并且线程池的大小是不可配置的。在Unity 5.6中,这些安全措施已经被删除,以便适应更现代化的硬件,并允许更快地访问HTTP响应代码和报头。

3.2.4 WWW.LoadFromCacheOrDownload
这是一个很古老的API了,从Unity 2017.1开始,就只是简单地包装了UnityWebRequest。因此,使用Unity 2017.1或更高版本的开发者应该直接使用UnityWebRequest来工作。Unity已经放弃了对改接口的维护,并可能在未来的某个版本中移除。

所以下面说的这些内容只适合于Unity 5.6或更老的版本。

WWW.LoadFromCacheOrDownload允许从远程服务器和本地存储加载对象。也可以通过文件//URL从本地存储加载文件。如果AssetBundle存在于Unity Cache中,则此API的行为将与AssetBundle.LoadFromFile完全相同。

如果AssetBundle尚未缓存,则WWW.LoadFromCacheOrDownload会将从它的源文件读取AssetBundle。如果AssetBundle被压缩过,它会使用工作线程进行解压缩并写入缓存中。否则,它将通过工作线程直接写入缓存。

在缓存AssetBundle之后,WWW.LoadFromCacheOrDownload将从缓存的、解压缩的AssetBundle加载头信息。然后,和AssetBundle.LoadFromFile加载AssetBundle行为相同。

此缓存会在WWW.LoadFromCacheOrDownload和UnityWebRequest之间共享。一个API下载的任何AssetBundle也可以通过另一个API获得。

虽然数据将通过固定大小的缓冲区解压缩并写入缓存,但WWW对象会在本机内存中保留AssetBundle字节的完整副本。这个额外副本被保留的原因是因为要支持WWW.bytes字节属性。

由于在WWW对象中缓存AssetBundle的字节的内存开销,所以,实际项目开发中AssetBundles应该要保持较少的体积以便减少内存。

与UnityWebRequest不同的是,每次调用这个API都会产生一个新的工作线程。因此,在手机等内存有限的平台上,最好限定一次只能下载一个AssetBundle,以避免内存激增。而在其它平台也要小心创建过多的线程。如果需要下载5个以上的AssetBundles,建议在脚本代码中创建和管理下载队列,以确保只有少数几个AssetBundle同时下载。

3.2.5 建议
(1)一般来说,只要有可能,就应该使用AssetBundle.LoadFromFile。这个API在速度、磁盘使用和运行时内存使用方面是最有效的。

(2)对于必须下载或热更新AssetBundles的项目,强烈建议对使用Unity 5.3或更高版本的项目使用UnityWebRequest,对于使用Unity 5.2或更老版本的项目使用WWW.LoadFromCacheOrDownload。

(3)当使用UnityWebRequest或WWW.LoadFromCacheOrDownload时,要确保下载程序代码在加载AssetBundle后正确地调用Dispose。另外,C#的using语句是确保WWW或UnityWebRequest被安全处理的最方便的方法。

(4)对于需要独特的、特定的缓存或下载需求的大项目,可以考虑使用自定义的下载器。编写自定义下载程序是一项重要并且复杂的任务,任何自定义的下载程序都应该与AssetBundle.LoadFromFile保持兼容。

3.3 从AssetBundles中加载Assets

到这里,我们已经能够获得AssetBundles了,那么接下来就是要从AssetBundles里获取Assets。

Unity提供了三个不同的API从AssetBundles加载UnityEngine.Objects,这些API都绑定到AssetBundle对象上,并且这些API具有同步和异步变体:

  • LoadAsset (LoadAssetAsync)

  • LoadAllAssets (LoadAllAssetsAsync)

  • LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)

并且这些API的同步版本总是比异步版本快至少一个帧(其实是因为异步版本为了确保异步,都至少延迟了1帧),异步加载每帧会加载多个对象,直到它们的时间切片切出。

加载多个独立的UnityEngine.Objects时应使用LoadAllAsset。并且只有在需要加载AssetBundle中的大多数或所有对象时,才应该使用它。与其它两个API相比,LoadAllAsset比对LoadAsset的多个单独调用略快一些。因此,如果要加载的Asset数量很大,但如果需要一次性加载不到三分之二的AssetBundle,则要考虑将AssetBundle拆分为多个较小的包,再使用LoadAllAsset。

加载包含多个嵌入式对象的复合Asset时,应使用LoadAssetWithSubAsset,例如嵌入动画的FBX模型或嵌入多个精灵的sprite图集。也就是说,如果需要加载的对象都来自同一Asset,但与许多其它无关对象一起存储在AssetBundle中,则使用此API。

任何其它情况,请使用LoadAsset或LoadAssetAsync。

3.3.1 低层级的加载细节
Object加载是在主线程上执行,但数据从工作线程上的存储中读取。任何不触碰Unity系统中线程敏感部分(脚本、图形)的工作都将在工作线程上转换。例如,VBO将从网格创建,纹理将被解压等等。

从Unity 5.3开始,Object加载就被并行化了。在工作线程上反序列化、处理和集成多个Object。当一个Object完成加载时,它的Awake回调将被调用,该对象的其余部分将在下一个帧中对UnityEngine可用。

同步AssetBundle.Load方法将暂停主线程,直到Object加载完成。但它们也会加载时间切片的Object,以便Object集成不会占用太多的毫秒帧时间。应用程序属性设置毫秒数的属性为Application.backgroundLoadingPriority。
ThreadPriority.High:每帧最多50毫秒
ThreadPriority.Normal:每帧最多10毫秒
ThreadPriority.BelowNormal:每帧最多4毫秒
ThreadPriority.Low:每帧最多2毫秒

从Unity 5.2开始,加载多个对象的时候,会一直进行直到达到对象加载的帧时间限制为止。假设所有其它因素相等,Asset加载API的异步变体将总是比同步版本花费更长的时间,因为发出异步调用和对象之间有最小的一帧延迟。

3.3.2 AssetBundle依赖项
根据运行时环境的不同,使用两个不同的API自动跟踪AssetBundles之间的依赖关系。在UnityEditor中,可以通过AssetDatabaseAPI查询AssetBundle依赖项。AssetBundles分配和依赖项可以通过AssetImportAPI访问和更改。在运行时,Unity提供了一个可选的API,通过基于ScriptableObject的AssetBundleManifest API加载在AssetBundle构建过程中生成的依赖信息。

当一个或多个AssetBundle的UnityEngine.Objects引用了一个或者多个其它AssetBundle的UnityEngine.Objects,那么这个AssetBundle就会依赖于另外的AssetBundle。AssetBundles充当由它包含的每个对象的FileGUID和LocalID标识的源数据。

因为一个对象是在其Instance ID第一次被间接引用时加载的,而且由于一个对象在加载其AssetBundle时被分配了一个有效的Instance ID,所以加载AssetBundles的顺序并不重要。相反,在加载对象本身之前,重要的是加载包含对象依赖关系的所有AssetBundles。Unity不会尝试在加载父AssetBundle时自动加载任何子AssetBundle。

示例:
假设Material A引用Texture B。Material A被打包到AssetBundle1中,Texture B被打包到AssetBundle2中:

在本用例中,AssetBundle2必须在Material A从AssetBundle1中加载之前先加载。这并不意味着AssetBundle 2必须在AssetBundle 1之前加载,或者Texture B必须从AssetBundle 2中显式加载。在将Material A从AssetBundle 1加载之前加载AssetBundle 2就足够了。

简单来说就是AssetBundle之间的加载没有先后,但是Asset的加载有。

有关AssetBundle依赖项的详细信息,请参阅手册页。

3.3.3 AssetBundle manifests
当使用BuildPiine.BuildAssetBundles API执行AssetBundle构建管线时,Unity会序列化一个包含每个AssetBundle依赖项信息的对象。此数据存储在单独的AssetBundle中,其中包含AssetBundleManifest类型的单个对象。

此Asset将存储在与构建AssetBundles的父目录同名的AssetBundle中。如果一个项目将其AssetBundles构建到位于(Projectroot)/Build/Client/的文件夹中,那么包含清单的AssetBundle将被保存为(Projectroot)/build/client/Client.manifest。

包含Manifest的AssetBundle可以像任何其它AssetBundle一样加载、缓存和卸载。

AssetBundleManifest对象本身提供GetAllAssetBundles API来列出与清单同时构建的所有AssetBundles,以及查询特定AssetBundle的依赖项的两个方法:

  • AssetBundleManifest.GetAllDependencies返回AssetBundle的所有层次依赖项,其中包括AssetBundle的直接子级、其子级的依赖项等。

  • AssetBundleManifest.GetDirectDependations只返回AssetBundle的直接子级

请注意,这两个API分配的都是字符串数组。因此,最好是在性能要求不敏感的时候使用。

3.3.4 建议
在多数情况下,最好在玩家进入应用程序的性能关键区域(如主游戏关卡或世界)之前加载尽可能多的所需对象。这在移动平台上尤为重要,因为在移动平台上,访问本地存储的速度很慢,并且在运行时加载和卸载对象会触发垃圾回收。


梅向南
4楼 · 2020-08-07 13:39

主要是游戏中的打包机制,由于把所有的资源都放到安装包中输出会造成安装包过大的问题,所以就会将一些模型,图片,贴图等等打成AB包放到服务器,当游戏安装完毕之后再从服务器下载相应的资源。

蜗牛
5楼 · 2020-08-10 09:35

AssetBundle是Unity中的一个资源压缩包,它可以包括模型、纹理、预设、场景或者更新文件,它可以在运行的过程中被加载,目的就是减少我们打包后的包体积。打包之后放到服务器上,游戏安装完毕之后,大的场景或者其他资源从服务器上下载

Transform
6楼 · 2020-08-12 11:02

AssetBundle是Unity中的一种资源包,这种资源包可以是游戏内要用到的几乎所有资源,例如:模型、纹理、预设、场景等大部分文件更新,并且可以在运行时动态加载。

值得注意的是AssetBundle是可以多个文件一起打包,例如将要打包的资源做成预设后再进行打包,这样可以将预设上面附带的组件、纹理、子对象等一并打包,加载后直接实例化就能直接使用了(并不是建议大家这么做,因为涉及的纹理材质可能会造成资源冗余)。


男孩无衣
7楼 · 2020-08-13 18:04

Assetbundle就是一个压缩文件。 


试想, 如果你要给qq好友发100个文件,直接发100次接受起来多么麻烦,而且顺序和名称也容易乱。 

所以你会把100个文件打包一下,压缩成一个.zip或者.gz文件。 再发送时, 就是一个文件啦,而且还压缩了。 


AssetBundle和zip文件一样,也是一种压缩格式,我们把需要更新的资源,打包压缩成.assetbundle格式的压缩包,发送到手机客户端里,然后客户端解压出来模型、代码等资源, 就也可以做更新啦。 


这种在程序运行时,动态更新资源的方法,我们叫做“热更新”。


Unity中做热更新时使用的压缩方法就是Assetbundle。

老杜
8楼 · 2020-08-14 09:02

AssetBundle其实就是unity资源的压缩包。

AssetBundle是将资源用Unity提供的一种用于存储资源的压缩格式打包后的集合。他可以存储任意一种Unity引擎可以识别的资源,如模型,纹理图,音频,动画甚至场景等。此外AssetBundle也可以打包开发者自定义的二进制文件。

UnityAssetBundle系统是对资源管理的一种扩展,可以动态的加载和卸载,并且大大节约了游戏所占的空间。

AssetBundle的操作可分为:

1. 创建AssetBundle(打包),开发者在Unity编辑器中通过脚本来将所需的资源打包AssetBundle文件。

2. 加载AssetBundle(拆包),客户端可以通过Unity提供的API读取Assets目录下的资源包,并加载资源包里所包含的模型,纹理包,音频,动画,场景等游戏资源在游戏中使用。

3. 卸载AssetBundle。在Unity中也提供了相应的API来卸载AssetBundle资源包,卸载AssetBundle可以节约内存资产。


相关问题推荐

  • 回答 5

    第一种方法:通过点击场景文件打开Unity游戏工程找到Unity游戏工程所在的目录,我这里的工程放在在E盘根路径的Unity_workspace文件夹中。注意:unity软件不支持中文路径,所以不要把工程放在中文文件夹下。我们在这里就打开New Unity Project 4工程,进入到Ne...

  • 回答 9

    unity3D是实时3D互动内容创作和运营平台。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助Unity将创意变成现实。Unity平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC...

  • 回答 13
    已采纳

    如果是学习研究的话,当然是体验官方的最新版本。要是项目开发的话,还是要选择长期稳定版本,也就是大版本的LTS。比如2017.4或者是2018.4都是LTS版本,至于后面的小版本可以去看下更新的内容来做选择吧!...

  • 回答 11

    1、Unity3D:如果你需要开发大型游戏,或需要开发3D游戏的,请选这个。2、Cocos2D-x:如果你开发的是中小型游戏,对安装包大小比较在意的,请选这个。3、Andengine、Cocos2D-iPhone:如果你只为开发单平台游戏,又非常在意速度和安装包大小,请选这个。最后。...

  • 回答 11

    首先在场景中调整好你要观看的视角选择摄像机,按下Ctrl+Shift+F或者菜单栏->GameObject->Align with view在不行的话,可以调整摄像机的Position 和 Rotation

  • 回答 5

    将MeshRender组件移除即可:

  • 回答 9

    1.在Asset store里选择一个skybox。 2.从素材库中选择一个人物角色,也可以自己建模或者在其他软件中做好再导进来。 3.想好角色如何运动,然后用自己比较熟悉的语言编写来作展示,这段代码可以实现当你按下键盘上的A/D/S/W的按键时,角色会向前后左右四个方向的...

  • 回答 17

    还是要学好编程基础呀如果你觉得编程很苦难 不一定要从c#开始学  学学js flash as等等  有个梯度就好多了如果要用好unity  不会编程那是不行的  学习的过程中都有个头疼的过程  记住  头越痛  代表你要接受的东西越多  坚持 你的大脑在和知识兼容中:D...

  • 回答 4

    xcel 表的操作少不了要引入第三方库,首先我们需要引入 Excel.dll 和 ICSharpCode.SharpZipLib.dll,这两个类库在网上都能找到;然后我们还需要引入 System.Data.dll,这个类库在 Unity3D 的安装路径下的 Editor\Data\Mono\lib\mono\unity 文件夹下能找到...

  • 回答 1

    需要添加如下引用: System.Configuration System.Data System.EnterpriseServices System.Security System.XML using UnityEngine; using System.Collections; using System;  using  System.Data;  using System.Data...

  • 物理引擎问题2021-06-15 17:35
    回答 4

    物理引擎则使用动量、扭矩等用高等数学手段来模拟真实物体,这将得到更真实的效果且使我们的编码更加容易。

  • 回答 1

    不能这样表述,三维通常是立体的空间,二维则是平面的。数学中通常是Oxyz表示空间直角坐标系,Oxy表示表示的是平面直角坐标系,你可以说空间直角坐标系中去掉Z轴可以转换为二维,因为去掉X或Y轴都能转换为二维。...

  • 回答 2

    GameObject.renderer.enabled//是控制一个物体是否在屏幕上渲染或显示 而物体实际还是存在的 只是想当于隐身 而物体本身的碰撞体还依然存在的GameObject.Destroy()//表示移除物体或物体上的组件 代表销毁该物体 实际上该物体的内存并没有立即释放,而是等到这...

  • Canvas三种渲染模式2021-04-29 19:50
    回答 10

    一:Overlay—覆盖模式类似于手机贴膜,所有UI都会显示在场景中2D,3D物体的上层在同一个Canvas下可以调整Canvas子物体的先后顺序,层级面板中越靠上则先被渲染多个Canvas下可以调整Canvas组件的Sort Order属性调整渲染顺序,数值越小的画布越先被渲染:Camer...

  • Unity引擎2021-04-29 19:47
    回答 4

    不得不说,Unity3d是个解放生产力的游戏引擎,自带了各种编辑器,可以进行一系列的可视化操作。需要注意的是,unity3d适合FPS游戏,物理游戏等中小型的游戏,并不太适合MMO开发。unity3d难学吗?如何学习unity3d呢?在学习之前又应该了解哪些内容呢?代码写不...

  • 回答 3

    不是人工检查的,如果你的问题里面有敏感关键字,是发不出去的,现在国内所有的网站在发布文章时都要进行检查的,所以你在发之前先检查一下看问题里面是否有违禁词语。

没有解决我的问题,去提问