MegaLights: Stochastic Direct Lighting in Unreal Engine 5

MegaLights: Stochastic Direct Lighting in Unreal Engine 5 - SIGGRAPH 2025

游戏光照面临的挑战与目标

游戏对光照质量的需求不断攀升

  • 希望使用 更多的光源,且所有光源都是 全动态的、投射阴影的
  • 希望使用 面光源(Area Lights) 并产生漂亮的 软阴影
  • 希望使用更复杂的 BRDF 与材质分层(Material Layering)——甚至仅仅是 无阴影的光照计算 本身就可能变得过于昂贵
  • 游戏复杂度持续增长,当前阶段 工作流(Workflow)已成为游戏画面的主要瓶颈——美术应该能够自由地、不受限制地工作(例如截图中程序化放置了大量灯光的场景)

核心设计目标

  • 这套方案需要成为 基线光照方法(Baseline Lighting Method),即制作团队可以将其作为 默认目标方案,而不是一个"额外的高端选项"
  • 最低要求:必须在 主机(Console)中端 PC 上可用

现有直接光照方案的局限性

方案一:传统的前向/延迟光照(Forward / Deferred Lighting)

  • 流程:对每盏灯 → 预计算 Shadow Map(或光追阴影 + 降噪得到 Shadow Mask)→ 将阴影项乘以预积分的光照辐照度
  • 优点:对 少量光源 效果很好
  • 缺点:光源数量增多后 开销线性增长,无法承受

关键问题:大量无用计算

  • 演讲者展示了一个像素的例子:
    • 该像素处于 50 盏灯的衰减范围 内 → 需要预计算 50 张 Shadow Map
    • 但实际上只有 15 盏灯可见(未被遮挡)→ 大量计算被浪费
    • 即使只看可见的 15 盏灯,80% 的能量仅来自 1 盏灯 → 完全没必要精确计算全部 50 盏灯
  • 启示:只需对最重要的 1 盏灯做全质量计算,其余做 近似 即可

方案二:BRDF 采样(将直接光照当作 GI 问题处理)

  • 常见的 UE 工作流 Workaround:美术放置 自发光网格(Emissive Mesh),从主视图中隐藏,用作 软面光源,由 GI 系统免费处理
  • 优点:不需要额外开销,因为 GI 本来就要计算
  • 缺点
    1. 即使有 GI 引导,BRDF 采样仍然很难找到小型或远距离的发光表面
    2. GI 本身已经很难——即使在离线渲染中,也常用"在窗户内放灯"这种 trick 来加速收敛。而游戏中的 GI 要在主机上 60Hz 运行,再加上直接光照问题会让情况雪上加霜

方案三:随机光线追踪固定数量的光源(Stochastic Approach)

  • 核心思路:随机选择一部分光源 → 追踪 固定数量 的光线 → 命中光源则累积能量到单个 Render Target → 追踪完成后对该 Render Target 做 降噪(Denoise)
  • 优点开销与场景光源数量无关,始终是固定工作量,扩展性极好
  • 缺点/难点
    • 在主机上每像素可能 只能追踪约 1 条光线,因此 光源选择(Light Selection) 变得极其关键
    • 示例:如果 2 条光线都追踪到了被遮挡的光源 → 整个追踪预算被浪费,什么都没计算到

光源选择策略的分析

方法一:光源层级结构(Light Hierarchies)

  • 将所有光源放入某种 层级结构 中,尝试找到"最有意义的光源簇(Cluster)"
  • 核心问题不考虑遮挡项(Shadowing Term),而如前所述遮挡信息非常关键

方法二:ReSTIR(Reservoir-based Spatiotemporal Importance Resampling)

  • 在高端 PC GPU 上已展示出惊人效果
  • 关键问题:能否缩放到主机/中端设备?

ReSTIR 的工作原理

ReSTIR 在随机直接光照管线中注入三个主要模块:

  1. 重用(Reuse):从 历史帧(Temporal History)空间邻域(Spatial Neighbors) 中抓取样本
  2. 可见性验证:追踪光线检查这些重用样本的 可见性(Visibility)
  3. 组合:将重用样本与新的随机候选光源 合并
  • 核心理念:如果当前帧随机选的光源很糟糕(都被遮挡了),大概率能从历史帧或邻居像素中 找到更好的样本

