[AssetBundles]Unity 5.2 AssetBundle 和 AssetBundle Manager 使用实践

vrman

vrman

发表于 2017-05-03 14:46:11

 Asset Bundle 和 Asset Bundle Manager (1)

介绍

AssetBundles 允许从本地或者服务器按需指定和加载资源(Assets)。通过 AssetBundles 技术,资源可以存放在远端的服务器上,当游戏中需要使用它们时,再去按照需要去加载这些资源。这种技术增加了项目的灵活性,并且减少了应用程序的初始包的体积大小。

本文讲介绍 AssetBundles 技术,并且讨论如何去使用它,AssetBundles 工作流的步骤和阶段,如何将资源打包到 AssetBundle 中去,如何使用以及何时应该使用 AssetBundle Variants,如何构建和测试 AssetBundles 和 Variants。所有的这些,我们都可以使用 AssetBundle Manager 来简化AssetBundles 的创建、测试和发布环节。本文的最后一章我们将介绍一个使用 AssetBundles 和 Variants 的实际例子。

示例项目

在开始阅读这篇文章之前,你最好先把这里的 示例项目 中的 AssetBundle Manager 下载下来,我们会在后面的章节中用到它。

AssetBundle 是什么

AssetBundles 是有 Unity 编辑器在编辑环境中(enit-time)创建的一些列的文件,这些文件可以被用在项目的运行环境中(run-time)。 AssetBundles 可以包括的资源文件有模型文件(models)、材质(materials)、纹理(textures)和场景(scenes)。AssetBundles 不能包含脚本文件。

具体来说,一个 AssetBundle 就是把一系列的资源文件或者场景文件以某种方式紧密保存的一个文件。这个 AssetBundle 文件可以被单独加载到可执行的应用程序中。AssetBundles 可以由被 Unity 构建的游戏或者应用按需加载使用。这允许对像模型、纹理、音频、甚至是整个的游戏场景这样的资源进行流式加载和异步加载。AssetBundles 可以预缓存(pre-cached)和存储在本地,这样在运行时就可以立即加载它们。但是 AssetBundles 技术的主要的目的是在需要的时候能够从远端的服务器上按需请求特定的资源,并加载到游戏中。AssetBundles 可以包含 Unity 可以识别的任何类型的资源,包括自定义的二进制数据。唯一的例外是,脚本资源是不被允许的。

有很多 AssetBundles 的使用案例。新的内容可以被动态的从应用程序中加载或者卸载。Post-release DLC 可以被更容易的实现。一个应用程序的磁盘占用或大小可以再第一次发布时被减小,在程序被安装后,在按照需要加载必要的资源。平台和设备相关的资源可以被正确的加载,而不需下载和存储当前设备不需要的平台或者分辨率所对应的资源文件。国际化也变得很容易,只需要根据用户的地理位置、语言和偏好设置来下载需要的资源就可以了。应用程序可以不需要提交新的版本就可以做到用新的资源内容来修复、改变和更新。

应该怎样把一个项目的资源具体组成成 AssetBundles,这将严重依赖于具体项目的需求。但是下面这些基本的原则可以帮助我们更好的理解 AssetBundles。

  • AssetBundles 是需要整体下载和缓存的。

  • AssetBundles 不需要整体的加载到应用程序中,可以只加载其中的某些资源。

  • 在 AssetBundles 中的资源对其他资源有依赖关系。

  • 在 AssetBundles 中的资源可以同其他资源具有相同的依赖关系。

  • 每个 AssetBundle 都有一些技术开销,即在文件的大小上,也在管理这些文件上。

  • AssetBundles 应该为每个目标平台单独构建。

每一个 AssetBundle 都是被整体下载的。如果一个 AssetBundle 包含了一些不是被立即使用的资源,甚至它们都不会被加载到当前这个场景中,它们也会耗费下载时的带宽和存储时的磁盘空间。

AssetBundles 的内容不需要被全部加载到应用程序中。只要 AssetBundle 被下载下来了,不同的资源就可以按照需要选择性的被加载。

一些资源可能会对其他资源有依赖关系。比如,一个模型资源可以有几个依赖。一个游戏中的模型不只是有网格数据(mesh data),实际上它是一个拥有它所有 Components 的 GameObject,以及每个 Component 自己做依赖的依赖关系。

