《刺客信条:影》中的光线追踪全局光照系统

Ray tracing the world of Assassin's Creed Shadows (Advances in Real-Time Rendering SIGGRAPH 2025)


项目背景与挑战

游戏世界的动态性

  • 《刺客信条:影》 是育碧迄今为止 最具动态性的大规模开放世界 游戏
  • 动态要素极为丰富:
    • 动态时间过渡(Time of Day transitions)
    • 14 种独立天气状态(unique weather states)
    • 4 个静态季节,会影响天气、材质和时间表现
  • 这些动态因素意味着:传统的 均匀探针分布方案(Uniform Probe Distribution) 无法良好适配如此高动态性的场景,扩展性(Scalability)不足

技术演进历程

  • 《刺客信条:起源》 时代:从均匀探针方案转向 稀疏探针方案(Sparse Probe Solution)
  • 《刺客信条:影》:进一步发展出 光线追踪漫反射与镜面反射方案(Ray Traced Diffuse & Specular Solution)

平台扩展性需求

  • 扩展性不仅面向动态性,还需要 平台扩展性(Platform Scalability)
  • 同一平台上,玩家可能选择 画质模式性能模式,对应两套不同的渲染方案
  • 因此系统设计必须灵活适配多种硬件配置

全局光照算法概览

技术基础

本方案建立在以下已有技术之上:

  • DDGI(Dynamic Diffuse Global Illumination):动态漫反射全局光照,使用了最新的 逐像素光线追踪 Pass(Per-Pixel Ray Tracing Pass) 版本
  • Probe Volume 作为间接光照缓存:将探针体积用作 多次弹射间接光照计算(Multi-bounce RTGI Computation) 的缓存
  • 类似系统已在多款游戏中应用:
    • 《地铁:离去》(Metro Exodus)
    • 《阿凡达》(Avatar)
    • 《星球大战:亡命之徒》(Star Wars Outlaws)(均使用 Snowdrop 引擎)

本作的独特挑战

在上述技术基础上,需要解决:

  • 大型动态开放世界 的 GI 质量与性能
  • 场景中包含 大量植被 等复杂几何
  • 需在 多平台 上运行

算法流程详解

第一步:光栅化与直接光照

  1. 从摄像机视角 光栅化场景,构建 GBuffer
  2. 计算 直接光照(Direct Lighting)

目标:为每个像素计算 间接漫反射(Indirect Diffuse)间接镜面反射(Indirect Specular) 光照

第二步:逐像素方向采样

  • 对每个像素,根据 BRDF 随机选择一个采样方向
  • 分为 两个 Pass
    • 漫反射波瓣(Diffuse Lobe) Pass
    • 镜面反射波瓣(Specular Lobe) Pass
  • 然后沿选定方向 投射光线(Cast Ray)

第三步:屏幕空间光线步进(Screen Space Ray Marching)

在进行硬件光线追踪之前,首先执行屏幕空间光线步进,原因有三:

  1. 性能优势:在某些平台(如主机)上,光线步进比光线追踪 更快
  2. BVH 世界表示非常粗糙:为了速度,光线追踪的 加速结构(BVH) 并不包含场景中所有物体
  3. 避免自相交(Self-Intersection)补回缺失物体的信息:屏幕空间步进能提供 BVH 中缺失的几何信息

第四步:光线追踪回退(Ray Tracing Fallback)

  • 如果屏幕空间光线步进 未找到交点,则将光线投入 BVH 加速结构 中进行真正的光线追踪
  • 关键术语:BVH(Bounding Volume Hierarchy,层次包围盒) —— 光线追踪中用于加速光线-场景求交的空间数据结构

第五步:命中点着色

在光线步进或光线追踪找到交点后:

  • 计算该命中点的 直接光照,包括:
    • 太阳光(Sun Light)
    • 所有局部光源(Local Lights)

核心架构设计思路总结

设计要点说明
混合追踪策略屏幕空间步进优先 + BVH 光线追踪回退,兼顾性能与质量
逐像素双 Pass漫反射和镜面反射分开处理,各自独立采样方向
粗糙 BVH为性能考虑,BVH 不包含所有物体,靠屏幕空间补偿
Probe Volume 缓存用于多次弹射的间接光照,降低逐帧计算开销
高动态适配算法需应对时间、天气、季节的持续变化,不能依赖静态烘焙

演讲结构预告

演讲分为两大部分:

  1. 算法与实现深度解析(由 Luke 主讲)—— 即上述内容的展开
  2. 《刺客信条:影》特有的挑战、问题来源与解决方案(由 Millie 主讲)
  3. 最后讨论 性能、算法局限性 以及 未来工作计划

间接光照与探针体积(Indirect Illumination & Probe Volume)

命中点的间接漫反射计算

  • 在命中点处计算 间接漫反射光照(Indirect Diffuse) 时,依赖摄像机周围分布的 探针体积(Probe Volume)
  • 具体做法:选取距离命中点 最近的 8 个探针(8 Nearest Probes),对它们进行 插值,得到该点的间接漫反射光照值
  • 对所有像素执行上述流程后,会得到一个 带噪声的结果(Noisy Solution)
  • 最后通过 降噪(Denoise) 处理,得到最终的光照结果

探针体积的更新流程