ReSTIR 在主机上的问题

  1. 高常数开销

    • 不仅是重用操作本身的开销
    • 最关键的是额外光线追踪的开销——每个重用样本都需要验证可见性
    • 要获得合理质量至少需要 每像素 1 个样本,这意味着需要追踪 2-3 条光线/像素
    • 但主机上只能承受 约 1 条光线/像素
  2. 候选采样(Candidate Sampling)问题

    • 理论上可以随机选一盏灯就完事,但实际上需要:
      • BRDF 对每盏灯加权
      • 至少检查 20% 的光源列表
    • 在高端 PC 上这不算什么,但在主机上 → 相当于对场景中 20% 的光源做无阴影光照评估,开销很大
    • 更严重的问题:如果存在很强但被遮挡的光源,BRDF 加权会让系统不断往这些光源追踪光线 → 更难找到真正可见的高质量候选样本
  3. 结论:ReSTIR 已经超出了主机预算,而且仍然需要解决非常相似的光源采样问题

ReSTIR 的质量问题:样本相关性

  • 一个关键发现:有时 简单的随机采样(无重用)反而比 ReSTIR 看起来更好
  • 原因:ReSTIR 从历史帧重用"好的离散样本",但这会导致 样本相关性(Sample Correlation)
  • 输出结果中会出现 样本聚团(Clumps of Samples)——这些聚团对 降噪器来说非常难处理
  • 这是一个基本性的质量限制:重用带来了信息增益,但同时破坏了样本的统计独立性

阶段性总结

方案扩展性主机可行性核心问题
延迟光照❌ 线性增长✅ 少量光源时光源多时大量无用计算
BRDF 采样 (GI)难以找到小/远发光面;给 GI 额外增加负担
固定光线随机追踪✅ 开销固定光源选择极其关键,1 条光线/像素容错率极低
ReSTIR❌ 超预算额外光线追踪开销 + 候选采样开销 + 样本相关性

Epic 的新方案目标:在不使用 ReSTIR 重用机制的前提下,找到一种更适合主机的随机直接光照方法,解决光源选择问题并保持降噪友好的样本分布。

核心系统设计:可见光列表(Visible Light List)


核心思想:每像素维护一个"可见光列表"

理想目标

  • 理想情况下,希望为 每个像素 维护一个 可见光列表(Visible Light List)
  • 每帧可以从列表中 选取不同的光源,生成漂亮的 交错采样模式(Interleaved Patterns),这种模式对 降噪器非常友好
  • 关键约束:列表中必须是 可见光源——朝被遮挡的光源追踪光线是浪费的,它们不会对最终像素产生贡献
  • 时间一致性假设:上一帧可见的光源,本帧大概率仍然可见,因此可以利用 历史帧数据 来构建此列表

实际做法:8×8 屏幕空间瓦片(Screen Space Tiles)

  • 逐像素存储光列表 数据量太大,不现实
  • 折中方案:以 8×8 像素的瓦片 粒度存储可见光列表
  • 采样时:将当前像素 重投影(Reproject) 到上一帧,从对应瓦片的列表中 选取光源

瓦片边界不连续性处理

  • 8×8 瓦片较大,相邻瓦片之间可能发生 光列表突变,导致视觉上的 不连续性
  • 解决方案:使用 随机双线性查找(Stochastic Bilinear Lookup) 来平滑过渡,隐藏瓦片边界

隐藏光源的探索策略

为什么需要探索隐藏光源?

  • 场景是 动态的,之前被遮挡的光源可能 随时变为可见
  • 如果只采样可见光列表,永远无法发现新的可见光源

20% 预算分配策略

  • 将采样预算的 20% 分配给 检查隐藏光源
  • 实现方式
    1. 分别 对隐藏光列表和可见光列表进行采样
    2. 在合并之前,将隐藏光源样本的权重 钳制(Clamp) 到总权重的 20%
  • 为什么不用降权(Downweighting)? 降权方式下,如果存在一个非常强但被遮挡的光源,可能仍然吸引过多光线。而钳制方式可以 保证 最多只有 20% 的光线追踪预算投向隐藏光源

重投影失败的处理

  • 当历史重投影 失败 时(例如重投影后超出屏幕范围,或深度测试不通过):
    • 仍然使用最近的可见光列表(大概率包含有用光源)
    • 但将隐藏光源的采样比例 提升到 50%,以加速新可见光源的发现

新管线概览

  • 整体管线与之前类似,新增一个 橙色模块:负责为每个 8×8 屏幕空间瓦片 构建可见光列表
  • 后续采样阶段利用此列表 引导光线方向
  • 优势
    • 构建列表 开销很低
    • 绝大多数追踪的光线 真正贡献到最终像素
    • 光列表可用于生成 降噪器友好的采样模式

光源选择算法:加权水库采样(Weighted Reservoir Sampling)

基本原理

  • 一种非常简单的算法:只需遍历所有光源一次,就能根据权重 随机选出一个光源
  • 权重函数:每个光源的权重 = BRDF 的亮度值(Volumetric Luminance of BRDF)
  • 额外应用 对数变换(Logarithm)感知加权(Perceptual Weighting)
    • 原因:如果某盏灯极其强烈,经过 色调映射(Tone Mapping) 后,它对最终像素的实际视觉影响并没有那么大;对数加权能更好地反映人眼感知

