1、”Cook”这个名字怎么来的?
在 Unreal 的构建流程中,「Cook」是一个绕不过去的概念。
我一开始很疑惑——为什么要叫「Cook」?难道 Unreal 把资源处理比喻成做菜?
后来发现确实就是这样。Unreal 的工程师觉得,编辑器里的资源是「生食材」,需要经过「烹饪」才能变成各个目标平台可用的「成品」。
这个比喻其实很贴切。
编辑器里的资源格式是通用格式——贴图可能是 .png,模型可能是 .fbx,材质是一个包含各种参数的蓝图节点图。这些格式方便编辑,但不适合在游戏里直接使用。
Cook 做的事情,就是把这些「生食材」烹饪成目标平台能直接消费的「成品」。
2、Cook 到底做了什么?
如果把 Cook 拆开看,它主要做了这么几件事:
贴图转格式
编辑器里你的贴图是 .png、.tga、.psd 这类通用格式。Cook 的时候,根据目标平台把它们转成目标格式:
- PC → DXT/BC 系列
- iOS → ASTC
- Android → ETC2 或 ASTC
同时生成 Mipmap(多级缩小版贴图),让远处物体用低分辨率版本,节省显存。
模型优化
.fbx 模型文件包含了大量编辑器需要的信息(命名、层级、导入参数等),但运行时不需要这些。Cook 把模型抽取成引擎的 Mesh 数据格式,计算好 LOD、碰撞体,扔掉编辑器专用的元数据。
材质烘焙
编辑器里的材质是一张蓝图节点图,有几十个参数可以实时调整。Cook 的时候,Unreal 把材质编译成目标平台的 Shader——把那些蓝图节点「翻译」成 HLSL/GLSL/Metal Shading Language 代码。
这几乎可以理解为「材质的 AOT 编译」。
Shader 编译
这是 Cook 里最耗时的环节。Unreal 的 Shader 系统非常灵活,一个材质可以有成千上万个 Shader Permutation(排列组合)。比如「开启阴影 + 不开启阴影」「有法线贴图 + 没法线贴图」「PC 平台 + Android 平台」……每一个组合理论上都需要一个独立的编译结果。
Cook 会遍历项目中使用到的所有材质,为每种可能的 Permutation 编译 Shader。一个中型项目的 Cook 可能需要编译几万甚至几十万个 Shader Variant。这就解释了为什么 Cook 这么慢。
引用分析
Unreal 的 Cook 需要分析哪些资源被打包进最终版本、哪些不打包。它会从关卡或入口资源开始,走一遍引用图——这个关卡用了哪些材质、这些材质引用了哪些贴图、这些贴图又引用了哪些……一路追踪下去。
只有被「根节点」引用到的资源才会被 Cook。这个机制叫 Cook by the book,本质是一个可达性分析。
3、Cook 的几种模式
Unreal 提供了不同的 Cook 模式,适应不同的场景:
CookOnTheFly(开发期)
编辑器正在运行,Cook 在后台按需进行。打开一个关卡或者加载一个资源时,Cook 被动态触发——没有 Cook 过的就 Cook,Cook 过的直接用缓存。
好处是开发者几乎无感。坏处是首次打开一个超大的关卡可能要等好一阵。
CookByTheBook(出包期)
正式构建时用的模式。指定一个入口(通常是 Game 的默认地图),然后按照引用图「按书(the book)」一层层 Cook。这是最完整的 Cook 模式,也是耗时最长的。
SkipCook(跳过 Cook)
如果你确定资源没有任何变化(比如只改了 C++ 代码,没有任何资源改动),可以跳过 Cook。这能大幅缩短构建时间。但一旦用错了——资源没更新,旧贴图还在——线上就是事故。
4、Cook 为什么这么慢?
Cook 慢的根本原因是资源太多 + 处理太细。
一个中型项目,Cook 可能需要几十分钟。时间主要花在:
- Shader 编译(占比最大):几万个 Shader Variant,每个都需要 GPU 编译器走一遍
- 贴图转换:几百上千张贴图,每张都要根据平台格式重新编码 + 生成 Mipmap
- 引用遍历:如果资源引用图很复杂,遍历本身就不快
有趣的是,这些处理的大部分结果其实是可以复用的。同一个贴图,只要源文件没变、Cook 参数没变,Cook 出来的结果就不会变。Unreal 也意识到了这一点——所以它引入了 DDC。
5、DDC:Cook 的缓存系统
DDC 的全称是 Derived Data Cache(派生数据缓存)。
它的概念很简单:Cook 的结果存起来,下次 Cook 时如果源资源没变,直接从缓存里拿结果,跳过处理过程。
DDC 可以配置为多种存储方式:
- 本地 DDC:存在本机磁盘上,只对自己有效
- 共享 DDC:存在团队的 NAS 或网络存储上,一个人 Cook 完,全团队都能用
- 云端 DDC:Unreal 官方提供的 Zen 存储,适合远程团队
有经验的项目都会配置共享 DDC。一个新来的同事拉下项目 + 团队共享 DDC,第一次 Cook 可能几分钟就完成了——因为大部分资源别人已经 Cook 过了,他只需要编译那些新改的或本机独有的部分。
DDC 是 Unreal 在缓存方面比 Unity 强出几条街的地方。
6、Cook 出错了怎么办?
Cook 过程中最常见的两个问题:
第一个:Cook 卡在某个资源上不动了。
通常是某个资源有问题(贴图巨到离谱、模型拓扑错乱、Shader 编译挂了)。排查方法是看 Cook 日志,找到 Cook 中断在哪个资源上,检查那个资源是否有问题。
第二个:Cook 出来的结果和编辑器里看到的不一样。
这是最头疼的。编辑器里效果完美,Cook 出来贴图糊了、材质丢了、模型变黑了。原因是编辑器用的是「未 Cook」的通用资源,而 Cook 后的资源经过了平台转换。排查这类问题,需要对比 Cook 前后的资源差异。
建议出包前一定要跑一次完整的 Cook + Pak + Run 的测试。
7、小结
Cook 是 Unreal 构建中最核心、最耗时的环节。它做的事情如果用一句话概括:
把编辑器的通用资源,转换成目标平台的原生格式,并把所有 Shader 预编译好。
它的慢是被设计的——你用构建时间换来了运行时的加载速度和渲染效率。DDC 是这个 trade-off 的缓释剂。
下一篇,我们聊 Pak 文件——Unreal 怎么把 Cook 好的资源打包成 .pak 文件?和 Unity 的 AssetBundle 相比,Pak 有什么异同?
每天前进一小步,就是一个新的高度!