共计 2238 个字符,预计需要花费 6 分钟才能阅读完成。
当 CPU 烘焙遇上百万级三角面
在传统 3A 游戏项目中,一个包含 200 万三角面的场景使用 CPU 烘焙器(如 Beast)生成 1GB 光照贴图,平均耗时约 8 小时。更糟糕的是,每次美术调整材质或灯光后,都需要重新经历这个漫长等待过程。我们实测数据显示:

| 三角面数量 | CPU 烘焙时间(Xeon Gold 6248) | 输出贴图大小 |
|---|---|---|
| 50 万 | 2 小时 | 256MB |
| 200 万 | 8 小时 | 1GB |
| 500 万 | 20 小时 + | 2.5GB |
这种工作流严重拖累迭代效率,尤其当需要频繁调整间接光照效果时。
为什么选择 Bakery GPU 方案
对比主流烘焙方案后发现:
- Enlighten:实时性强但预计算仍需 CPU 参与
- Beast:烘焙质量高但完全依赖 CPU
- Bakery:
- 全 GPU 流水线(从光线发射到最终贴图生成)
- 实时预览窗口支持材质 / 灯光参数即时反馈
- 基于 CUDA 的 Wavefront 调度使 GPU 利用率稳定在 95% 以上
关键优势在于:修改灯光颜色后,Bakery 能在 10 秒内 更新预览效果,而传统方案必须重新烘焙。
核心实现解析
Wavefront 调度策略
Bakery 将场景划分为32×32 像素块,每个 CUDA 线程组处理一个块。通过原子计数器实现动态任务分配:
// Wavefront 调度核心逻辑
RWStructuredBuffer<uint> g_TaskCounter;
[numthreads(32, 32, 1)]
void CS_RayDispatch(uint3 tid : SV_DispatchThreadID)
{uint taskID = g_TaskCounter.IncrementCounter();
uint2 pixelBlock = GetPixelBlock(taskID); // 将线性 ID 转换为 2D 块坐标
// 每个线程组独立处理一个像素块
[unroll]
for(int i=0; i<64; i++) {uint2 pixel = pixelBlock * 32 + uint2(i%32, i/32);
TraceRadianceRay(pixel);
}
}
显存优化技巧
- Half-float 压缩 :将中间计算的辐照度数据存储为R16G16B16A16_FLOAT 格式
- Mipmap 链共享:烘焙时直接生成 mipmap 链,避免后期单独处理
- 动态卸载:对不可见面片的几何数据实施 LRU 缓存策略
实测 VRAM 占用对比:
| 数据格式 | 200 万面场景占用 |
|---|---|
| R32G32B32A32_FLOAT | 3.2GB |
| R16G16B16A16_FLOAT | 1.6GB |
Adaptive Sampling 抗噪方案
通过方差估计动态分配采样数,关键代码片段:
float3 EstimateNoise(float3 history, float3 current) {float3 variance = abs(history - current);
float maxVariance = max(variance.r, max(variance.g, variance.b));
return **lerp(1.0, 8.0, saturate(maxVariance * 10.0))**;
}
// 在光线追踪循环中应用
for(int i=0; i<g_BaseSamples; i++) {float3 radiance = TraceRay(pixel, samplePos);
if(i > 4) { // 跳过前几个预热样本
float adaptiveWeight = EstimateNoise(accumulated, radiance);
sampleCount += adaptiveWeight;
accumulated += radiance * adaptiveWeight;
}
}
性能实测数据
测试场景:200 万三角面室内场景(含动态光照探头)
| 硬件配置 | 烘焙时间 | 峰值 VRAM 占用 |
|---|---|---|
| Xeon Gold 6248 | 6h42m | 12GB(内存) |
| RTX 4090 | 23m | 5.8GB |
| RTX 3090 双卡 | 18m | 3.2GB/ 卡 |
VRAM 占用与面数量的关系:
面数量(万) | VRAM 占用(GB)
50 | 2.1
100 | 2.8
200 | 5.8
500 | 11.4 (触发 Fallback)
避坑指南
多 GPU 负载均衡
通过 NVLink-aware 任务分配 避免 PCIe 瓶颈:
- 使用
cudaDeviceGetP2PAttribute检测设备互连拓扑 - 优先将相邻面片分配给同一显卡处理
- 动态平衡:每完成 10% 进度重新评估各卡负载
显存不足 Fallback
当检测到 VRAM 即将耗尽时:
- 激活 分块烘焙模式(每块完成后立即释放资源)
- 降级几何精度:
- 自动启用 LOD 1 级模型
- 对远处物体使用简化碰撞体
- 日志提示:” 建议减少动态光照探头数量 ”
Shader 兼容性处理
跨平台编译的解决方案:
// 定义精度宏避免 Mobile 平台报错
#ifndef PLATFORM_MOBILE
#define PRECISION
#else
#define PRECISION mediump
#endif
PRECISION float3 ComputeIndirectLight() { ...}
未来优化方向
目前 Bakery 对完全动态物体仍需实时光照计算。结合 Neural Radiance Caching 的可能路径:
- 烘焙时同步生成场景的神经辐射场隐式表示
- 动态物体通过球谐系数插值获取间接光
- 使用光流场处理动态物体投影
开放问题:如何平衡神经网络推理开销与画质提升?这或许是下一代混合烘焙系统的突破口。
通过本次实践,我们将一个原本需要过夜的烘焙过程缩短到咖啡时间。更重要的是,实时交互的能力让美术团队可以像编辑材质那样自由调整间接光照——这才是 GPU 加速带来的真正革命。
正文完