蓝噪声优化:STBN(Spatiotemporal Blue Noise)

  • 为了生成降噪器友好的采样模式,使用 时空蓝噪声(STBN)
  • 问题:STBN 为每像素预计算 一个随机变量,但光源选择的水库采样循环中需要 多个随机变量

随机变量复用技巧

单光线情况:范围回映射(Range Warping)

  • 每次水库采样迭代后,将已选范围 重新映射回 [0, 1]
  • 这样一个随机变量就可以在整个循环中 反复使用

多光线情况:分段采样(Dithered Sampling / Segment Remapping)

  • 如果需要每像素追踪 多条光线,则将随机变量 分割成多个区间段
  • 每条光线使用各自的区间

关键收益

  • 使用 单个随机变量 完成所有光源采样
  • 保持 STBN 的蓝噪声特性 不被破坏
  • 获得 显著的质量提升,且无额外计算或光线追踪开销

实际场景中的光源遍历策略

不能真的遍历所有光源

  • 真实场景中,一个 Light Grid Cell 内可能有 数百盏灯,逐一遍历不现实

两阶段策略

  1. 检查可见光列表中的所有光源:它们大概率仍然可见
  2. 从 Light Grid Cell 中采样部分光源:每个像素检查 不同的子集
    • 这种做法 相干性较差(Incoherent),对 GPU 性能不太友好
    • 但好处是能 快速发现新的可见光源

计算优化

  • 标量化计算:由于只需要 BRDF 的亮度值作为权重,不需要完整的 RGB 计算,可以只做标量运算,节省 VGPR(向量通用寄存器)
  • 阈值剔除:权重低于某个阈值的光源 直接丢弃
    • 这不是性能优化,而是 质量优化
    • 原因:如果一盏灯太弱、无法影响最终像素,那就没必要检查它的可见性,应该把这条光线分配给更重要的光源

降分辨率采样(Lower Resolution Sampling)

依据

  • 相邻像素如果 深度和法线相似,那么光源权重通常也 非常相近
  • 因此可以 降低采样分辨率

具体做法

  • 例如:不再每像素选 1 盏灯,而是 每 4 个像素选 4 盏灯(共享采样结果)
  • 采样模式必须精心设计
    • 使用 棋盘格(Checkerboard)叉形模式(Fork Pattern)
    • 空间和时间 上都施加 抖动(Jitter),最大化重建成功率

重建方法

  • 随机双线性上采样(Stochastic Bilinear Upsampling),结合 深度和法线权重 进行加权
  • 如果 本帧无法成功重建:直接 复用历史帧数据不做任何历史矫正(无邻域钳制等操作)

整体效果

  • 有时会让阴影 稍微变软
  • 采样速度提升 4 倍
  • 实践中通常是 非常划算的折中

方向光的特殊处理

问题

  • 方向光(Directional Light)通常比任何局部光源 强数千倍
  • 如果按 BRDF 加权采样,几乎所有光线都会被分配给方向光,局部光源被饿死

常见方案(但不够好)

  • 将方向光从随机光照采样中 剥离,单独运行一个 光追阴影 Pass
  • 缺点:需要每像素额外追踪一条光线 + 额外的降噪 Pass,开销显著

本方案的做法

  • 限制方向光最多占 50% 的采样预算
  • 当局部光源 较暗或不存在 时,放松此限制,允许所有光线都追踪方向光
  • 这样在 不增加额外 Pass 的前提下,方向光和局部光源可以 共存于同一个随机采样管线

面光源的特殊处理

问题

  • 面光源(Area Light)可能 体积很大
  • 简单的 二值可见性 不够用:光源的一大部分可能被遮挡,如果光线恰好追踪到被遮挡区域,就会浪费预算

解决方案:2×2 位掩码(Bit Mask)

  • 为每盏面光源维护一个 2×2 的位掩码,跟踪光源 哪些部分可见
  • 此掩码与可见光列表 一起构建
  • 采样流程
    1. 先为每像素 选择一盏灯
    2. 再为该灯 选择光源表面上的具体点
    3. 在选择具体点时,降低被遮挡部分的权重,引导更多光线到 可见部分
  • 同样使用 STBN + 样本映射(Sample Warping),但采用适用于 2D 点 的变体

着色阶段(Shading)

流程

  1. 累积所有可见样本的权重:收集影响给定像素的所有可见光样本的权重之和
  2. 乘以预积分的光照辐照度(Pre-integrated Light Irradiance)

着色-阴影分离的折中

  • 此方法假设 着色(Shading)与阴影(Shadowing)可以分离
  • 这是一个 近似,会在某些极端情况下不完全正确