qEFN3ez.png一个网格模型及其所使用的材质

这个模型在 Mesh Renderer 中依赖于一个材质资源,而一个材质资源的 Albedo Texture 属性又依赖于一个纹理资源。所以,实际上这个坦克的模型依赖于三个资源,而不只是一个。

E7jmAn (1).png这个坦克模型的资源依赖链:模型 > 材质 > 纹理

资源可以其他资源共享依赖关系。比如,两个不同的模型可以共享一个相同的材质资源,而这又有可能依赖于同一个纹理资源。

ARvQ3q2 (1).png这两种岩石柱拥有不同的模型,但是共享相同的材质

每一个 AssetBundle 都有一些技术开销。AssetBundles 是一些封装资源的文件。这种封装会增大了 AssetBundle 的整体大小,尽管这种大小的增加不会太明显,而且是可测量的。AssetBundles 也需要一定的管理开销来组织、创建、上传和维护。 在项目中使用越多的 AssetBundles 也会越多的增加这种开销,即包括技术开销也包括管理开销。

当组织 AssetBundles 时,是更多的小的 AssetBundles 还是更少的大的 AssetBundles 呢?这是需要我们根据自己的项目的实际情况来好好权衡的。更多的小的 AssetBundles 会面临更多的跟踪和创建相关的开销,太少的 AssetBundles 会使单个AssetBundle 本身的大小变大,也会导致它们可能包含一些冗余的数据。

由于 AssetBundle 的内容是按照当前的目标平台和它的 Import Setting 来构建和优化的,所以 AssetBundles 需要在每一个平台上单独构建。

MANIFESTS 和依赖管理

关于依赖关系和依赖管理,有几个要点是需要重点理解的。

资源的依赖关系是永远不会丢失的。如果当前选择的资源所依赖的其他资源没有被包含在任何一个 AssetBundle 中时,这些被依赖的资源就会被自动添加到当前的这个 AssetBundle 中。这是非常便利的,也防止依赖资源的丢失。但是,这也会导致资源的重复。比如,上面介绍的两个岩石柱的例子中,如果两个岩石柱在不同的 AssetBundle 中,并且它们共享的材质都没有被显示的指定到一个 AssetBundle 中去,那么这个材质就会被两个岩石柱的 AssetBundles 都重复包含进去了。值得注意的是,当这种情况发生时,所有重复的资源会保存在它们单独的 AssetBundles 中,并且现在它们的依赖关系就被打破了。每一个岩石模型资源现在都依赖于它们 AssetBundle 中的材质资源,这样就不再享有共享材质资源所带来的好处。为了防止这样的事情发生,材质就需要显示的指定到一个 AssetBundle 中去。这个 AssetBundle 可以是独立的,也可以和其他资源共享一个 AssetBundle。不管是哪一种方式,这个岩石柱的 AssetBundle 就要依赖于包含这个岩石柱材质的 AssetBundle。

一个工程的 AssetBundles 的依赖信息和其他信息被存储在一个 Manifest 文件中。这个 manifest 文件很像一个项目的 AssetBundles 内容的清单列表。当构建 AssetBundles 时,Unity 会产生很多数据。这些数据的详细情况被存储在 Manifest 中。每一个平台都会创建一个 Manifest。这个 Manifest 列出了这个工程根据当前的编译平台创建出来的所有的 AssetBundles,并且存储和跟踪他们的依赖关系。通过这个 Manifest,就能够查询所有的 AssetBundles 和他们的依赖关系。

对于 AssetBundles 还有一个特殊的操作,我们称之为 AssetBundle Variants。AssetBundle Variants 是为了满足一种特殊的用户需求而设计的:重新映射不同的资源到项目中的独立的物体上。当我们需要根据分辨率、语言、地理位置或者是用户的偏好设置来选择不同的资源时,这种技术就会非常有用。AssetBundle Variants 可以包含所有需要支持的资源,并能根据用户的具体选择来映射特定的资源到需要的对象上去。

结语

AssetBundles 是一些包含模型、材质、纹理和场景等资源的文件。AssetBundle 是由 Unity 编辑器在编辑期间串接创建出来的,可以被应用程序在运行期间使用的。AssetBundles 是设计用来按需从本地或者服务器加载资源的。AssetBundles 可以用 Variants 来根据用户的偏好设置来映射不同的资源。


用户评论(0)