以下是该文档的详细总结,内容涵盖 Capcom 在 RE Engine 中为《生化危机:安魂曲》(Resident Evil Requiem)和《PRAGMATA》实现实时光线追踪(Path Tracing)的技术演讲,以及 NVIDIA 工程师提供的底层性能优化分析。
---
## 一、演讲概述
- **演讲者**:Capcom 的 Hitoshi Mishima(三岛仁)以及 NVIDIA 的 Calvin Shu
- **主题**:RE Engine 中路径追踪(Path Tracing)的实现,集成 NVIDIA DLSS 3.5(DLSS RR)以及相关优化
- **涉及游戏**:《生化危机:安魂曲》、《PRAGMATA》
- **关键技术**:路径追踪 vs. 光线追踪、NEE(Next Event Estimation)、RIS(Resampled Importance Sampling)、ReSTIR GI、DLSS RR 引导缓冲区(Guide Buffer)、DXR 1.2 与 SER(Shader Execution Reordering)等
---
## 二、路径追踪与光线追踪的对比
- **路径追踪**:更精确的实时渲染,包括更细致的阴影、更稳定的降噪、更锐利的反射、更准确的遮挡。
- **传统光线追踪**(RE Engine 原有实现):仅用于间接光照,直接光照仍使用光栅化。
- **路径追踪统一处理**:直接光照、间接光照、透明物体、后期效果均纳入统一管线。
---
## 三、RE Engine 路径追踪管线
### 3.1 总体流程
1. **Common Pass**:计算着色器执行可复用组件(如蒙皮、集群模拟)。
2. **G-Buffer**:提供初始命中信息。
3. **路径追踪核心循环**(每弹射一次 dispatch):
- 使用 NEE 评估直接光照
- 采样 BSDF 确定方向并发送新光线
- 如果命中几何体,更新表面信息,重复 NEE 与 BSDF 采样
- 如果未命中,则使用 IBL(Image-Based Lighting)贡献结束路径
- 使用俄罗斯轮盘(Russian Roulette)终止长路径
4. **最多 3 次弹射**(3 次 dispatch)
5. **可选的 ReSTIR GI** 用于稳定 DLSS RR 质量
### 3.2 与原有光线追踪的兼容性
- 路径追踪与光线追踪使用相同的 Ray Query 接口和材质着色器
- 实现时间:约 1.5 年,由两名开发人员完成
---
## 四、RIS(Resampled Importance Sampling)策略
### 4.1 简化 BSDF 用于 RIS
- 生成初始候选光源时,使用简化的 BSDF:
- 漫反射:Lambertian
- 镜面:单叶 GGX
- 将 BSDF 转换为单通道值,简化计算(F、G、L 评估)
### 4.2 光源剔除结构
- 类似光栅化光源剔除,定义每个光源的影响范围
- 使用 3D 纹理,每个 texel 存储光源 ID 位掩码
- 每个 cell 尺寸:16×128×128(长宽深)
- 在 shading point 评估重要光源
### 4.3 高强度 IBL 与室内场景问题
- IBL 在室内场景中导致高方差噪声,因为 RIS 未评估可见性
- **解决方案**:从候选集中移除 IBL,单独评估其亮度
### 4.4 高强度聚光灯问题
- RIS 未评估可见性,导致聚光灯照射区域偏暗
- **解决方案**:亮度补偿——使用相机曝光和调整系数作为 reservoir 更新权重,而非传统的 luminance (F·G·L)
### 4.5 弹射与阴影光线数量
- 第一弹射:2~3 条阴影光线
- 第二、三弹射:1 条阴影光线
- 方向光单独处理;点光源与发光多边形通过 RIS 合并
---
## 五、发光多边形(Emissive Polygons)采样
### 5.1 问题
- 仅靠光线命中(ray-hit only)会产生大量噪声
- NEE 必须包含发光多边形
### 5.2 解决方案:Walker's Alias Method
- 构建数据结构:每个 bucket 最多两个元素,支持 O(1) 采样
- 权重:三角形面积 × 基础强度,可包含距离衰减
- 为每个子网格(submesh)与材质对构建一次数据结构(假设面积不变)
- 采样步骤:
1. 用第一个随机数选择 bucket
2. 用第二个随机数选择 bucket 中的元素
3. 选中子网格后,在其三角形上均匀采样
- 预生成样本存于 buffer 中以避免每帧开销
- 发光纹理的影响通过 RIS 进一步降低
---
## 六、ReSTIR GI 的应用
### 6.1 目的
- 稳定 DLSS RR 的质量,减少间接光照的离散(dispersion)
### 6.2 实现细节
- 当前帧像素信息与上一帧像素信息混合,进行重采样(resampling)
- 为避免对 DLSS RR 产生过高的时间相关性,重采样时选择与上一帧像素略有偏移的位置
### 6.3 效果改善示例
- **鬼影/模糊区域**:右侧使用 ReSTIR GI 后明显改善
- **次表面散射(Subsurface Scattering)**:散射前后亮度差异被写入 Guide Buffer,消除了 RR 导致的散射伪影
- **毛玻璃/模糊玻璃**:同样使用次表面散射 Guide 方法消除伪影
---
## 七、DLSS RR 引导缓冲区(Guide Buffer)的扩展
### 7.1 遮挡掩码(Disocclusion Mask)用于雨水/水滴
- 问题:雨水、水滴在 DLSS RR 中变得透明或被过度降噪
- 解决方案:创建遮挡掩码,标记雨水、水滴的像素位置,强制 RR 保留细节
- 注意:过度使用掩码会重新引入噪声,应保守使用
### 7.2 动画投影纹理光源
- 问题:动态纹理光(如地面波纹)导致延迟或拖尾
- 解决方案:利用光源动画信息计算权重,估计每个 shading point 的贡献,创建包含掩码,仅对动画光强烈的区域施加修正
### 7.3 全息图案(Hologram)
- 问题:全息图案使用 emissive 颜色动画,但 DLSS RR 的 Guide Buffer 未包含该信息,导致图案模糊
- 解决方案:将 Guide Buffer 中的漫反射 albedo 和镜面 albedo 替换为 emissive 颜色,使图案清晰可见
---
## 八、头发渲染(Hair Strands)
- 《生化危机:安魂曲》和《PRAGMATA》均使用发丝(strands)模拟头发
- 结合硬件光栅化和软件光栅化
- **PRAGMATA 的挑战**:低重力环境下长发飘动,导致 fallback mesh 与 strands 模拟不一致,产生错误阴影
- **解决方案**:为 strands 构建专用的 BVH(基于 NVIDIA OptiX 或 DXR),使光线追踪与光栅化表现一致
---
## 九、阴影与 Alpha 测试
### 9.1 粗几何体阴影
- 路径追踪产生的阴影可能因几何体粗糙而不完美
- 仅在过场动画中使用特殊方法(参考论文,未详细展开)
### 9.2 Alpha 测试
- 光线追踪中 Alpha 测试通常使用 Any Hit shader
- 路径追踪中为避免复杂 Any Hit shader,采用屏幕空间 Alpha 测试(Screen Space Alpha Test):
- 类似阴影贴图的逆过程,不产生阴影而是允许光线穿过
- 由光栅化器决定命中位置是否可见
---
## 十、BVH 管理与异步计算
- BVH 作为加速结构在后台构建
- **阴影终止点(Shadow Terminator)**:使用 recast ray 避免自相交
- **异步计算**:将 Direct Queue 与 Compute Queue 结合,避免因同时使用 Frame Generation 和 BVH 更新导致的空闲
---
## 十一、性能数据(2022年11-12月)
- 《生化危机:安魂曲》在 4K + DLAA 模式下的初始性能:约 21ms/帧
- 经过优化后:17.7ms → 16.9ms(SER 优化)→ 13.3ms(驱动优化,未来补丁)
---
## 十二、底层性能优化(Calvin Shu 部分)
### 12.1 计算着色器波前(Wavefront)实现
- 每弹射一次 dispatch,写入活跃像素信息,使用原子计数器(atomic append)和间接调度
- 活跃像素的 warp 平均占用 13.7 线程,相干性 43%
- 性能瓶颈:光采样循环(punctual light + emissive light)
### 12.2 光采样循环优化
**原始流程**(每光样本):
- 调用随机函数 2 次
- 评估完整 BRDF
- 向 reservoir 输出漫反射/镜面 radiance
- 再调用随机函数 1 次
- 追踪阴影光线,通过后累加
**优化措施**:
- 简化 RIS 目标函数:仅关注镜面 lobe,漫反射使用固定项
- 使用 world space 的 vanilla GGX 代替高质量 GGX(避免 Firefly 函数)
- 合并随机调用:使用一个 uint 随机数,拆分为高 16 位和低 16 位作为两个 float
- 共享 reservoir 间的随机种子
- 光采样循环只输出 incoming radiance,最后追踪阴影光线时才计算完整 BRDF
**结果**:性能提升 15%(21ms → 17.7ms),指令数减少约 3k,样本数从 400k 降至 300k
### 12.3 DXR 1.2 与 SER(Shader Execution Reordering)
**波前方法 vs. SER**:
- 波前方法:需要手动通过 UAV 传递数据,全局内存开销大,每弹射需同步
- SER:编译器自动决定传递变量,数据可能留在片上,所有弹射并行执行,支持不同材质的不同 hit shader
**初始 SER 移植结果**:23.5ms(SER off)→ 20.8ms(SER on),仍慢于波前方法的 17.7ms
**原因分析**:
- SER 版本指令数高达 24k(波前方法每 pass 约 11k,两个 pass 共 22k 但可独立切换资源)
- 因为合并了两次弹射,且静态 SRV 引用导致编译器重复生成指令
- 35% 时间消耗在“无指令停顿”(等待加载新指令)
**解决方案**:
- 将静态 SRV 引用改为 bindless 数组,使编译器只生成一套代码
- 指令数降至 12k,无指令停顿降至 18%,性能达到 16.9ms(略优于波前方法)
**最终**:结合驱动优化,可降至 13.3ms
### 12.4 性能建议总结
- 减少光采样循环中的 ALU 操作
- 简化目标函数评估
- 复用随机种子,拆分 uint 为两个 float
- 合并光循环类型以减少指令缓存缺失
- 考虑完整 ReSTIR DI 实现以共享相邻像素和时间样本
- 推荐使用 DXR 1.2 + SER,注意避免过度特化的代码路径
---
## 十三、DLSS RR 引导缓冲区的使用建议
- 尽量先不使用掩码,仅在必要时保守添加
- 过度使用掩码会重新引入噪声,关闭累积效果
- NVIDIA 将持续改进 Disocclusion Mask 引导缓冲区
---
## 十四、问答环节摘要
1. **最困难的部分**:满足美术人员的期望(环境间接光照的“煮沸”效果、ReSTIR GI 导致的遮挡变化)
2. **为何使用 Ray Query 而非完整光线追踪管线**:引擎已有 Ray Query 实现,SER 较新,未能在发布前完全优化完成
3. **遮挡掩码过度使用是否导致噪声**:是,毛玻璃等问题使用次表面散射 Guide 而非遮挡掩码
4. **美术协作**:技术美术(TA)收集各项目问题,与引擎团队协作
5. **随机数重用与拆分是否引入偏差**:未严格证明,通过视觉验证
6. **最大性能提升因素**:光源剔除(light grid culling)
7. **切换 IBL 采样策略时是否出现可见噪声**:RR 处理良好,几乎无可见切换噪声
---
## 十五、未来工作
- 继续改进 ReSTIR GI
- 发光多边形评估
- 更多性能优化和 DLSS RR 更新
---
## 十六、致谢
- Capcom 开发团队(Kenta Nakamoto, Kosuke Navata 等)
- NVIDIA DevTech 团队
---
**总结完毕**。文档详细介绍了 Capcom 在 RE Engine 中实现实时路径追踪的全套技术方案,包括核心算法、采样策略、降噪与引导缓冲区、性能优化以及与 NVIDIA 的合作成果。