优势

  • 减少噪声
  • 向后兼容性:随机光照模式下的光源外观与 非随机模式完全一致
    • 这对于在现有项目中无缝启用此功能至关重要
  • 不是根本性限制,只是一个 特定的工程折中

着色后的降噪与滤波(Denoising)


整体降噪架构

  • 即使仅靠 随机光照采样 + 光源选择(SR),画面已经相当不错,但部分区域仍需 专门的降噪处理
  • 所有光源的结果合并后,使用 单个降噪 Pass 统一处理
  • 降噪分别运行在 漫反射(Diffuse)镜面反射(Specular) 两个独立信号上
  • 两个信号都经过 解调(Demodulation):即移除 非随机性的材质属性(如纹理 Albedo),避免降噪器模糊掉材质纹理细节

降噪核心思想:基于时序方差的自适应滤波

  • 降噪算法基于 追踪时序方差(Temporal Variance Tracking),该思路源自 SVGF(Spatiotemporal Variance-Guided Filtering)
  • 核心逻辑:时序方差告诉我们 某个像素有多"噪",从而决定需要对其施加 多大的空间滤波核

时序滤波(Temporal Filter)

数据存储

  • 将历史帧 重投影(Reproject),累积 光照值光照矩(Lighting Moments)
  • 光照值存储在 两个 32-bit 格式 中(实际实现为 4×2-bit 的紧凑格式),这得益于 随机浮点量化(Stochastic Float Quantization) 技术
  • 额外存储 第一矩和第二矩,但仅针对 漫反射亮度(Luminance of Diffuse)镜面反射亮度(Luminance of Specular)
  • 利用这两个矩可以 重建时序方差

邻域钳制(Neighborhood Clamp)

  • 使用较宽的 5×5 邻域钳制
  • 实现方式:先将数据 加载并打包到 Group Shared Memory 中,再从共享内存执行 方差裁剪(Variance Clipping)

两个关键技巧

  1. 基于距离的历史权重衰减

    • 如果当前帧新数据 与历史值距离很远(远离邻域边界),则 大幅降低历史权重
    • 目的:快速丢弃不可靠的历史数据,消除鬼影(Ghosting)
  2. 降采样重建像素的宽松钳制

    • 在降采样过程中,部分像素是 重建出来的(而非直接采样)
    • 对这些重建样本,适当放宽邻域钳制的范围,避免过度约束

空间滤波(Spatial Filter)

与标准做法的差异

  • 不使用 传统的 多 Pass À-Trous 小波滤波(开销太大,不适合此场景)
  • 改用 单 Pass + 单个稀疏核(Single Sparse Kernel),该核 逐像素旋转
  • 此方法与 TSR(Temporal Super Resolution) 配合良好,TSR 可以进一步清理残留噪声

自适应应用

  • 仅在高相对方差的像素上 应用空间滤波核
  • 双重收益
    1. 提升性能:不必要的像素跳过滤波
    2. 保持锐度:低噪声像素不被模糊

边缘停止函数(Edge-Stopping Functions)

  • 使用标准的 边缘停止函数,防止跨越不相关材质的模糊

遮挡与 Firefly 处理

色调映射空间累积

  • 为处理 遮挡导致的能量突变,在 色调映射空间(Tone Map Space) 中进行累积
  • 作用:有效 消除萤火虫(Fireflies) 现象(极亮的异常像素点)

自适应衰减策略

  • 初始阶段还会 增加空间采样数量
  • 随着历史数据累积充足,逐渐淡出 色调映射和额外采样——即系统在收敛后自动减轻滤波强度

降噪与时序上采样的分辨率冲突

问题描述

  • 降噪器渲染分辨率(Render Resolution) 下累积历史
  • 时序上采样(Temporal Upsampling / TSR)显示分辨率(Display Resolution) 下累积——远高于渲染分辨率
  • 这意味着降噪历史中的 一个像素 对应上采样后的 一组像素
  • 两难选择
    • 混合不相关像素 → 光照变得 模糊
    • 每帧丢弃历史 → 结果充满 噪声

解决方案:基于能量覆盖率的自适应旁路

  • 核心观察:如前所述,大部分能量往往来自 1~2 盏光源
    • 例如:80% 的能量来自 1 盏灯,且本帧 成功采样到了该光源 → 该像素 其实并不太噪
    • 此时可以 直接将信号传递给 TSR,完全跳过降噪

启发式判断方法

  • 可见光列表 提供了像素 可接收的总能量
  • 当前帧的采样结果提供了 实际成功采样到的能量
  • 计算 已采样能量占总能量的比例
    • 比例高 → 减少降噪强度 甚至 完全绕过降噪器,直接交给 TSR
    • 比例低 → 正常降噪流程