探针体积需要在逐像素光线追踪之前完成计算,流程如下:

  1. 对探针体积中的 每个探针,向覆盖其球面所有方向 发射子光线(Cast Sub-rays)
  2. 在每条光线的命中位置,计算来自 所有光源的直接光照
  3. 然后计算该命中位置的 间接光照,此时同样使用探针体积——但使用的是 上一帧的探针结果(Last Frame's Probe Result),因为当前帧的探针正在计算中

这种 时序递归(Temporal Recursion) 的做法,实现了探针体积内的 多次弹射全局光照(Multi-bounce Global Illumination)

探针数据的卷积处理

完成所有探针的光照计算后,需要进行两种卷积:

卷积类型输出用途
辐射度缓存卷积(Radiance Cache Convolution)滤波后的辐射度缓存(Filtered Radiance Cache)当光线 未命中任何几何体 时,作为回退值(Fallback)
漫反射 BRDF 卷积(Diffuse BRDF Convolution)辐照度漫反射缓存(Irradiance Diffuse Cache)用于计算空间中 任意点的间接漫反射全局光照
  • 辐射度缓存的卷积 牺牲了一定精确性,换取更低的噪声和更稳定的结果

光线追踪场景定义(Ray Tracing Scene Definition)

设计原则:粗糙但快速

  • 光线追踪使用的场景描述是光栅化版本的 粗糙表示(Coarse Representation)
  • 核心目标:因为需要大量投射光线,所以场景描述必须尽可能 加速求交过程

几何简化策略

策略说明
使用低级别 LOD尽可能使用最低 LOD,在不产生 可见瑕疵(Visible Artifacts) 的前提下降低几何复杂度
不支持顶点动画蒙皮(Skinning) 支持,即 无角色、无运动中的植被
剔除小型几何尽量剔除 小型植被、小型杂物(Cluttering Objects)

三角形数据预烘焙(Baked Triangle Data)

  • 为了加速命中结果的获取,对三角形数据进行 预烘焙
  • 传统流程:先获取 顶点索引 → 再获取 顶点数据 → 插值
  • 优化后:直接获取 预烘焙的三角形数据,插值 UV 即可得到所有所需信息
  • 减少了间接内存访问(Indirect Memory Fetches),显著提升性能

材质系统(Material System)

统一材质描述(Unified Material Description)

  • 光栅化版本中,每种材质可拥有 各自的 Shader
  • 光线追踪版本中,采用 统一的材质描述(Unified Description)
  • 好处:可以使用 内联光线追踪(Inline Ray Tracing),在多平台上通常 性能更优

PBR 常量烘焙

  • 对每种材质,计算其 PBR 常量(PBR Constants)
  • 同时支持 Albedo 纹理Alpha 纹理 以提升质量

材质烘焙流程

烘焙流程如下:

  1. 遍历每个 PBR 参数的纹理,计算其 平均值(Average Value)
  2. 对于复杂材质(如 树木 Planner):
    • 先将材质结果 烘焙到一张纹理图集(Texture Atlas)
    • 再将该图集作为输入进行后续处理
    • 该纹理也可直接用于 Albedo 和 Roughness

Alpha 材质处理

  • 在计算均值时,需 考虑 Alpha 通道的权重
  • 还需为每个使用 Alpha 的 Mesh 计算一个 不透明度值(Opacity Value)
  • 计算方式:
    • 将 Mesh 的每个三角形 重投影到 Alpha 纹理
    • 对每个三角形内部的纹素取平均
    • 得到的 Opacity 参数后续用于 Alpha Test 材质的光线追踪

植被材质特殊处理

  • 支持 颜色查找表(Color LUT),根据 季节 定义不同颜色
  • 支持 双通道 Alpha 纹理
    • 一个通道:有叶子(With Leaf)
    • 另一个通道:无叶子(Without Leaf)
    • 根据当前季节选择正确的通道

BVH 更新机制

  • 每帧更新 BVH 加速结构
  • 更新过程简洁明了:
    • 根据 流式加载(Streaming) 状态和 摄像机位置添加或移除实例(Add/Remove Instances)
    • 确保 BVH 始终反映当前可见范围内的场景状态

BVH 场景动态更新(BVH Scene Update)

动态物体支持

  • 对场景中移动物体的 变换矩阵(Transformation Matrix) 进行逐帧更新
  • 支持 超级动态物体(Super Dynamic Objects),但 不支持顶点动画(Vertex Animation)(即无蒙皮角色、无植被摆动)

地形的特殊处理

  • 地形(Terrain) 是一个特殊案例,采用 分块(Patch) 方式管理
  • 根据摄像机位置,动态 添加/移除地形块
  • 地形的材质处理也不同:为每种 PBR 参数 单独使用一张 纹理图集(Texture Atlas)

实例剔除与时间切片

  • 根据摄像机视角进行 实例剔除(Instance Culling)
  • 场景中实例数量可能超过 10 万个,无法单帧全部更新
  • 因此采用 时间切片(Time Slicing) 策略:每帧只选择一个子集进行剔除更新
  • 完整场景更新大约需要 ~1 秒 完成一个完整周期

探针体积的数据结构与管理(Probe Volume Data)

探针网格结构

  • 使用标准的 多级联 3D 均匀网格(Cascaded 3D Uniform Grid),跟随摄像机移动
  • 《刺客信条:影》中共有 略超过 10,000 个探针

探针数据组成

每个探针包含以下数据:

数据类型说明
数据缓冲区(Data Buffer)存储光照相关信息
元数据(Metadata)包括世界偏移等辅助信息
世界偏移(World Offset)允许探针在其定义区域内移动,以找到 更优的渲染位置

探针数据存储格式

  • 探针数据存储在 纹理图集(Texture Atlas) 中,使用 八面体映射编码(Octahedral Encoding)
  • 存储流程:
    1. 保存压缩后的 GBuffer 信息
    2. 基于 GBuffer 计算 临时光照缓冲区(Temporary Lighting Buffer)
    3. 对光照缓冲区进行 卷积(Convolution),生成:
      • 可见性探针(Visibility Probe):用于计算探针插值权重
      • 滤波辐射度探针(Filtered Radiance Probe):滤波后的辐射度缓存
      • 辐照度探针(Irradiance Probe):用于间接漫反射计算

探针更新优化策略(Probe Update Optimization)

核心问题

  • 每帧更新所有 10,000+ 探针 成本过高
  • 需要通过多种优化手段降低开销

三种更新模式

更新模式内容特点
完整更新 - 全分辨率(Full Update, Full Resolution)投射光线计算 GBuffer → 计算光照 → 卷积结果 → 尝试重定位探针最高质量,开销最大
完整更新 - 四分之一分辨率(Full Update, Quarter Resolution)与上述相同,但 GBuffer 更新在 1/4 分辨率 下执行光线追踪部分获得 ~40% 加速
仅光照更新(Lighting Update Only)复用当前缓存的 GBuffer,仅重新计算光照开销最低,适合静态几何区域

探针选择的贪心算法(三步策略)

每帧有固定的 探针更新预算

  • 60fps 模式:约 1,000 个探针/帧
  • 低端平台(如 Xbox Series S):约 500 个探针/帧

第一步:新创建的探针(Newly Created Probes)

  • 当摄像机移动时,网格边界处会 新建探针,对侧旧探针被删除
  • 新建探针数量波动较大(0 ~ 500),为了 稳定帧时间,这些探针使用 完整更新 + 四分之一分辨率 模式

第二步:全分辨率轮转更新(Round-Robin Full Update)

  • 在每个级联(Cascade)中,按 轮转(Round-Robin) 方式选取一定数量的探针
  • 大约消耗剩余预算的 ~16%
  • 使用 完整更新 + 全分辨率 模式
  • 经过若干帧后,可以完成每个级联的 完整刷新

第三步:仅光照轮转更新(Round-Robin Lighting-Only Update)

  • 同样在每个级联中按轮转方式选取探针
  • 消耗 所有剩余预算
  • 使用 仅光照更新 模式
  • 当摄像机移动不大时,此步骤占据单帧预算的 80% ~ 84%

设计思路总结:通过三级优先级分配——新探针优先保证覆盖、全更新保证质量刷新、光照更新保证大面积时效性——在有限预算内最大化探针体积的整体质量和响应速度。

探针更新详细流程(Probe Update Pipeline Details)

元数据预处理(Metadata Pre-Update)

在对选中的探针执行任何光照计算之前,首先更新其 元数据(Metadata)

  • 室内/室外分类(Indoor / Outdoor Classification):判断探针处于室内还是室外(后续会用到)
  • 地形分类(Terrain Classification)
    • 如果探针 略低于地形表面,则将其 上移至地形之上
    • 如果探针 深埋于地形之下,则直接 禁用该探针

GBuffer 更新(Full GBuffer Update)

光线投射策略

  • 对选中的探针执行完整更新:向各方向 投射光线 以更新 GBuffer
  • 光线在 像素中心(Center of Pixel) 处追踪,没有抖动(No Jittering)没有时域累积(No Temporal Accumulation)
    • 原因:抖动和时域方法与 GBuffer 缓存方案不兼容

光线最大距离

  • 光线的 最大追踪距离 取决于探针所属 级联(Cascade)区域定义大小
    • 大级联 → 光线追踪 更远
    • 小级联 → 光线追踪 更短

命中处理

  • 命中几何体后,提取 所有材质信息 写入探针的 GBuffer
  • 同时记录 背面命中次数(Back-face Hit Count)
    • 在更新结束尝试 重定位探针(Relocate Probe) 时,如果无法找到合适位置且背面命中过多,则 禁用该探针

太阳阴影计算(Sun Shadow in GBuffer)

阴影写入 GBuffer

  • 在更新 GBuffer 的同时,计算太阳阴影并存入 GBuffer
  • 这是一种 近似做法:在两次 GBuffer 更新之间可能执行多次光照更新,期间太阳位置可能发生变化
  • 但根据探针选择算法,GBuffer 大约每 2 秒完整更新一次,而太阳在此期间移动不大,因此近似 足够精确,且带来显著 性能提升

阴影计算的分层策略

步骤方法条件
第一步查询摄像机附近的 阴影贴图(Shadow Map)命中点在阴影贴图范围内
第二步(回退)投射 阴影光线(Shadow Ray)命中点在阴影贴图范围外,且三角形 朝向太阳
第三步叠加 云层阴影(Cloud Shadow)始终执行

光照快速变化的探针重缩放(Probe Rescaling for Fast Sun Movement)

问题描述

  • 当太阳快速移动时(如快速时间过渡),每帧只更新少量探针会导致 明显的逐帧光照不一致,能清楚看到探针被分批更新的视觉瑕疵

解决方案:全局光照重缩放(Global Lighting Rescaling)

本帧未被重新计算 的探针进行光照缩放:

  1. 基于 太阳位置天空可见性(Sky Visibility),分别计算 上一帧当前帧 的光照近似值
  2. 取两者的 比值(Ratio) 作为 缩放因子(Scaling Factor)
  3. 用此缩放因子 调整未更新探针的光照

实现细节

  • 无需逐 Texel 缩放:每个探针只存储 一个缩放因子,应用于整个探针
  • 额外好处:缩放因子使每个探针处于 局部光照空间(Local Lighting Space)提升了存储精度

探针光照计算的双 Pass 策略(Split Lighting Computation)

架构设计

完成 GBuffer 更新(或复用缓存 GBuffer)后,对所有选中的探针计算光照。计算被分为 两个 Pass

Pass处理对象计算内容
Pass 1:命中几何光线 命中了几何体 的 Texel计算来自所有光源的 直接光照 + 使用 上一帧探针体积 计算 间接光照
Pass 2:未命中几何光线 未命中任何几何体 的 Texel优先使用 探针辐射度缓存(Probe Radiance Cache)(若光线终点在探针体积内);否则回退到 天空近似纹理(Sky Approximation Texture)

性能收益

  • 将命中/未命中拆分为两个 Pass,加上额外的 分类 Pass(Classification Pass),总共获得约 20% 的性能提升
  • 天空近似纹理 分辨率较小,精度有限,但作为最终回退已足够

探针光照输出与缩放因子(Probe Lighting Output & Rescaling)

双值输出策略

光照计算最终为每个探针输出 两个值

输出值用途
计算后的辐射度(Computed Radiance)用于后续卷积生成探针的平均辐射度
局部光源光照值(Local Light Value)卷积后得到平均局部光源照明强度
  • 卷积后得到的 平均辐射度平均局部光源照明 将被用于 缩放那些本帧未被重新计算的探针(即前文提到的 Rescaling 策略)

探针卷积流程(Probe Convolution Pipeline)

可见性卷积:方差阴影贴图(Variance Shadow Map)

  • 从探针的 深度缓冲区(Depth Buffer) 计算一张 方差阴影贴图(Variance Shadow Map, VSM)
  • 用途:在插值探针时计算 权重(Interpolation Weights),防止光照泄漏

关键技巧:重缩放与钳制顺序

  • 由于编码到 8 位精度,需要将数值 重缩放并钳制到 [0, 1] 范围
  • 关键点:重缩放和钳制操作 在计算平均深度和平均深度平方之前执行
  • 这种顺序有助于 减少某些场景下的光照泄漏(Light Leaking),例如 U 形房间的角落

辐射度与辐照度卷积

在可见性之外,还对探针执行:

  • 辐射度卷积 → 生成 滤波辐射度探针(Filtered Radiance Probe)
  • 辐照度卷积 → 生成 辐照度探针(Irradiance Probe)

卷积过程中计算的元数据

元数据用途
天空可见性(Sky Visibility)用于光照分类与缩放
平均局部光源亮度(Average Local Light Luminance)缩放因子的一部分
平均亮度(Average Luminance)作为探针的 缩放因子(Scaling Factor)

卷积 Shader 优化

线程组分配策略

  • 每个 线程组(Thread Group) 负责计算 一个探针 的卷积结果
  • 每个 线程(Thread) 负责计算输出探针的 一个像素

利用硬件双线性过滤加速

  1. 所有线程首先协作,将探针像素 加载到 LDS(Local Data Share / 共享内存)
  2. 加载时利用 硬件双线性过滤(Bilinear Filtering),一次采样获取 4 个纹素(Texel) 的平均值
  3. 然后对加载的值执行卷积

效果:需要卷积的纹素数量 减少为 1/4,该 Pass 获得约 4 倍加速

精度权衡

  • 这种做法并非完全精确——实际上是对 平均值 做卷积,而非对 每个纹素单独做卷积后再平均
  • 但差异 非常小,相比获得的性能提升,完全可以接受

探针重定位(Probe Relocation)

目的

探针更新的最后一步:将 嵌入几何体内部过于靠近几何表面 的探针移动到合适位置

重定位算法

  1. 检查探针的 深度缓冲区 中所有深度值
  2. 找到 最小深度(Min Depth)最大深度(Max Depth)
  3. 判断条件:
    • 如果最小深度 为负过小(说明探针嵌入或过于贴近几何体)
    • 则尝试沿 最大深度方向 移动探针
  4. 如果无法找到 足够远离几何体 的有效位置:
    • 禁用该探针(Disable),标记为无效

逐像素漫反射光照 Pass(Per-Pixel Diffuse Illumination Pass)

基本参数

参数设置
分辨率四分之一分辨率(Quarter Resolution)
光线方向余弦分布(Cosine Distribution) 中随机选取
最大追踪距离取决于光线起点离摄像机的距离:越远则追踪越远
  • 四分之一分辨率已足够产生良好质量,且获得 4 倍加速

光线求交的两阶段流程

阶段一:屏幕空间光线步进(Screen Space Ray Marching)

对每条光线先在当前屏幕空间中步进,结果分为三类:

结果处理可视化颜色
命中有效几何加入 有效命中列表(Valid Hit List)🟢 绿色像素
步进完整距离无命中加入 未命中列表(Miss List)🔵 蓝色像素
其他情况(不确定)需要进入第二阶段其余像素

阶段二:BVH 光线追踪(3D BVH Ray Casting)

对屏幕空间步进未能确定结果的像素,投射光线到 BVH 中:

  • 命中几何 → 加入有效命中列表(🟢),同时构建命中点的 GBuffer 信息(材质、法线、深度/距离等)
  • 未命中 → 加入未命中列表(🔵)

命中点光照计算(两个 Pass)

与探针光照类似,采用 双 Pass 结构。与探针流程的 主要差异 在于 太阳阴影的计算方式

太阳阴影分层策略(Per-Pixel 版本)

由于逐像素光线追踪是从 摄像机视角 发射光线,因此可以访问 级联阴影贴图(Cascaded Shadow Map, CSM)

优先级方法条件
第一优先级联阴影贴图(CSM)命中位置在屏幕上可见且在 CSM 范围内
第二优先(回退)围绕摄像机的辅助阴影贴图(Secondary Shadow Map)命中位置不在 CSM 可见范围内

这与探针中的阴影策略不同——探针先查摄像机附近的阴影贴图,然后回退到投射阴影光线;而逐像素 Pass 依赖 CSM 优先,辅助阴影贴图作为回退。

逐像素漫反射光照 Pass 详细流程

阴影处理的简化策略

  • 当命中点 落在阴影贴图范围之外 时:
    • 对于 漫反射情况,直接判定该点为 完全阴影(Fully Shadowed)
    • 这样做对最终光照效果 影响极小,且 不会产生漏光(Light Leaking)

命中几何体的光照计算

依次执行以下步骤:

  1. 计算阴影后,计算来自 太阳所有局部光源直接光照(Direct Lighting)
  2. 使用 辐照度探针体积(Irradiance Probe Volume) 计算 间接光照(Indirect Illumination)

未命中几何体的回退(Miss Pass)

对于未命中任何几何体的光线,处理流程与探针体积类似:

优先级回退方案条件
1辐射度探针体积(Radiance Probe Volume)命中位置在探针体积覆盖范围内
2天空近似纹理(Sky Approximation Texture)命中位置在探针体积范围外

输出编码:球谐函数(Spherical Harmonics)

与探针体积直接输出辐射度不同,逐像素 Pass 采用 球谐函数(Spherical Harmonics, SH) 编码输出:

  • 不直接输出辐射度,而是将其 编码为球谐系数
  • 目的:尝试 重建每像素的完整球面辐射度,后续再进行降噪和上采样
  • 这种方式能获得 显著更高的质量

额外输出:命中距离

  • 同时输出 命中距离(Hit Distance),也会被降噪和滤波
  • 命中距离的两大用途:
    • 生成 光线追踪环境光遮蔽(Ray Traced AO),后续与最终结果合成
    • 帮助 降噪器 决定:
      • 使用的 滤波核大小(Kernel Size)
      • 镜面反射光照的 重投影(Reprojection) 策略

降噪与上采样(Denoising & Upscaling)

降噪器

  • 使用 Snowdrop 引擎降噪器的修改版本,基于 NVIDIA 降噪器
  • 针对《刺客信条:影》做了额外修改(后续详述)
  • 核心架构:多 Pass 时域 + 空域滤波(Multi-pass Temporal & Spatial Filtering)

上采样流程

步骤说明
输入四分之一分辨率的 球谐系数
上采样算法双边上采样(Bilateral Upscaling)
权重依据深度(Depth)、法线(Normal)、材质(Material)
最终评估将上采样后的球谐系数与 全分辨率法线 进行求值,得到最终逐像素光照

球谐 vs 直接辐射度滤波的对比

方法效果
直接滤波辐射度细节丢失,方向性信息弱
滤波球谐系数后重建更多细节保留更好的光照方向性

球谐方法的核心优势:保留了光照的 方向信息(Directionality),在使用高分辨率法线求值时能恢复出更丰富的光照细节


间接镜面反射光照(Indirect Specular Illumination)

开发背景

  • 该功能 最初并未计划在本作中上线,而是计划用于后续游戏
  • 因项目延期,团队获得 额外 3 个月 来实现、调试并使其达到发行质量
  • 时间有限,且 无法修改已有数据
  • 因此主要聚焦于 质量正确性,优化工作相对有限

与漫反射 Pass 的异同

算法整体与漫反射逐像素 Pass 高度相似,但针对镜面反射增加了 特有处理

分辨率选项

分辨率模式说明
四分之一分辨率支持但非最终选择
半分辨率(Half Resolution)宽度减半,高度保持全分辨率
全分辨率支持

最终发行版选择 半分辨率,因其 质量-性能比最优

镜面反射的特化处理

采样方向选择

  • 使用 GGX 可见法线分布的重要性采样(Importance Sampling with GGX Visible Normal Distribution)
  • 而非漫反射中的余弦分布采样

光线长度自适应

粗糙度光线长度原因
高粗糙度短光线行为接近漫反射波瓣
低粗糙度(接近镜面)极长光线需要捕捉远处细节

性能优化:复用漫反射结果

  • 镜面反射至少投射 两倍数量的光线,性能开销约为漫反射的 两倍
  • 核心优化策略:复用漫反射 Pass 已计算的信息
    • 对于 粗糙度高于特定阈值 的像素,其镜面反射行为已接近漫反射
    • 直接复用该像素的 逐像素球谐系数,在 目标反射方向上求值 即可
    • 无需额外投射光线,大幅节省开销

间接镜面反射光照的优化与质量改进

低权重像素的加速策略

  • 当光线方向 远离完美镜面反射方向 时,该像素的 权重非常低
  • 此时直接使用 球谐函数求值(Spherical Harmonic Evaluation) 代替完整计算
  • 视觉差异 几乎不可察觉,但获得 20%~30% 的加速
  • 副作用:由于使用了更高质量的渲染,细节和瑕疵也更容易被看到

镜面反射中的瑕疵修复

核心问题

  • 在漫反射 Pass 中做的 大量近似 在漫反射结果中 不可见
  • 但在 高镜面反射材质(如水面反射)中,这些近似 开始显现为可见瑕疵
  • 因此需要逐一修复

修复项一:Alpha Test 材质

漫反射 Pass镜面反射 Pass
使用 近似 Alpha Test(更快)改用 真正的 Alpha 纹理测试(Alpha Texture Test)(更高质量)
  • 近似方案在反射中 清晰可见,必须替换

修复项二:材质定义的精度提升

  • BVH 中使用的材质定义 较为简化,对漫反射足够,但在 接近镜面反射 时能看出差异
  • 解决方案:屏幕空间重投影(Screen Reprojection)
    1. 每次光线命中 BVH 几何体后,将命中点 重投影到屏幕空间
    2. 如果重投影位置 有效且匹配,则用 GBuffer 中的高质量材质信息 替换 BVH 材质
    3. 由于两者差异不大,分界线几乎不可见,最终光照结果自然

修复项三:更复杂的光照计算

增加项说明
镜面反射 BRDF 求值在漫反射 Pass 中为提速被移除,镜面 Pass 中重新加入
阴影光线(Shadow Ray)当命中点 落在太阳阴影贴图范围外 时,投射阴影光线计算阴影——仅限 PC 平台

探针插值优化(Miss Pass)

问题

  • 探针插值成本 占光照评估总成本的约一半
  • 需要获取 8 个探针 的数据并计算权重,开销很大

单探针快速路径(Single Probe Shortcut)

1. 选取命中位置处的 最近探针(Nearest Probe)
2. 计算该探针的 权重(Weight)
3. if 权重足够高:
       → 仅使用该单个探针(快速路径)
   else:
       → 回退到完整的 8 探针插值
  • 效果:探针级联评估速度 提升约 2 倍

Miss Pass 的回退纹理升级

漫反射 Pass 的回退

  • 使用简单的 天空近似纹理(Sky Approximation Texture)

镜面反射 Pass 的升级

  • 替换为 完整的局部立方体贴图(Local Cubemap)
    • 跟随摄像机位置
    • 每帧更新
    • 包含内容:地形 + 天空 + 所有 BVH 外的远距离几何体

原因:在高反射表面上,远距离缺失几何体 非常明显。升级后的回退纹理提供了 更丰富的远景信息


雾效评估(Fog Evaluation)

漫反射 Pass镜面反射 Pass
雾效❌ 不计算(差异小,节省开销)✅ 计算雾效
  • 水面等体积反射场景 中差异极大
  • 加入雾效后 与场景整合度大幅提升
  • 演示对比:左侧无雾效 vs 右侧有雾效

镜面反射的降噪挑战(Specular Denoising)

核心难点

  • 镜面反射的滤波核 远小于漫反射
  • 结果 更难降噪
  • 需要额外技术辅助

BRDF 解调(BRDF Demodulation)

基于 NVIDIA NRD 文档 中描述的技术:

基本原理

  1. 计算辐射度时 不包含 BRDF 项
  2. 纯辐射度 进行滤波(避免 BRDF 引入的额外噪声)
  3. 滤波完成后,再乘以 预积分 BRDF(Pre-integrated BRDF) 恢复最终结果

问题:掠射角瑕疵

  • 这是屏幕空间追踪 + 预滤波局部 Cubemap 的标准做法
  • 但在 掠射角(Grazing Angle) 处会出现 可见瑕疵
  • (演示中正在展示该问题)

后续预计会讨论针对此掠射角问题的解决方案

镜面反射降噪的进一步改进

BRDF 解调的改进方案

问题

  • 简单的 BRDF 解调在某些情况下,当光照过强时会产生可见瑕疵(放大后尤为明显)

改进策略

步骤操作
1完整计算 辐射度 × BRDF 求值结果
2滤波前,将结果 除以预积分 BRDF(Pre-integrated BRDF)
3对除法后的结果执行 降噪滤波
4滤波完成后,乘回预积分 BRDF

核心思想:将 BRDF 引入的噪声在滤波前分离出去,滤波在更平滑的信号上执行,最终再恢复 BRDF 贡献。比纯解调方案效果更好。


亮度空间压缩降噪(Luminance Space Compression)

问题场景

  • 室内朝室外看时:部分光线命中 低照度的室内表面,部分光线命中 高照度的室外
  • 两者亮度 差异极大,导致 极度噪声,降噪器难以处理

解决方案:在压缩空间中降噪

  • 不在线性光照空间 中执行降噪
  • 先对亮度进行 非线性压缩,再执行降噪,降噪后再解压

压缩函数选择

方案评估
Reinhard Tone Mapping常用选择,但 过度压制眼部适应级别的亮度,损失太多中间调细节
幂函数(Power Function)最终采用,指数为 0.0625(即约 1/16 次方)

物理上不准确,但有效减少噪声,满足发行质量要求。


萤火虫去除(Firefly Removal)

  • 在降噪器的某个 已有的滤波 Pass 中集成(该 Pass 本身就遍历周围像素)

  • 算法:

    1. 在遍历邻域像素时,计算邻域平均亮度
    2. 将当前像素亮度与邻域平均亮度 比较
    3. 如果差异 过大,则 钳制(Clamp) 当前像素亮度至合理范围
  • 几乎 零额外开销(复用已有 Pass 的数据)


Alpha Test 材质的性能挑战(Alpha Tested Materials)

问题

  • Alpha Test 材质在光线追踪中 非常昂贵
  • 每次光线与 BVH 相交时,需要调用 Any Hit Shader 检查 Alpha 值

各方案对比

方案成本(相对参考)质量说明
参考方案(无限制 Any Hit)100%最高不限制 Any Hit 调用次数
限制 Any Hit 调用次数~85%有瑕疵简单但产生可见问题
进一步限制(N=2)更低较好用于 镜面反射 GI(其他方案瑕疵太明显)
蓝噪声抖动 + 平均不透明度无明显提升中等基于概率决定光线是否穿透;不限制时几乎无增益
不透明度近似(Opacity Approximation)~60%接近 N=2漫反射 GI 和屏幕空间阴影的最终方案

不透明度近似方案(Shipped Solution for Diffuse)

1. 根据网格的 平均不透明度(Average Opacity)缩放三角形
2. 仅使用 完全不透明的交叉测试(Fully Opaque Intersections)
3. 完全跳过 Any Hit Shader
  • 效果与 N=2 Alpha Test 限制 非常接近
  • 成本仅为参考方案的 约 60%

半透明材质的间接光照(Translucency)

问题

  • 缺少半透明材质的间接光照贡献会导致场景 明显偏暗
  • 引入半透明间接照明后,场景 亮度显著提升

实现方案

二次命中的直接光照(Direct Lighting on Secondary Hit)

  • 对命中点的 正面和背面 都评估直接光照
  • 将两者的贡献 加和

二次命中的间接光照(Indirect Lighting on Secondary Hit)

  • 同样需要评估正面和背面的辐射度
  • 优化:不执行两次独立的探针查询,而是:
    1. 查找 8 个最近探针
    2. 根据 正面/背面 对这 8 个探针进行 分类(Classification)
    3. 分别用对应的探针子集评估正面和背面辐射度

主光线命中表面的直接光照(Direct Lighting on Primary Hit)

  • 根据材质的 半透明度(Translucency) 调整选择 正面背面 的概率
  • 这改变了采样的 概率密度函数(PDF),需要相应 补偿(Accommodate)
采样概率调整:
  P(front face) = f(translucency)
  P(back face)  = 1 - P(front face)
  
最终贡献 = sample_value / adjusted_PDF

通过概率调整而非两次完整计算,在保持物理正确性的同时节省了开销。

半透明材质的球谐编码

球谐编码的法线翻转

  • 编码为球谐函数时,将采样方向 翻转为正面对齐(Front-face Aligned)
  • 确保球谐系数在后续求值时方向一致

光照泄漏问题与解决方案(Light Leaks)

光照泄漏是实时全局光照方案中的 已知经典问题。本作将泄漏来源分为 直接光照泄漏间接光照泄漏 两大类。


直接光照泄漏(Direct Illumination Leaks)

泄漏来源

来源说明
CSM 剔除优化屏幕上不可见或不产生可见阴影的物体 不被渲染到级联阴影贴图中
CSM 范围有限距离摄像机过远的物体 没有阴影信息
强偏置(Bias)《刺客信条:影》中墙壁非常薄,需要较大 Bias,易导致漏光

解决方案:二级阴影贴图(Secondary Shadow Map)

由于物体可能在屏幕遮挡区域中被从 CSM 剔除,引入一张 低分辨率补充阴影贴图

参数设置
分辨率1K × 1K
覆盖范围玩家周围约 64 米
分块分为 16 个 Tile
更新策略时间分片(Time-sliced),16 帧完成一轮更新
渲染内容始终渲染所有遮挡体(不做剔除优化)

二级阴影贴图的应用

  • 延迟光照(Deferred Lighting)阶段应用与 CSM 相同的 Bias
  • 对探针执行 Min Gather,进一步压制阴影泄漏
  • 双重范围外的回退策略:如果命中点同时在 CSM 和二级阴影贴图范围外,直接判定为 阴影状态,减少探针漏光

镜面反射中的副作用

  • 反射中可能出现 屏幕外物体被错误判定为阴影 的情况
  • PC 高质量模式 的解决方案:在光线追踪 Pass 中启用 阴影光线投射(Shadow Ray Cast) 缓解此问题

间接光照泄漏(Indirect Illumination Leaks)

核心问题

  • 二次命中点周围使用 8 个探针插值
  • 某些 室外探针 亮度远高于室内,即使权重较低仍会 泄漏大量光照到室内
  • 权重系统 无法充分补偿 室内外巨大的亮度差异

探针查询的偏移策略(Query Position Offsets)

在探针过滤时,对查询位置进行三种 经典偏移

偏移类型说明
视线方向偏移(View Direction Offset)沿视线方向偏移查询点
采样方向偏移(Sampling Direction Offset)沿采样方向偏移
反向光线方向偏移(Inverse Ray Direction Offset)沿光线反方向偏移
  • 所有偏移量 限制在光线追踪距离的一半以内

探针权重计算(Probe Weighting)

步骤方法
1. 方向权重使用 Wrap Shading 计算方向性权重
2. 可见性权重评估探针的 方差阴影贴图(VSM)
3. 权重压制对小于 0.2 的权重进行 平方压制(Crush),增强遮挡效果
4. 三线性插值权重最终乘以 三线性插值权重(Trilinear Interpolation Weight)

问题:可见性测试 精度不够,室外探针亮度远超室内,仍然产生泄漏


室内体积分类(Indoor Volume Classification)

利用游戏中已有的 室内体积(Indoor Volumes)(原用于烘焙方案):

用途说明
室内/室外分类将二次命中点和探针分别标记为 室内(Indoor)室外(Outdoor)
地下区域识别标识地形下方需要 保持有效 的区域(如地下室、隧道)
GI 遮挡器(GI Blockers)洞穴 等极低照度区域添加额外遮挡,阻止天空光泄漏(此场景中更为关键)

探针环境光遮蔽(Probe AO)

作为最终的遮挡补偿步骤:

目的

  • 表示 探针覆盖范围内缺失的遮挡信息
  • 当光线追踪距离 小于探针网格间距 时,存在遮挡信息缺失

算法

if hit_distance < grid_spacing:
    occlusion_scale = hit_distance / grid_spacing
    // 按比例缩放遮挡贡献
else:
    // 无需额外遮挡补偿
  • 考虑 网格间距(Grid Spacing),根据命中距离与间距的比值进行缩放
  • 补偿探针在近距离范围内 无法捕获的细节遮挡

光照泄漏解决方案总结

直接光照泄漏
├── 二级阴影贴图(1K×1K, 64m, 16-tile time-sliced)
├── 探针 Min Gather 压制
├── CSM + 二级阴影贴图范围外 → 默认阴影
└── PC 高质量:阴影光线投射

间接光照泄漏
├── 查询位置三重偏移(View / Sample / Inverse Ray)
├── 权重计算(方向 × VSM × 压制 × 三线性)
├── 室内体积分类(Indoor / Outdoor / Underground)
├── GI Blockers(洞穴等关键区域)
└── Probe AO(近距离遮挡补偿)

遮蔽处理(Occlusion)

多层遮蔽合成流程

遮蔽效果通过 多个 Pass 逐层叠加 构建最终结果:

层级Pass说明
1镜面反射球谐结果前文 Luke 展示的基础间接光照
2探针 AO(Probe AO)影响 树木和树冠(Canopies) 等大尺度遮蔽
3光线追踪环境光遮蔽(Ray Traced AO)类似 SSAO,由美术驱动调参(Artistically Driven)
4GTAO(Ground Truth Ambient Occlusion)参数化用于恢复 微观细节(Micro Details),特别是 BVH 中缺失物体(如角色、地面杂物)的遮蔽

最终效果:基础球谐光照 → 加入探针 AO → 加入光追 AO → 加入 GTAO → 完整遮蔽结果


降噪的特殊挑战与解决方案(Denoising Challenges)

半透明材质的降噪问题

  • 问题:同一物体上部分区域半透明、部分不透明时,半透明区域会 向自身泄漏光照
  • 解决方案:添加 半透明遮罩(Translucency Mask) 用于降噪分类

角色与植被的降噪遮罩

  • 角色和植被在 无限距离追踪 时产生大量噪声
  • 添加 角色/植被遮罩(Character & Vegetation Mask) 辅助降噪

室内场景的高噪声问题

问题

  • 室内场景 依然非常嘈杂

解决方案:探针辐射度缓存回退(Probe Radiance Cache Fallback)

1. 追踪较短光线(Short Rays)
2. 更早回退到辐射度缓存(Radiance Cache)
3. 缓存已滤波且时域稳定
优势劣势
性能提升引入更多 光照泄漏
减少高频细节噪声精度降低
时域稳定性大幅提升

本质上是 精度与噪声之间的权衡

去遮蔽(Disocclusion)处理

尝试方案结果
直接使用最近探针的 GI(ProbeGI)产生太多瑕疵,未采用
额外空间滤波 Pass使用 Poisson 滤波器,8 或 16 个采样点,用于去遮蔽像素

植被特殊处理

  • 移除法线权重贡献:去遮蔽时植被不使用法线作为滤波权重
  • 放松时域重投影标准:对运动植被使用更宽松的重投影匹配条件

植被去遮蔽仍然是 最嘈杂的场景,团队计划未来继续改进


性能数据(Performance)

场景复杂度(典型城市场景)

指标数值
BLAS 物体数~2,000
TLAS 实例数~30,000
GPU 加速结构内存~320 MB

探针内存

指标数值
探针数量~10,000
内存占用~73 MB

各平台计时

测试场景:大阪城的特定视角

说明详情
异步计算展示了 Pass 在 异步线程(Async Thread)图形线程(Graphics Thread) 上的分布
无异步模式橙色数据为所有 Pass 线性执行 时的耗时

各平台特殊设置

平台特殊处理
Xbox Series S每帧更新的探针数量 减半;漫反射 GI 使用 更低分辨率
PC每帧更新探针数量也 减半(因更高帧率)
镜面反射 GI仅在 PS5 Pro 和 PC 上发售,耗时仍然很高(优化时间不足)

当前方案的局限性(Limitations)

工程与生产层面

局限说明
维护两套 GI 系统非常耗时
双重美术调参需要为两套系统分别调整对比度和 GI 效果,成本极高
材质重追踪(Retracing Materials)简化复杂着色器的工作量巨大
BVH 外物体缺失 AO非常明显,不得不用 GTAO 等方案补偿
BVH 质量固定近处和远处物体在光追世界中质量相同,无 LOD 概念
缺少 3D 运动向量导致 更多去遮蔽问题

算法层面

局限说明
探针网格分辨率固定增加分辨率/减小间距可提升细节,但在均匀分布的级联中 扩展性差
探针插值始终泄漏方差阴影贴图的可见性测试 精度不足,无法完全防止泄漏
屏幕追踪优化的副作用光栅化世界与 BVH 几何体 差异过大 时(某些情况下 50cm 阈值不够)
复杂场景仍然嘈杂城堡地下室中不得不 移除室内体积分类,宁可接受泄漏也不要噪声和时域错误
双重上采样的累积损失GI 先滤波上采样一次,再经最终上采样器(如 TSR/FSR)二次上采样,噪声问题被放大

未来工作(Future Work)

降低生产支持负担

目标计划
简化光追发行流程降低使用光追的门槛
自动化 BVH 构建减少手动标记和调整
淘汰烘焙 GI 遗留技术最终统一为单一光追 GI 方案
扩展到低端平台Xbox Series S 性能已在可发行范围,但 内存规划未为此优化

噪声与泄漏改进

方向说明
重要性采样(Importance Sampling)减少噪声、提升收敛速度
表面生成探针(Surface-generated Probes)在几何表面上放置探针,而非均匀网格
稀疏级联(Sparse Cascades)提升探针分布的灵活性

降噪器优化

  • 当前降噪 Pass 占总耗时近一半
  • 计划 显著降低降噪成本

总结

本次演讲完整展示了《刺客信条:影》从 烘焙 GI 向全光线追踪 GI 过渡 的技术路线:

  1. 探针体积系统(Probe Volume):多级联、时间分片更新、优化的卷积与插值
  2. 逐像素漫反射 GI:四分之一分辨率、球谐编码、高效降噪
  3. 逐像素镜面反射 GI:更高质量的材质/光照/雾效计算
  4. 多层遮蔽合成:探针 AO + 光追 AO + GTAO
  5. 防泄漏体系:二级阴影贴图、室内体积分类、探针权重压制
  6. 降噪体系:亮度空间压缩、BRDF 解调改进、萤火虫去除、特殊材质遮罩
  7. 平台适配:异步计算、分辨率/更新频率分级

核心权衡始终围绕 精度 vs 噪声 vs 性能 vs 泄漏 四个维度展开,团队在有限时间内做出了务实的工程决策。