Content directories: Beyond the AssetBundle

Sep 22, 2026|6 Min
George Ing
George Ing - Unity Technologies
Senior Engineering Manager
Content directories in Unity 6.6

为方便起见,此网页已进行机器翻译。我们无法保证翻译内容的准确性或可靠性。如果您对翻译内容的准确性有疑问,请参阅此网页的官方英文版本。

今天位聊聊Unity的内容创作。

自Unity 2.1 以来,不起眼的AssetBundle就一直是Unity内容(在 Player 二进制文件之外发布)的基础。在过去的二十年里,数量惊人的游戏都使用了AssetBundles作为其数据表示形式,其中包括一些世界上规模最大的游戏。

从根本关卡,每个AssetBundle都是一个不可分割的单元,用于分发、存储和加载。AssetBundles在包关卡轨其依赖项,形成一个更大的单体单元,为了提高效率,需要一起下载、加载和卸载。

由于这一规范,游戏如何定义其AssetBundle布局是影响其运行时性能和下载大小等一切因素的主要因素。无论直接使用AssetBundles ,还是通过Addressables包,情况都是如此。

今天,我们要谈谈Unity运行时的一些不同之处。

介绍内容目录

内容目录是AssetBundles的基础性、高性能、细粒度替代方案。它们目前在Unity 6.6 中可用,可作为 Player 自带AssetBundles的替代方案。在Unity 7 版本中,技术栈将扩展以处理完整的、精细的空中传输(稍后会详细介绍——这非常酷)。

内容目录并非将资源烘焙成大型可加载单位,而是使Unity运行时能够独立识别、加载和卸载单个资源。(网格、纹理等)充分利用硬件资源并隐式进行内容去重。

图示展示了Unity资源如何从本地存储加载到工作内存中。左侧的“局部存储”面板包含九个Unity资源图标(3D网格、精灵图集、音频剪辑和预制件)。标有“单独加载”的箭头向右指向“工作内存”面板,其中仅包含三个此类资产,下方空白区域标有“可用于其他工作”。箭头下方有一条副标题写着“加载→使用→发布”。

现在,管理Unity项目的内容比以往任何时候都更加容易,构建速度更快,对资源位置和AssetBundle布局的担忧也更少。

你编译版本的游戏体积更小、速度更快、隐式去重,并且可以通过新的可加载引用类型访问完整的动态内存管理。对于使用Addressables来存储播放器捆绑内容的用户,您可以切换到内容目录。无需编写任何代码即可进行更改。

我们是如何make这一切的?让我们深入了解一下管线的每个阶段。

熟悉的基础:Build

早在 2019 年,我们就讨论过我们希望Unity中一个严肃的编译版本基础具备哪些特性——在每个核心上并行运行、确定性、完全缓存,并且能够在机器之间共享其编译版本数据。结果发现,我们的一些同事多年来一直在发布一个具有这些特性的API ,即资产导入框架。

因此,内容目录编译版本过程是在标准资源导入器框架内运行的。每个资产都是由资产导入器单独构建的,在沙盒环境中且在进程外的。构建过程是确定性的,具有资产数据库缓存、所有硬件核心的完全饱和以及原生加速器支持,可实现快速共享构建。

这可能不是你第一次听说这种编译版本系统。你们中的一些人可能还记得我们在Unity 2023.1 中预告的多进程编译版本管线。这是同一个基础。

图示展示了如何通过Build导入器将源文件转换为Unity资源。两个FBX 文件分别生成两个AssetBundle对象(显示为蓝色和灰色包图标),而两个PNG文件分别生成一个精灵/纹理资源(显示为棋盘格方块图标)。FBX 文件中的分支箭头表明,单个3D源文件可以生成多个运行时资源。

输出结果是一组松散的、粒度很高的工件,一个跟踪它们之间依赖关系的清单,以及一设置新的诊断文件,make理解您的编译版本比以往任何时候都更容易。

这非常简单。

熟悉的基础:解决

如果你打开一个内容目录编译版本并查看其中的工件,你会注意到每个瑕疵都有一个非常奇怪的哈希名称:

c0152db4dd710be51b2decb997325f34.cf
f0a44ad4a4babd121543fd44032928e7.resS
4226b5c16a50dab6eff0f08dd1253d4b.resource

酷的是——这不是随机生成的哈希值。相反,内容目录系统使用与 git 等技术相同的内容寻址存储模式。每个内容文件都通过其内容的哈希值进行命名和引用。这种模式对Unity运行时非常有用,因为它允许 Unity 以原生功能的形式隐式地对内容进行去重。

也就是说,具有真正依赖关系图的内容寻址存储存在高流失的风险。考虑两个物体之间最简单的关系:

A → B

UpdateB,以及 B 的哈希值变化。不幸的是,因为 A 引用了 B,所以 A 的哈希值也发生了变化。更糟糕的是,这种影响会一路向上蔓延。

相反,工件之间不通过内容哈希相互引用,而是通过稳定id进行引用。编译版本清单维护着一个小型查找表,将稳定 ID 映射到内容哈希值。

这样一来,运行时就拥有了加载所需的一切!

熟悉的基础:加载

在内容目录中,我们引入了一个性能极其优异的动态加载系统。

当内容目录挂载时,加载系统会读取清单并解析构件之间的稳定id依赖关系。它允许每个瑕疵完全独立地加载和卸载,不会受到相邻工件的干扰。 (还记得AssetBundles的问题吗——一个单一的、不可分割的单元?)已消失。)