稳定性处理

  • 该启发式判断本身可能 有少许噪声
  • 在其上施加一层 时序稳定化(Temporal Stabilization) 即可
  • 整体效果非常好:启用此机制后,画面 明显更加锐利(Much Sharper)

可见性计算与光线追踪机制(Visibility & Ray Tracing)


为什么使用硬件光线追踪而非 Shadow Map

  • 主要可见性计算方法是 硬件光线追踪(Hardware Ray Tracing)
  • 核心优势:避免了为每帧维护和渲染 大量 Shadow Map 的开销——当光源数量庞大时,传统 Shadow Map 方案的开销尤其严重

BVH 表示的挑战

无法直接使用完整细节几何体

  • 内存开销:BVH 中每个顶点都有较高的 内存消耗
  • Nanite 游戏的特殊问题:使用 Nanite 的游戏倾向于使用 高精度网格,导致 BVH 构建和追踪 过于昂贵
  • Kit-Bashing 环境:大量实例 重叠(Instance Overlap) 进一步增加追踪成本

解决方案:分层简化表示

必须使用 简化代理网格(Proxy Meshes)激进的实例剔除(Instance Culling) 以及 聚合表示(Aggregate Representations) 来降低光追复杂度。


双层光线追踪结构

近场(Near Field):代理网格

  • 覆盖范围:玩家摄像机周围 150 米
  • 使用 低多边形代理网格,在 性能与精度 之间取得平衡
  • 适用于 近距离追踪

远场(Far Field):聚合简化表示

  • 当光线未命中近场网格并 超出近场半径 时,继续追踪远场
  • 远场表示会 合并实例大幅减少三角形数量
  • 存储在 独立的 TLAS(Top-Level Acceleration Structure)
    • BVH 复杂度更低 → 追踪更快
    • 默认使用 Inline Ray Tracing,在当前一代主机上性能更好

代理网格的核心问题:几何不匹配(Geometry Mismatch)

问题描述

  • 代理网格与光栅化几何体之间存在 不匹配
  • 光线从 光栅化表面 出发,可能 立即与代理网格三角形相交,导致 错误的自阴影(Self-Shadowing)

具体案例

  1. 曲面细分(Tessellation)网格:墙壁使用曲面细分,光追中无法高效表示 → 墙面出现错误阴影
  2. 地板不匹配:代理网格与地板光栅化几何体偏差 → 额外自阴影
  3. 布料模拟网格:玩家角色的模拟布料在光追中表示不佳 → 角色阴影错误
  4. 动画与 Alpha Mask 几何体:在光追中表示和追踪都 非常昂贵

为什么不能用面剔除解决?

  • 背面剔除(Back Face Culling):在某些简单情况下可以防止错误遮挡
  • 但实际中:光线可能同时命中 正面(Front Face),此时仍会产生错误阴影
  • 额外代价:启用正面或背面剔除会 增加约 10% 的追踪开销,因为阻止了 BVH 遍历中的 提前退出(Early Exit)

解决方案一:屏幕空间光线追踪(Screen Space Ray Tracing)

