Unity 6.6 让 AssetBundles 退役:Slime Rancher 2 的增量构建从 32 分钟缩短到三分钟
Unity 在 6.6 版本中推出了 content directories——一种打包和加载内容的新方式,引擎开发者直接将其称为 AssetBundles 的替代品。最主要的区别在于,运行时现在寻址、加载和卸载的是单个构件,例如某个具体的网格或贴图,而不再是整个 bundle。各团队多年来绞尽脑汁琢磨分组策略的 bundle 划分,不再是一项设计决策。
Unity 给出的数据来自一个真实项目:从 Addressables 迁移到 content directories 的 Slime Rancher 2。增量构建从 32 分 16 秒缩短到 3 分 4 秒,全新构建从 58 分 6 秒缩短到 37 分 13 秒。游戏构建体积从 4 GB 瘦身到 2.88 GB,加载时间从 45 秒加快到 30 秒,约快了三分之一。测试在搭载 M5 Max 的 MacBook Pro 上、于 Unity 6.6 Beta(6000.6.0b10)中完成。
为什么 bundle 作为加载单位不再够用
AssetBundle 是分发、存储和加载中不可分割的单位。依赖关系在 bundle 层级被追踪,加载和卸载也必须整体进行。由此衍生出全部配套工作:手工把资源分配到各个组、追踪依赖链、与多个 bundle 之间公共资源的重复作斗争。
content directories 的构造完全不同。Unity 采用了内容寻址存储方案——与 git 的底层思路相同:每个内容文件都以自身内容的哈希来命名和寻址。去重从开发者的任务变成了格式本身的属性。不过构件之间并不通过哈希相互引用,而是使用稳定的标识符——否则修改一个文件就会让整条链上的哈希连锁变化;标识符与哈希的对应关系保存在构建清单中。
哪些内容要进入构建,现在不再靠给每个资源打标记来指定,而是由根资源决定,也就是普通的 ScriptableObject。依赖会被自动带入,并按单个资源而非按 bundle 追踪。代码中出现了 Loadable<T>
类型——引擎层级的可加载引用:声明一个形如 Loadable<Mesh> bodyMesh 的字段,随后调用 bodyMesh.Load();单个资源的加载与卸载既可以同步进行,也可以通过 async/await 异步进行。被 Loadable 引用的对象会进入构建,但在被请求之前不会加载到内存。加载本身在读取和反序列化两个环节都完全异步,使用各平台的 async API;其底层是 2022 年在 DOTS 中出现的内容文件格式。已经在用 Addressables 的人该怎么办
Unity 没有破坏现有项目。content directories 与 Addressables 包兼容,后者仍然是组织内容的界面,现有项目可以转换到新的后端:Slime Rancher 2 的迁移没有改动一行代码。转换流程以及各种方案的对比,都写在 Addressables 的文档里。
真正改变的是「究竟需要标记什么」这一思路。Unity 会自动把 Loadable 引用到的资源纳入构建,并自行清除重复项,因此不再需要为公共依赖单独建 bundle。文档建议为整个项目只创建一个根资源;如果代码要通过字符串键加载大量资源,则建议用 ScriptableObject 充当资源列表,而不是建立大量根资源。
需要提前知道的限制
在 6.6 中,content directories 只适用于本地内容,即随播放器一同分发的那部分。远程分发和安装后的补充下载,仍然需要 AssetBundles 或自研机制。完整的「空中」细粒度分发,Unity 承诺放在 Unity 7 一代,细节将在 2027 年公布。
- BuildUsage
content directory 在运行时注册,此后其中的资源即可使用;场景同样通过可加载引用接入。详细内容见 Unity 关于 content directories 的官方文档。
Unity 为什么偏偏在此时更换地基
content directories 看上去是整个内容技术栈换了支点,而不是 6.6 的一项单独功能。AssetBundle 的局限在 Addressables 的设计中也清晰可见:使用这个包的相当一部分工作,实质上是在弥补 bundle 不可分割这一点。一旦基础单位变得原子化,技术美术和构建工程师的部分惯常工作——按组划分、追查重复、手工管理依赖链——自然也就失去了意义。
这个方向与整个行业转向内容寻址存储和增量构建的趋势一致:同样的原理早已在版本控制系统和构建缓存中运转,而在大型项目里,它的收益首先体现在迭代时间上。Slime Rancher 2 这个例子中增量构建缩短到十分之一,冲击的与其说是最终构建,不如说是每天修改与验证的循环——而团队的工时正是花在这上面。
Addressables 并不会就此消失:从迁移方式来看,这个包仍然是面向用户的界面,而 content directories 占据了它下面的位置。考虑到 Unity 把远程分发绑定在 Unity 7 一代的新地基上,迁移到这套后端很可能会逐渐成为细粒度内容补充下载的前提条件,而今天还靠手工划分 bundle 度日的项目,值得提前研究一下转换事宜。
为什么 AssetBundles 直到现在才被送去退役:来自 Godot 和 Unreal 的压力、Addressables 积攒下来的痛点,还是 John Riccitiello 离任后的路线转向?