1、那个让构建时间砍半的东西
上一篇我们讲了 AssetBundle 的两代接口演进——从第 0 代「手写代码收集资源、不自动处理依赖」,到第 1 代的两条路线(标记包名 / AssetBundleBuild[] 代码定义分包)。
虽然第 1 代的 BuildAssetBundles 解决了依赖处理的可靠性问题,但它有两个硬伤。第一,增量构建的效率很差——你改了项目中一个贴图的压缩格式(比如从 RGBA32 改成 ASTC),理论上只改了这一个资源,应该只重新打包这一个 Bundle 吧?实际上 Unity 默认的 BuildAssetBundles 经常「过度重打」——明明没变的 Bundle 也被重新打包了。大型项目里,每次出包都要等几十分钟甚至更久。
更关键的是第二个问题:前几代打包 Pipeline 的源码是不开放的。打包流程出了问题,你想自己排查、自己修——对不起,源码你看不到。你只能等 Unity 官方更新,或者在外面绕道 workaround。
这时候,Scriptable Build Pipeline(简称 SBP) 登场了。
2、SBP 是什么?
SBP 的全称是 Scriptable Build Pipeline。它是 Unity 官方提供的一套底层打包 API 替代方案,最早以独立的 Package 形式发布(通过 Package Manager 安装),后来逐渐成为 Unity 推荐的打包基础设施。
它的定位很明确:替代 BuildPipeline.BuildAssetBundles ,提供更高效、更可控的资源打包流程。
注意,SBP 替代的是「打包接口」,不是「加载接口」。你用 SBP 打出来的依然是 .bundle 文件,运行时加载方式(AssetBundle.LoadFromFile 等)完全不变。SBP 只影响构建阶段,不影响运行时。
这也是它最大的优点:迁移成本低。 你不需要改任何游戏逻辑代码,只需要把 CI 上的打包脚本从调 BuildAssetBundles 换成调 SBP 的接口。
而且,SBP 的源码是开放的。这和前几代打包 Pipeline 形成了鲜明对比——SBP 之前,打包流程的源码完全不开放,你想排查问题、想自己修 bug,根本无从下手。SBP 的源码你可以在 Package 里看到,虽然底层最终也调了引擎内部接口,但至少大部分打包逻辑是暴露出来的,你可以读、可以改、可以调试。
3、SBP 的三大核心优势
优势一:精确的增量构建
SBP 对「什么变了、什么不需要重打」的判断比 BuildAssetBundles 精准得多。
BuildAssetBundles 的增量判断比较粗糙——而且因为源码不开放,你根本不知道 Unity 内部是怎么判断的。它就像一个黑盒,经常出现「看起来没变的东西也被重打了」的情况,你连排查都无从下手。
SBP 则把整个打包流程拆成了多个可独立缓存的步骤:
资源收集 → 依赖计算 → 内容哈希 → 压缩打包
每一步都有独立的缓存。如果你的贴图改了压缩参数,SBP 会:
- 重新计算这个贴图的 Hash(内容变了)
- 重新计算它的依赖关系也没变(引用同一张贴图的预制体没变)
- 只重新打包包含这个贴图的 Bundle
而其他几十个没有引用这个贴图的 Bundle,完全跳过。
对于大型项目来说,这个改进意味着:日常构建时间可能从 40 分钟降到 10 分钟甚至更少。
优势二:可编程的构建流程
BuildAssetBundles 就像一个黑盒——源码不开放,你把资源标记好,告诉它输出目录,它就开始跑。内部逻辑你完全看不到。你想在打包过程中插一个步骤(比如打包前自动检查贴图尺寸是否超限、打完包自动生成版本文件),你得在构建脚本里「包一层」,调完 API 再做额外操作。
SBP 把构建流程变成了可组装的管道。它暴露了多个 IBuildTask 接口,你可以在标准的打包流程中插入自己的步骤:
// 用 SBP 自定义构建流程的简化示意
var buildTasks = new List<IBuildTask>
{
new CalculateAssetDependencyData(), // 计算依赖
new CalculateCustomHashes(), // 计算 Hash(自定义)
new StripUnusedSpriteSources(), // 自定义:移除未使用的 Sprite 源数据
new GenerateBundlePacking(), // 生成打包计划
new WriteSerializedFiles(), // 写入序列化资源
new ArchiveAndCompressBundles(), // 压缩打包
};
这使得团队可以按自己的需求定制打包流程,而不是被 Unity 的默认行为锁死。
优势三:透明的缓存和日志
SBP 的每一步做了什么、哪些增量命中了缓存、哪些资源被重打了,日志里都一清二楚。排查「为什么这个 Bundle 每次都被重打」之类的问题,SBP 比默认接口友好很多。
4、SBP 和 Addressables 的关系
有一个很容易混淆的点:SBP 和 Addressables 是什么关系?
简单说:
- SBP 是底层基础设施——替换
BuildAssetBundles,管「怎么打」 - Addressables 是上层资源管理系统——管「打什么」「怎么加载」「怎么更新」
它们是两个独立的 Package,可以分开使用:
- 只用 SBP,不用 Addressables:如果你的项目已经在第 1 代 AssetBundle 体系下跑得很好了,只想提升构建速度和缓存效率,那可以只用 SBP 替换底层的打包接口。加载逻辑不动,运行时不变。这是改动最小的升级路径。
- 只用 Addressables,不用 SBP:Addressables 默认底层的打包用的就是
BuildAssetBundles(不过新版本 Addressables 已经推荐搭配 SBP)。 - SBP + Addressables 一起用:这是 Unity 官方推荐的最终状态——Addressables 做资源管理,SBP 做底层打包。也是新项目的最佳实践。
5、从第 1 代到 SBP 的最小化迁移
如果你用的是标记模式的路线 A(手动标记包名 + BuildAssetBundles),迁移到 SBP 非常简单。大致步骤:
- 通过 Package Manager 安装
com.unity.scriptablebuildpipeline包 - 保留你现有的 AssetBundle 标记(
.meta文件中的包名不变) - 把打包脚本中调用
BuildPipeline.BuildAssetBundles()的地方,替换为 SBP 的CompatibilityBuildPipeline.BuildAssetBundles()
就这么简单——名字换了,参数格式基本兼容,SBP 会自动读取现有的 AssetBundle 标记,增量缓存自动生效。
如果用的是路线 B(AssetBundleBuild[] 代码定义分包),也没问题——SBP 也提供了兼容 AssetBundleBuild[] 的接口,或者你可以直接使用 SBP 的高级 API 来重写打包流程,获得更精细的控制。不论哪条路线,迁移成本都不大。
当然,如果你想要更精细控制,后续可以逐步用 SBP 的高级 API 替换兼容模式,但这已经是最平滑的入门路径了。
6、小结
| 维度 | BuildAssetBundles(第 1 代) | SBP(第 2 代底层) |
|---|---|---|
| 增量构建 | 粗糙,经常过度重打 | 精确,基于内容 Hash 的增量判断 |
| 可定制性 | 黑盒(源码不开放),不可定制的固定流程 | 可插入自定义 BuildTask(源码开放) |
| 迁移成本 | — | 极低,兼容模式几乎零改动 |
| 与 Addressables 的关系 | Addressables 可选用它 | Addressables 推荐搭配使用 |
| 运行时影响 | — | 无影响,打出来的仍是 .bundle |
SBP 解决的是「怎么让打包更快、更智能」的问题。而「资源怎么管理、怎么加载、怎么热更新」这个层面的问题,它不负责——那是 Addressables 的主场。
下一篇,我们来聊聊 Addressables——它是 Unity 目前推荐的资源管理方案。在第 1 代 AssetBundle + SBP 的基础上,它又解决了一层什么问题?为什么它的改动比 SBP 大得多?
每天前进一小步,就是一个新的高度!