核心思路

  • 先在 屏幕空间 追踪光线(使用光栅化的 深度缓冲区
  • 由于屏幕光线是基于光栅化几何体的,可以 安全地离开表面,不会错误地与代理网格相交
  • 然后根据屏幕追踪的距离,偏移世界空间光线的起点 → 避免大部分自阴影问题
  • 额外收益:获得 BVH 中未表示的物体的 接触阴影(Contact Shadows)

关键技术细节

HZB 追踪(Hierarchical Z-Buffer Tracing)

  • 与典型接触阴影不同,这里需要 像素精确的屏幕追踪,不能用少量固定步进
  • 原因
    • 光线长度在 世界空间 中定义,某些情况下需要追踪 整个屏幕宽度
    • 固定步进太贵
  • 使用 HZB(Hierarchical Z-Buffer)追踪 快速但精确地 跳过空白区域

表面厚度策略

  • 默认采用 非常保守的低表面厚度
  • 当光线穿过表面背后时,不假设存在交点,而是回退到 硬件光追
  • 目的:尽可能避免典型屏幕空间追踪伪影

深度缓冲区别名问题

  • 长距离屏幕追踪会因 深度缓冲区走样(Depth Buffer Aliasing) 产生明显伪影
  • 实际做法:限制屏幕追踪光线长度

深度缓冲区自阴影处理

  • 深度缓冲区追踪本身也会造成自阴影
  • 解决方案:组合使用 点采样(Point Sample)双线性采样(Bilinear Sample) 深度值

Stencil 位标记

  • 使用 Stencil Bit 标记哪些实例在光追中 有对应表示
  • 如果光线穿过 无光追表示的像素背后,则 增大估计厚度,从这些实例获得更多接触阴影

解决方案二:Alpha Mask 几何体处理

问题本质

  • 对于 漫反射 GI,可以在 BVH 构建时通过 缩小/剔除三角形 来粗略近似 Alpha Mask 遮挡
  • 但对 直接阴影,这些 trick 效果不佳
  • 理想方案是固定功能 Alpha Masking,但美术使用 材质图(Material Graph) 定义 Alpha Mask → 不实际

三种处理方式

方案描述优缺点
全量 Any-Hit 评估所有光线使用完整的 Any-Hit Shader 评估材质✅ 结果精确;❌ 无法使用 Inline Ray Tracing,主机开销巨大
延续光线(Continuation Ray)先做轻量级 Inline 追踪;命中需要材质评估的实例时,发射延续光线 并启用 Any-Hit✅ 仅在需要时付出额外开销;✅ 保留 Inline 追踪的性能优势
回退到 Virtual Shadow Map对特定光源/实例回退使用 VSM适用于硬件光追完全不实际的情况

解决方案三:Virtual Shadow Map(VSM)回退

适用场景

  • Any-Hit Shader 开销过高(如 密集植被,大量重叠三角形)
  • 大量实例动画网格,BVH 构建耗费过多内存和时间

VSM 的优势

  • 能够生成 可信的软阴影,与其他硬件光追阴影 混合良好
  • 在光源采样 Pass 中,可以 标记哪些 Page 被采样,避免不必要的网格渲染到 Shadow Map 中

灵活的混合使用

  • 非二元选择:美术可以 手动标记 哪些实例渲染到 Shadow Map,其余实例仍使用硬件光追
  • 局限:VSM 回退并未解决 Shadow Map 的 根本扩展性问题
  • 实际使用:主要用于 方向光(Directional Light),因为方向光的几何不匹配问题最为显著

完整追踪管线总结

整体管线按以下顺序执行:

1. 屏幕空间追踪(Screen Traces)
   → 避免代理网格自阴影
   
2. 近场追踪(Near Field Traces)
   → 处理大部分光线
   ├─ 命中 Alpha Mask 物体?→ 延续光线 + 材质评估
   └─ 光线超出近场半径?→ 远场追踪(Far Field Traces)

3. VSM 回退(可选)
   → 对配置了 VSM 的光源,额外采样 Shadow Map

着色器性能优化:瓦片分类(Tile Classification)

问题

  • 追踪着色器需要处理 多种材质类型光源特性寄存器压力(Register Pressure) 高,占用率(Occupancy)

解决方案

  • 基于 材质类型影响每个 Tile 的光源类型 进行 瓦片分类
  • 只在 确实需要 的 Tile 上付出最坏情况的 VGPR 使用量
  • 矩形光(Rect Light)纹理光(Textured Light) 的支持逻辑开销较大 → 为其创建 专用着色器排列(Shader Permutations)

实际效果

  • MegaLights Demo 中,基于光源类型的额外分类使 占用率提升约 20%,而分类本身的额外开销很小

半透明材质与体积雾的照明(Translucency & Volumetric Fog)


UE5 中体积光照的既有架构

两种存储结构

  1. 体积雾(Volumetric Fog):使用 摄像机对齐的视锥体网格(Camera-Aligned Frustum Grid / Froxel Grid)
  2. 粒子效果与半透明物体(Translucency):使用 世界空间网格(World Space Grid),每个体素存储 一阶球谐(First Order Spherical Harmonics)

传统更新方式

  • 每帧将光源 注入(Inject) 这两个体积结构
  • 阴影通常通过 Shadow Map 计算

Mega Lights 带来的问题

  • Mega Lights 方案下 没有 Shadow Map
  • 注入 大量光源 本身也 非常昂贵
  • 因此这两个体积结构必须 升级以适配 Mega Lights

将不透明表面管线扩展到体积

基本方法

  • 对体积同样运行 采样 + 光线追踪 管线:
    1. 半分辨率光线 对每个体素进行 光源采样 并追踪 阴影光线
    2. 对可见样本使用 相位函数(Phase Function)(体积雾)或 漫反射 BRDF(半透明体积)进行着色
    3. 构建 可见光列表(Visible Light Lists)
  • 需要对两个体积 各执行一次

直接套用的问题

  1. 探针稀疏:尤其是世界空间网格,从邻近体素 收集可见性信息 容易导致在 高频阴影区域引导失效
  2. 大量重复工作:两个体积的探针覆盖范围 大幅重叠,导致选光和追踪的重复计算

优化方案探索

方案一:统一使用 Froxel 网格(存储球谐)

  • 思路:扩展 Froxel 网格结构,使其也存储 球谐数据,用于粒子和半透明物体照明

  • 优点

    • 避免两个体积之间的重复工作
    • Froxel 更密集 → 引导效果更好
  • 缺点 / 实际伪影

    1. Froxel 网格结构可见:尤其在摄像机移动时非常明显(世界空间网格虽也有类似问题,但至少是 摄像机无关的、稳定的
    2. 时序滤波的重投影问题:会产生无法完全避免的 可见伪影

方案二(采用方案):混合方案——共享采样与追踪

  • 核心思路:仅 采样和追踪 在两个体积间共享,着色分别进行

具体流程

  1. 采样阶段:基于 Froxel 位置(更密集)运行采样逻辑 → 相邻探针可以 共享可见性数据 而不损害引导效果
  2. 追踪阶段:对这些样本统一追踪阴影光线
  3. 着色阶段:运行 两个独立的着色 Pass,每个体积从最近的采样探针 随机收集(Stochastically Gather) 样本

半透明采样的特殊挑战

与不透明表面的关键差异

不透明表面的 "80% 能量来自 1 盏灯" 假设在半透明中 不完全成立

  1. 光源注入球谐:不知道哪些表面最终会用某个体素着色 → 无法利用法线和材质属性 预先筛选光源
  2. Froxel 尺寸相对像素仍然很大:从邻近体素 随机上采样 容易导致 不稳定 或需要更宽的滤波
  3. 双重评估需求:统一体积中必须同时考虑 相位函数半透明 BRDF → 光源权重分布 更均匀,难以集中到少数几盏灯上

结论

需要 每个体素着色更多样本(比不透明表面多得多)

两种增加样本的策略

策略方法优点缺点
增加每体素样本数直接提升采样数量简单直接管线各阶段 全面变贵
扩展随机上采样着色时从 多个邻近体素 收集并合并样本(而非仅一个)避免额外采样和追踪开销模糊可见性项,损失光照细节

后处理稳定化

  • 对体积光照结果额外施加 时序滤波空间滤波,提高照明稳定性

高质量半透明表面(如玻璃)

问题描述

  • 部分半透明材质(如 玻璃)需要 更高质量的照明,包括 镜面反射(Specular)

方案一:完整管线重跑

  • 将前层视为最重要层,对其重新运行 整个 Mega Lights 管线
  • 问题:当玩家靠近半透明表面时,直接光照开销可能翻倍——实际中通常太贵
  • 还需要支持 多层着色,可扩展性不足

方案二(当前使用):利用球谐近似

  • 使用已有的 半透明体积球谐数据
  • 从球谐中 提取主方向(Dominant Direction) 来近似镜面反射照明
  • 优点:非常廉价
  • 缺点
    1. 仅支持 一个镜面高光
    2. 球谐中的光照必须 非常稳定,否则镜面反射会出现 可见的抖动(Jitter)——即使光源是静态的
  • 当前状态:作为临时方案使用,改进仍在进行中

运行时性能分析(Runtime Performance)


测试环境

参数
平台PlayStation 5
渲染分辨率1080p
每像素样本数1 SPP
TSR 计算禁用
屏幕光源数量超过 900 盏
每像素光源数量20~80 盏

总体开销

  • 总耗时约 5.5 毫秒,涵盖 所有直接光照的阴影和着色 成本

关键性能观察

1. 采样比着色更耗时

  • 不透明表面采样 尽管运行在 半分辨率 下,耗时仍然 超过着色
  • 原因
    • 采样成本与 光源数量 成比例——此场景光源数量极高
    • 大量 矩形光源(Rect Lights),采样开销高且 限制 Occupancy(占用率)
  • 着色相对稳定:有每像素着色样本数的 上限,成本主要受 瓦片类型 影响

2. 半透明着色几乎与不透明一样贵

  • 尽管 探针数量远少于屏幕像素数
  • 原因:如前所述,半透明需要 每个体素着色更多样本 以改善稳定性和降低噪声

美术工作流的实际影响

美术创作模式的转变

  • 一旦美术开始使用 Mega Lights,创作方式 迅速发生变化
    1. 初期:谨慎地零星放置光源
    2. 中期:光源数量 大幅增加
    3. 后期:开始大量使用 矩形光源,甚至利用 程序化光源生成工具(Procedural Light Spawners) 沿样条线自动布置灯光

系统的可扩展性

  • 整体系统 扩展性更好、容错性更强
  • 但传统的 内容优化手段 仍然有价值:
    • 减小衰减范围(Attenuation Range)
    • 收窄锥角(Cone Angles)
    • 使用挡光板(Barn Doors)
    • 这些措施可以有效 降低噪声采样 Pass 的开销

总结与未来工作展望(Conclusion & Future Work)


Mega Lights 系统总结

核心成就

  • Mega Lights 利用 实时硬件光线追踪 来计算直接光照,甚至在当前一代主机上 也可运行
  • 光源数量不再是主要限制因素——这是该系统最重要的实际收益

现有质量限制

  • 网格在光追中的表示质量 仍然是画质的主要瓶颈
  • 大多数情况下每像素仅能负担 1 个样本精心的采样策略高质量降噪 至关重要

性能特性

  • 性能开销主要取决于两个因素:
    1. 每像素的光源样本数量
    2. 光追场景复杂度
  • 实践中证明这是一个 良好的性能-质量权衡

未来工作方向

1. 产品化完善

  • Mega Lights 仍在 走向生产就绪(Production Ready) 的过程中
  • 需要完成大量 优化、修复和缺失功能

2. 可扩展性问题(Scalability)

  • 核心挑战:一旦美术使用 Mega Lights 制作内容,很难在不大量返工的情况下降低光源数量
  • 不希望 美术被迫手动维护 多套光照配置(例如高端/低端分别一套)
  • 这仍是一个 开放问题

3. 降噪与上采样的统一化

  • 当前管线:Mega Lights 自有降噪TSR 进一步处理
  • 机器学习降噪 领域有大量新研究,展示出非常有前景的结果
  • 机会点:将降噪和上采样 统一整合,减少总开销并提升最终画质

4. 光追中的网格表示(最大挑战)

  • 此前 漫反射 GI粗糙反射 对几何精度要求较低,低精度代理网格 勉强够用
  • 直接光照的阴影 会轻易 暴露底层几何表示的不足
  • 动态几何体 仍是 未解决的难题
    • 大量动画实例会 轻易超出内存和性能预算
    • 目前无法精确表示

5. 新一代光追 API 扩展

  • 开始出现新的 光追 API 扩展,有望更高效地表示 Nanite 网格
  • 几何复杂度在持续增长,且新类型的内容(如 Nanite 植被等)在光追中的表示更具挑战性

观众问答精华

Q1:是否考虑过 Light Cuts 等多光源合并技术?

  • 回答:有考虑过,即演讲开头提到的 光源层级结构(Light Hierarchies)
  • 核心问题:这类技术 不考虑遮挡项,而被遮挡光源的问题正是 Mega Lights 要解决的关键点,因此帮助有限

Q2:如何判断上采样是否对某帧失败?

  • 回答:上采样时根据 深度和法线 对每个像素计算权重
  • 如果权重为零(例如非常细的线条),则判定 无法上采样,回退到上一帧信息

Q3:多轮样本范围回映射(Sample Warping)是否会出现精度问题?

  • 回答是的,每次回映射会 丢失 1 bit 精度
  • 但实际中采样的光源数量 并不多——只采样上一帧可见的光源 + 光源网格单元中的少量光源
  • 因此精度位数 不会耗尽

Q4:仅用光追检查遮挡,是否需要高质量光追几何体?对动画 Nanite 网格效果如何?

  • 回答:多管齐下的策略——
    1. 支持 动画代理网格(会有不匹配,但可接受)
    2. 屏幕空间追踪 在很多情况下效果很好
    3. 美术在 Mega Lights 下倾向于放置 软阴影光源,天然 隐藏了不匹配问题
    4. 对于 关键光源(Hero Lights) 或问题严重的实例,可标记使用 Virtual Shadow Map 路径,获得完全精确的阴影

Q5:有无策略减少遮挡检测的延迟?突变亮度变化是否有滤波处理?

  • 回答
    • 遮挡检测滤波器(Disocclusion Filter):在历史累积不足的帧上施加 额外空间采样
    • 着色置信度(Shading Confidence) 机制修复了大部分延迟问题
    • 仅在光源数量非常多 时才可能出现累积不够快的问题

Q6:能否用集群加速结构(Cluster Acceleration Structures)替代代理网格?

  • 回答
    • 非常感兴趣,但 当前主机上尚不支持
    • 即使有新的光追扩展,某些内容(如 曲面细分、Nanite 植被)仍无法很好表示
    • 理想目标 是完全消除代理网格和屏幕追踪,但 距离实现还很远

Q7:Mega Lights 对快速移动的光源/摄像机/动画网格表现如何?

  • 回答取决于像素处的光照复杂度
    • 如果只有 1-2 盏主导光源 → 表现 很好
    • 如果有 20 盏光源需要多帧累积 → 表现 很差
  • 本质:随机采样提供了一个 性能与质量之间的滑块——可以根据具体需求调整在时序稳定性和画质之间的平衡点

关键结论

维度状态
光源数量限制✅ 基本解决
主机可用性✅ 已实现
产品化就绪🔄 仍在进行中
可扩展性(低端回退)❌ 开放问题
光追几何表示质量❌ 最大的未来挑战
动态几何体❌ 未解决
降噪 + 上采样统一🔄 有前景,待整合