对于 DOTS 用户来说,工件的底层文件格式可能看起来也相当熟悉。内容目录生成并加载我们在 2022 年 DOTS 中引入的下一代内容文件格式,将四年来一直支持多线程Entities加载的技术带到所有资产。

这是一个完全异步的加载系统,读取和反序列化操作都是异步的。这意味着更高的加载带宽和平台指定的异步读取 API 的利用。

图示对比了两种Unity资源加载流程。顶部部分标记为“AssetBundles”,显示了按顺序处理的序列化文件:每个资源依次经过读取和Deserialize,然后进行最终的唤醒步骤, GPU上传仅在最后进行。这被标记为“顺序”。底部部分标记为“内容目录”,显示了一个使用作业化管线的内容文件:首先并行读取所有资源,然后每个资源的Deserialize和唤醒步骤交错重叠, GPU上传则分布在整个过程中。这被标记为“Jobified”,说明了并行加载相对于顺序AssetBundle方法的性能优势。

更令人兴奋的是,内容目录基础架构使我们能够首次将现代可加载引用类型引入Unity ,称为Loadable

可加载的<网格> bodyMesh;
bodyMesh.Load();

这是一个真正的可加载引用,直接内置于基于内容目录的项目引擎中。可加载对象引用的对象将被拉入编译版本中,但只有在调用该可加载对象后才会加载。将 Loadables 与(非常)熟悉的ScriptableObject接口结合使用,可以让你以惊人的速度组织动态加载的内容。

我们对此原则感到非常兴奋。以内容目录和可加载项为基础,任何资产在Unity中,从角色创建器的各个部分到流式地形的各个部分,都可以成为独立加载和卸载的单元——这是引擎直接内置的功能——无需围绕AssetBundle布局或组定义进行设计。

使用Unity缩放构建游戏从未如此简单!

对内容目录进行测试:Slime牧场2

在过去的几个月里,我们的一些合作伙伴非常慷慨地允许我们用他们的游戏测试内容目录。

例如,让我们来看看 Monomi Park 的优秀游戏《Slime牧场 2》,以及它从切换到内容目录中获得的一些好处。(《Slime牧场》现已在Steam上架!)Slime牧场Slime牧场2

增量编译版本时间
Addressables (AssetBundle后端)
32 分 16 秒
Addressables (内容目录后端)
3 分 4 秒
完整编译版本时间:
Addressables (AssetBundle后端)
58 分 6 秒
Addressables (内容目录后端)
37 分 13 秒
播放器编译版本大小
Addressables (AssetBundle后端)
4GB
Addressables (内容目录后端)
2.88GB
加载时间 (游戏启动 ->菜单->游戏玩法)
Addressables (AssetBundle后端)
45秒
Addressables (内容目录后端)
30秒

此数据基于运行在MacBook Pro (M5 最大 ) 上的Unity 编辑器版本Unity 6.6 Beta (6000.6.0b10)。

最棒的是,用户能够立即感受到新加载系统带来的好处。更酷的是, 《Slime牧场2》是一个现有的Addressables项目,它在没有任何代码更改的情况下切换到了内容目录。

坦白说,我们迫不及待地想看看Unity生态系统中的游戏在 6.6 版本发布内容目录后会获得哪些好处。但这引出了一个问题,远程内容呢?

接下来是什么:远程内容分发

参加今年Unite Seoul 路线图演示的各位可能还记得,Jason Mann 曾透露,我们新的内容目录基础架构将使即将到来的Unity 7 世代的远程内容交付make更加容易。让我们简要地谈谈这究竟意味着什么,以及它如何与我们目前讨论的内容联系起来。

总而言之,有了内容目录,我们就有了一个小型的哈希驱动清单,能够唯一地标识工件及其依赖项。问题是,所有这些物品都必须随玩家一起运送吗?

答案是绝对的否定。

图示为一个云端,其中包含许多标记为“颗粒数据”的小绿色立方体图标,多条虚线蓝色箭头(标记为“内容请求”)从云端向下流入底部的移动设备。箭头汇聚到设备屏幕上,表明单个设备发出多个单独的网络请求,从云端下载细粒度资源。

得益于现代 HTTP 标准, Unity现在可以复用大量资源请求。

再加上内容目录基础,运行时可以准确地确定设备缺少哪些工件,只将这些工件下载到本地存储中,然后加载它们——而无需担心共存位置、数据布局或依赖的AssetBundles。更新在单个瑕疵关卡传播,并且由于清单使用内容哈希进行操作,运行时可以低成本地判断哪些工件已过时,并仅获取差异。

这种近乎未来的Unity运行时只会下载所需的内容,从而缩短开发时间,让玩家更快地进入游戏,并大幅降低CDN成本。

我们将在 2027 年分享更多关于该项目的信息。

立即体验Unity 6.6 中的内容目录

我们今天分享的是Unity内容全面改革漫长征程的第一阶段,旨在为整个运行时带来“默认高性能”。6.6 版本中提供了内容目录,用于存放播放器附带的内容,并且在Unity 7 版本中将扩展到处理远程内容。

要开始使用内容目录,检查查看我们的文档;如果您有任何反馈意见,请联系我们

再次感谢 Monomi Park 的朋友们,他们用他们精彩的标题帮助我们展示了内容目录!(Slime牧场Slime牧场2 )。