MegaLights: Stochastic Direct Lighting in Unreal Engine 5
MegaLights: Stochastic Direct Lighting in Unreal Engine 5 - SIGGRAPH 2025
讲座核心内容
- 讲座主题: 介绍在 Unreal Engine 5 中实现的一种名为 MegaLights 的新型直接光照技术。
- 核心技术: 该技术属于 随机直接光照 (Stochastic Direct Lighting) 的范畴。
- 随机 (Stochastic) 意味着该方法很可能利用随机采样来解决光照计算问题,这通常是为了在可控的性能开销下,处理极其复杂的场景。
- 直接光照 (Direct Lighting) 指的是计算从光源直接照射到物体表面所产生的光照效果,不包括间接光照(如反弹光)。
- MegaLights 这个名称暗示了该技术的核心目标是高效处理海量光源 (Mega - amount of lights) 的场景,这在传统实时渲染中是一个巨大的挑战。
动机 (Motivation)
本页阐述了开发这项新渲染技术的根本动机,即当前游戏开发在光照领域面临的四大核心挑战:性能与规模、视觉质量、美术工作流以及技术普适性。
1. 对性能与扩展性的极致追求
现代游戏场景对动态光源的数量和性能要求达到了前所未有的高度。
- 核心观点: 渲染引擎必须有能力在单帧内高效处理海量、完全动态且带阴影的光源。
- 关键术语:
- 百数量级的带阴影光源 (100+ shadowed lights): 目标是在屏幕上同时支持超过100个能够投射阴影的光源。这远超传统正向渲染(Forward Rendering)或早期延迟渲染(Deferred Shading)的常规处理能力。
- 完全动态 (Fully dynamic): 场景中的所有光源、物体都可以在运行时自由移动、改变属性,不允许依赖任何形式的静态预计算(Baking)。
- 性能瓶颈: 随着光源和材质复杂度的提升,渲染开销急剧增大。如今,即使是计算无阴影光照的成本也已高到可能成为性能瓶颈,这凸显了优化光照计算本身的重要性。
2. 对视觉质量的更高标准
玩家和开发者对画面真实感的追求永无止境,尤其是在光照和材质表现上。
- 核心观点: 渲染技术需要支持更接近物理真实的光照模型和材质效果,以提升画面的沉浸感。
- 关键术语:
- 面光源 (Area Lights): 必须支持非点状的、具有体积和形状的光源(如灯管、窗户),并能产生符合物理规律的软阴影 (Soft Shadows),而非传统点光源产生的锐利硬边阴影。
- 复杂的BRDF与光照类型 (Complex BRDFs and light types): 引擎需要能够处理复杂的双向反射分布函数(BRDF),例如模拟清漆、多层布料等分层材质 (Layered Materials)。这通常要求对每个像素、每个光源进行多次、复杂的BRDF求值。
3. 以美术师为核心的创作流程
技术的发展不应成为美术师创作的枷锁。高效、自由的工作流是释放创造力的关键。
- 核心观点: 先进的渲染技术必须服务于美术师的创作流程,工作流的效率已成为制约游戏画面品质的主要瓶颈。
- 关键术语:
- 工作流是关键 (Workflows are key): 一个繁琐、限制重重的渲染管线会严重影响美术师的迭代效率和最终产出质量。技术方案的设计必须将美术师的工作体验放在首位。
- 无烘焙 (No baking): 彻底摆脱光照烘焙,实现完全的所见即所得。这使得美术师可以像玩游戏一样进行创作(work playfully),例如通过程序化工具快速、自由地布置和调整成百上千的光源,并立即看到最终效果。
4. 作为基准方案的普适性要求
这项技术并非一个仅用于高端演示的“屠龙技”,而是旨在成为项目开发中被广泛使用的基础光照方案。
- 核心观点: 该技术必须足够高效和稳定,能够作为项目美术生产的视觉基准,并且能在主流游戏硬件上流畅运行。
- 关键术语:
- 基准光照方法 (Baseline lighting method): 它必须是美术师在日常工作中主要依赖的光照系统,而不是一个需要额外适配、增加工作负担的补充性功能(例如,避免需要美术师为它单独进行一次“re-lighting pass”)。
- 目标平台: 性能要求必须覆盖主流市场,即能够在游戏主机 (Consoles) 和中端PC (mid-range PC) 上达到可接受的帧率。
直接光照技术 (Direct Lighting Techniques)
本页对比了两种计算直接光照的主流思路:传统的“逐光源”评估方法和现代的“基于采样”的随机方法。这两种方法的根本区别在于计算成本的来源——是与光源数量挂钩,还是与每个像素的采样数量挂钩。
传统方法:评估所有光源 (Per-Light Evaluation)
这是一种在游戏引擎中广泛使用的经典方法,尤其适用于光源数量可控的场景。代表技术是前向渲染 (Forward Lighting) 和 延迟渲染 (Deferred Lighting)。
-
核心观点: 渲染开销与场景中的光源数量成正比。每个光源都需要单独计算其对场景的贡献。
-
工作流程:
- 阴影计算: 对每一个光源,首先通过 阴影贴图 (Shadow Maps) 或光线追踪阴影等技术,预先计算出其投射的阴影,并通常会生成一张屏幕空间的阴影遮罩 (Shadow Mask)。如果使用光追阴影,通常还需要一步降噪处理。
- 光照应用: 在一个独立的光照处理阶段(Lighting Pass),遍历所有光源。将每个光源的辐照度(Irradiance)与预先计算好的阴影遮罩以及物体表面的材质(BRDF)相结合,累加得到最终的光照结果。
-
关键优势:
- 对于少量光源,此方法非常高效且易于控制。
- 输出结果是无噪声的,效果稳定。
-
关键劣势:
- 当场景中光源数量急剧增加时(例如成百上千个),性能会急剧下降,因为计算量是
像素数 * 光源数,成本变得无法接受。
- 当场景中光源数量急剧增加时(例如成百上千个),性能会急剧下降,因为计算量是
随机方法:基于采样 (Stochastic/Sampling-Based)
这种方法在离线渲染中更为常见,但随着硬件性能提升,也逐渐在实时渲染中(尤其是光线追踪)得到应用。其核心思想是解耦光照复杂度和渲染性能。
-
核心观点: 渲染开销与光源数量无关,仅取决于每个像素发射的光线(样本)数量。这使得它能够高效处理海量光源的复杂场景。
-
工作流程: 对于每个像素,我们不遍历光源,而是发射固定数量的采样光线来“寻找”光照贡献。主要有两种采样策略:
-
BRDF 采样 (BRDF Sampling)
- 方法: 根据物体表面的双向反射分布函数 (BRDF) 来决定光线的出射方向。简单来说,就是模拟光线从物体表面会朝哪些方向反射。
- 光照贡献: 如果射出的光线碰巧击中 (hit) 了某个光源,就将该光源的能量累加到最终结果中。
- 特点: 对于镜面或高光材质效果较好,因为它倾向于从反射方向采样。
-
光源采样 (Light Sampling / Next Event Estimation)
- 方法: 随机地从场景中的光源集合中选择一个子集(甚至只有一个),然后从着色点直接向选中的光源发射一条光线(通常称为阴影光线)。
- 光照贡献: 如果这条光线没有被任何物体遮挡,就说明该光源能够照亮着色点,将其能量累加到最终结果中。
- 特点: 对于处理漫反射材质和面积光源的软阴影效果更高效。
-
-
关键优势:
- 性能与光源复杂度解耦,能够从容应对成千上万的光源。
-
关键劣势:
- 结果是随机的 (Stochastic),单次采样的结果会充满噪声 (Noise),需要大量的采样或者先进的降噪器 (Denoiser) 才能获得干净的图像。
延迟光照(Deferred Lighting)的扩展性瓶颈
传统延迟光照的工作流程
延迟光照(或称延迟渲染)是一种非常流行的渲染管线,尤其在游戏中。其基本思想是将几何体渲染(G-Buffer生成)和光照计算解耦。在光照阶段,它的工作方式是:
- 逐光源(Per-Light)进行计算:对于场景中的每一个光源,首先计算它对场景产生的阴影,然后将光照和阴影效果应用到所有受其影响的像素上。
- 阴影计算方法:通常使用阴影贴图(Shadow Maps) 或光线追踪阴影(Ray Traced Shadows) 来确定像素是否在阴影中。
核心痛点:无法扩展到大量光源
尽管延迟光照很流行,但当场景中的光源数量急剧增加时,其 “逐光源” 的特性会带来严重的性能问题。
- 核心观点:传统延迟光照的计算成本与潜在影响像素的光源数量成正比,导致在复杂光照场景下性能瓶颈严重。
讲座中给出了一个非常典型的例子来说明这个问题:
- 潜在光源 (Potential Lights):一个像素位于 50 个不同光源的衰减范围内。
- 可见光源 (Visible Lights):在剔除遮挡后,其中只有 15 个光源实际对该像素有贡献。
- 主导光源 (Dominant Light):在这 15 个可见光源中,往往仅 1 个最主要的光源就贡献了 80% 的光照能量。
这意味着,为了计算这15个光源的贡献,我们可能对全部50个光源都进行了昂贵的阴影计算(如生成Shadow Map或光线追踪),其中大量的计算被完全浪费了。
现有优化方案的局限性
业界已经有一些针对该问题的优化方案,但它们并不能从根本上解决扩展性问题。
1. 阴影缓存(Shadow Caching)
- 例如虚拟阴影贴图(Virtual Shadow Maps, VSM) 。
- 局限性:
- 缓存失效 (Cache Invalidation):在高度动态的场景中(如大量移动的光源、物体或变化的相机),缓存会频繁失效,导致性能回落到没有缓存的水平。
- 内存消耗巨大:即使场景是静态的,为了缓存所有光源的阴影,也需要极大的显存。在讲座的 "MegaLights" 演示中,VSM的缓存大小设置为4GB依然不够用,并会导致渲染瑕疵。
2. 光线追踪阴影(Ray Traced Shadows)
- 通过自适应追踪(Adaptive Tracing)或稀疏阴影蒙版(Sparse Shadow Masks)等技术可以优化。
- 局限性:
- 固有的高成本:逐光源进行光线追踪和降噪的开销依然巨大。这为场景中可用的动态光源数量设置了一个相对较低的硬性上限。
3. 光照评估成本(Light Evaluation Cost)
- 问题:即使我们能以零成本获得阴影信息,仅仅在着色器中对每个像素评估大量光源(即使是15个)的光照方程本身也是一笔不小的开销,特别是当材质和光源模型(如IES Profile)很复杂时。
思想转变:从“蛮力计算”到“按重要性采样”
对上述问题的深入分析引出了一个关键的思考方向:
- 核心观点:既然绝大部分光照能量都集中在少数几个主导光源上,我们就不应该对所有光源都一视同仁地进行高质量的“蛮力”计算。
这引出了讲座后续内容的核心思路:我们能否只为最重要的那个光源进行高质量、高成本的计算,而对其余大量次要光源的贡献进行某种形式的近似(Approximation) ?这为设计一个能处理成千上万个光源的新型渲染架构奠定了基础。
BRDF采样作为光源方案的探讨
将直接光照视为全局光照(GI)问题
-
核心观点:这是一种尝试将直接光照(Direct Lighting)完全整合到全局光照(Global Illumination, GI) 的计算流程中的方法。其基本思路是,不单独处理场景中的光源,而是完全依赖于GI系统通过材质的BRDF(双向反射分布函数)进行采样,在半球方向上随机发射光线来“寻找”并计算来自光源的贡献。
-
实践案例:在UE5中,艺术家有时会使用一种变通方法(Workaround):
- 在场景中放置一些自发光(Emissive)的网格物体。
- 将这些网格对主摄像机设置为隐藏。
- 利用它们来模拟软区域光(Soft Area Light) 的效果,完全交由Lumen(UE5的GI系统)来处理。
优缺点分析
-
优点
- “免费”的性能开销:因为实时GI系统(如Lumen)无论如何都要运行,将直接光照的计算并入其中,理论上不会带来额外的、专门用于直接光计算的开销。成本已经被GI的计算“摊销”了。
-
缺点
- 采样效率低下,质量受限:这是该方法最致命的缺陷。
- 难以找到小光源:BRDF采样在寻找小型或远距离光源方面表现非常挣扎。当一个光源在着色点所构成的半球上只占很小的立体角时,随机根据BRDF方向发射光线,能恰好命中该光源的概率极低。这会导致最终图像产生大量噪点,或者干脆完全丢失该光源的贡献。
- 高级技术也难以弥补:即使有Lumen的光线引导(Ray Guiding) 等高级技术来辅助,试图将采样光线引向更重要的方向,这个问题依然存在,说明这是该方法的根本性难题。
核心论点:不要让GI“负重前行”
-
GI本身已是难题:在游戏主机上实现60Hz的实时全局光照,本身已经是一个巨大的技术挑战。
-
正确的协作方式:通常,直接光照应该作为GI的“帮手”。在实时渲染乃至离线渲染中,一种常见的优化技巧是使用解析光源(Analytical Lights)来“帮助”GI系统,为其提供稳定、准确的直接光照信息,从而加速GI的收敛并提升最终质量。例如,在窗户位置手动放置一个区域光,可以极大地改善室内场景的GI效果。
-
本末倒置的做法:将直接光照完全交给GI处理,是在反其道而行之。这种做法非但没有用清晰的直接光信息来辅助GI,反而给本已困难重重的GI问题增加了额外的负担——让它去负责寻找并计算直接光。这使得原本就极具挑战性的实时GI任务变得更加困难,违背了渲染优化的基本原则。
实时渲染中的多光源光照:一种可扩展的随机采样方案
本页提出了一种用于处理大量光源的、高度可扩展的实时渲染方法。其核心思想是将每个像素的光照计算工作量固定下来,使其与场景中的光源总数无关。
核心工作流:固定光线预算的解耦方案
该方法将光照计算分解为四个独立的阶段,形成一个清晰的渲染管线:
-
1. 光源采样 (Sampling):
- 为屏幕上的每个像素,从场景中的所有光源中随机选择 (Stochastically selected) N 个光源样本。
- 这里的 N 是一个固定的、较小的数字(例如,在主机上可能 N=1)。
-
2. 阴影追踪 (Tracing):
- 从着色点向每个选中的光源样本发射一条阴影光线,以检测它们之间是否存在遮挡物。
- 所有的阴影计算都由此步骤的光线追踪完成。
-
3. 着色计算 (Shading):
- 对于那些通过了遮挡测试(即光线未被遮挡)的可见光源样本,计算其对着色点的光照贡献(例如,评估其 BRDF)。
- 所有可见光源的贡献会累加到同一个渲染目标 (Render Target) 中。
-
4. 降噪 (Denoising):
- 在所有光线追踪和着色完成后,对包含所有光源贡献的渲染目标进行一次统一的降噪处理。
核心观点: 这个流程的最大优势在于其出色的可扩展性。无论场景中有几百个还是几千个光源,每个像素执行的工作量(追踪N条光线)是恒定的,从而将渲染性能与光源数量解耦。
核心挑战:低采样率下的光源选择
当渲染预算非常有限时(尤其是在主机等性能受限的平台上),我们每个像素可能只能负担得起追踪极少数光线(例如 SPP=1,即每像素1个样本)。在这种情况下,光源的选择变得至关重要。
-
挑战详情: 如果我们唯一的这条光线射向了一个虽然很近、很亮,但恰好被遮挡的光源,那么这条光线的全部计算开销就被浪费了,该像素将得不到任何直接光照信息,最终导致图像中出现噪点或能量损失。
-
核心观点: 在极低的光线预算下,如何智能地选择最有可能贡献光照且未被遮挡的光源,是该方法成败的关键。一个好的选择算法应该最大化每条光线的有效性。
现有光源选择技术的局限性
讲座提到了两种业界流行的光源选择技术,并分析了它们在当前场景下的不足之处。
1. 光照层次结构 (Light Hierarchies)
- 基本思想: 通过构建光源的层次结构(类似于BVH),来快速剔除和选择重要的光源簇。
- 主要缺陷:
- 不考虑可见性 (No visibility term):这是最致命的问题。它可能会引导我们选择一个能量很强但实际上被完全遮挡的光源簇,从而浪费光线预算。
- 实践难题: 虽然理论上支持光源合并(类似LOD),但在实践中容易出现漏光、光照错误等问题。
- 性能开销: 在GPU上每帧动态构建这种层次结构,成本相当高昂,对GPU架构不够友好。
2. ReSTIR (Reservoir-based Spatiotemporal Importance Resampling)
- 基本思想: 一种先进的重要性重采样技术,通过时域和空域的信息复用,能以较低的采样成本获得高质量的结果。
- 主要缺陷:
- 向下扩展性存疑 (Can it scale down?): ReSTIR 在高端PC上表现出色,但其算法复杂度和资源消耗较高。它是否能够被优化和裁剪,以适应主机等性能受限平台,并作为一个基础光照方案来使用,仍然是一个开放性问题。
ReSTIR 基础管线与性能瓶颈
ReSTIR的核心思想:时空复用
ReSTIR 并非一个全新的渲染管线,而是在经典的随机直接光照(Stochastic Direct Lighting) 流程中,通过引入一个样本复用(Sample Reuse) 阶段来显著提升渲染质量。
-
核心假设: 当前像素在本帧随机采样的光源样本效果不佳(例如,被完全遮挡或贡献度低)时,其历史帧的有效样本或邻域像素的有效样本中,极有可能存在一个质量更高的选择。
-
基本流程:
- 候选样本生成 (Candidate Sampling): 和传统方法一样,为当前像素随机采样 N 个新的光源样本。
- 样本复用 (Sample Reuse): 从屏幕空间的历史数据(temporal reuse) 和邻域像素(spatial reuse) 中,获取 M 个过去被证明是有效的旧样本。这些历史和邻域数据通常以 Reservoir 的形式存储。
- 可见性测试 (Tracing): 对所有样本(N个新样本 + M个旧样本)都进行光线追踪,以判断它们是否对当前着色点可见。这是性能开销的主要来源。
- 重采样 (Resample): 在所有可见的样本中,通过 Reservoir resampling 算法,以一种保留能量的方式,智能地选出最优的单个样本来代表该像素的光照贡献。
- 更新历史: 将最终选出的优质样本存入当前像素的 Reservoir 中,供下一帧使用。
性能瓶颈:高昂的固定光线追踪开销
尽管 ReSTIR 带来了巨大的质量提升,但其引入的样本复用机制也带来了难以忽视的性能问题。
-
核心观点: ReSTIR 最大的性能瓶颈在于样本复用引入了高昂且固定的光线追踪开销。复用操作本身(查找历史/邻域数据)有一定成本,但真正昂贵的是需要为每一个被复用的样本都追踪一条新的可见性光线。
-
成本量化:
- 即使最终渲染目标仅为 1 SPP (Sample Per Pixel),实际的光线追踪数量也远超于一。
- 一个典型的 ReSTIR 实现,为了在质量和性能间取得平衡,每个像素可能需要追踪 2-3 条光线:1条用于本帧的新样本,另外1-2条用于从时域和空域复用的样本。
- 这意味着相比于传统的 1 SPP 随机采样,ReSTIR 带来了 2-3倍 的光线追踪负载。
-
现实挑战:
- 这种额外的开销在高端 PC 上或许可以接受,但在主机(Console) 等性能受限的平台上,渲染预算通常被严格限制在每个像素追踪不多于 1 条光线。
- 这使得标准的 ReSTIR 算法难以在这些平台上直接部署,也构成了本次讲座试图解决的核心技术挑战。
ReSTIR 候选采样 (Candidate Sampling)
本页的核心在于探讨 ReSTIR 算法中一个关键但代价高昂的环节:如何为每个像素生成初始的光源候选样本。理想的候选样本是后续时空复用和重采样的基础,但传统方法的效率和效果都存在严重瓶颈。
候选样本的需求与传统方法的挑战
-
核心观点: ReSTIR 算法的性能和最终图像质量,在很大程度上依赖于持续获得高质量的初始候选样本。如果初始样本质量差(例如,大部分都指向被遮挡的光源),那么后续的优化步骤也很难“无中生有”地创造出好的结果。
-
传统方法: 为了获得高质量的样本,一种常见的技术是基于 BRDF 的重要性采样 (BRDF Importance Sampling)。
- 原理: 根据当前像素的表面材质(BRDF)特性,为场景中的每个光源计算一个权重,优先选择那些根据材质反射特性来看最可能贡献光照的光源。
- 目标: 这样做是为了让采样更“智能”,而不是在庞大的光源列表中进行完全随机的盲选。
传统候选采样方法面临的两大难题
尽管基于 BRDF 的采样听起来很理想,但在实践中却面临两个无法回避的致命问题。
1. 高昂的计算成本 (High Computational Cost)
- 核心问题: 为了做出明智的选择,算法需要遍历一个庞大的列表。讲座中提到,为了达到“可交付”的质量,每个像素需要检查场景中大约 20% 的光源。
- 性能瓶颈: 这相当于对屏幕上的每一个像素,都执行一次无阴影的光照计算(Unshadowed Light Evaluation) ,而且是针对场景中 1/5 的光源。这种“暴力”筛选的计算量是巨大的,尤其是在光源数量众多的场景中,对于性能预算有限的平台(如游戏主机)来说,这几乎是不可接受的固定开销。
2. 忽略遮挡问题 (Ignoring Occlusion)
- 核心问题: BRDF 本身只关心材质、光线方向和光源强度,它对场景中的几何遮挡关系一无所知。
- 负面影响: 这会导致一个非常普遍且棘手的问题:被遮挡的强光源会“污染”采样池。
- 具体场景: 想象一个非常亮的灯在一个房间内,而我们的采样点在墙的另一侧。尽管光线完全被墙挡住了,但由于这个灯本身很亮,它的 BRDF 权重可能依然非常高。
- 结果: 采样算法会频繁地选中这个实际上毫无贡献的、被遮挡的光源作为“高质量”候选样本。这不仅浪费了宝贵的采样名额,也使得算法更难发现那些真正可见、有贡献的优质光源。
总结来说,ReSTIR 的初始候选采样阶段陷入了一个两难境地:我们一方面渴望高质量的样本来驱动整个算法,但传统的重要性采样方法不仅计算成本高到难以承受,而且其“无视遮挡”的特性还常常导致采样质量不佳,事倍功半。
ReSTIR 的样本相关性 (Sample Correlation)
本页的核心在于探讨 ReSTIR 方法的一个关键副作用——样本相关性,以及它如何与后续的降噪流程产生冲突,并引出整个讲座试图解决的核心问题。
ReSTIR 的核心问题:样本相关性而非样本引导
-
核心观点: ReSTIR 的本质并非一种“引导”采样(Sample Guiding)技术去寻找新的、更好的光路,而是通过复用(Reuse) 历史帧中已发现的“优质”离散样本来实现降噪。
-
产生的问题: 这种持续的复用机制会导致严重的样本相关性(Sample Correlation) 。这意味着在时间和空间上,被选中的样本会倾向于“扎堆”出现,形成所谓的“团块效应”(Clumping Effect)。
- 形象比喻: 理想的采样模式应该是
ABCABC这样多样化且无关联的,而 ReSTIR 的输出模式更像是AABBCC,其中相同的样本被连续多帧、多个像素复用。 - 根本原因: 一个样本一旦在早期被选中,它在后续帧中被再次选中的概率会随着时间的推移呈指数级增长,因为它有越来越多的路径(通过时间复用和空间邻域复用)可以传播到当前帧。
- 实践中的缓解: 实际项目中,通常会限制 M 值(即样本的历史保留帧数) 来缓解这个问题。但即便如此,团块效应依然显著。如果将 M 降至 1,则完全禁用了时间复用,ReSTIR 就退化为了普通的随机采样。
- 形象比喻: 理想的采样模式应该是
采样与降噪的矛盾
-
核心观点: ReSTIR 带来的采样优化与降噪器(Denoiser)的最佳工作条件是相悖的,导致两者的收益会部分抵消(partially cancel each other out) 。
-
降噪器的偏好: 降噪器(尤其是现代的时空降噪器,如 SVGF, TAAU)在处理高频、不相关的噪声时效果最好。它们期望输入的是像
ABCABC一样均匀分布的、无固定模式的噪点。 -
ReSTIR 的输出: ReSTIR 产生的
AABBCC模式是一种低频、高度相关的噪声。降噪器难以有效处理这种成片的、有明显时间连续性的“噪声”,因为它看起来更像场景的真实细节而非随机噪点。
新视角:将 ReSTIR 与降噪器视为两种时空滤波
-
核心观点: 我们可以将 ReSTIR 和降噪器都看作是在屏幕空间进行的时空滤波(spatio-temporal filtering) ,但它们的机制和侧重点不同。
-
机制对比:
- ReSTIR:
- 操作对象: 复用样本并重新着色(Reuse samples and reshade) 。它操作的是光线路径的“种子”,并为当前像素重新计算光照。
- 时间历史: 通常可以维持更长的时间历史(例如,比降噪器长2倍),因为它不直接复用颜色,所以不需要处理复杂的历史帧校正(history rectification) 。
- 优势: 能够更激进地聚合时间和空间信息,积累更多有效样本。
- 降噪器 (Denoiser):
- 操作对象: 复用已着色的像素颜色(Reuse already shaded colors) 。
- 时间历史: 历史帧数相对受限,因为必须通过运动矢量等信息进行复杂的历史帧校正,以避免鬼影(Ghosting)。
- ReSTIR:
-
潜在的负面影响: ReSTIR 激进的滤波虽然减少了初始噪声,但也扰乱了采样模式(scrambles sampling patterns) ,在某些情况下,这种扰乱经过降噪器处理后,最终的画面质量甚至可能比不用 ReSTIR 更差。
讲座的核心思路:为降噪器而设计采样
-
提出的问题: 既然 ReSTIR 的时空复用与降噪器存在冲突,我们能否跳过 ReSTIR 这一步,转而设计一种更“聪明”的采样策略?
-
解决方案方向: 设计一种新的采样方法,其目标不再是自身产生最平滑的中间结果,而是产生最适合后续降噪器处理的输入。这意味着我们要追求生成
ABCABC这样低相关性的采样模式。 -
最终目标: 通过让采样器与降噪器协同工作(cooperate with the denoiser) ,我们期望能以远低于 ReSTIR 的性能开销,实现相似甚至更好的最终渲染质量,从而更好地满足项目性能预算。
回归本源:理想的光源采样方案
这页的核心是提出一个理想化的目标,为后续要讲解的技术(很可能是为了逼近这个理想目标而设计的)设定一个清晰的“靶子”。它首先指出现有或朴素方法的缺陷,然后描绘出一种完美的解决方案应该是什么样的。
问题的根源:对所有光源进行采样
在有海量光源的场景中,如果我们对一个像素进行着色,最直接的方法是从场景中所有的光源里随机挑选几个进行采样,计算它们的光照贡献。这种方法的弊端非常明显:
- 浪费采样 (Wastes Samples): 对于一个特定的像素(或其表面上的着色点),场景中的绝大部分光源可能都被其他物体遮挡了。如果我们向这些被遮挡的光源(Hidden Lights) 投射阴影光线,这些光线注定会被阻挡,其光照贡献为零。这部分计算就完全被浪费了。
- 产生噪点 (Causes Noise): 渲染中的噪点本质上是蒙特卡洛积分的方差过高。当大量采样结果为零(因为光源被遮挡),而少数采样结果有贡献时,就会极大地增加最终像素颜色的方差,表现为图像上的明显噪点。左侧的对比图生动地展示了这种充满无效采样和高噪点的情况。
理想的目标:每像素的可见光列表
为了解决上述问题,一个理想的解决方案被提了出来:我们希望在对着色点进行光照计算之前,就能拥有一个只包含那些对该点可见的光源列表(Visible Light List) 。
- 核心定义: 可见光列表 (Visible Light List) 是一个针对单个像素(或着色点)的、经过筛选的光源集合。该集合中的每一个光源都被确认为是能够照亮该点,且中间没有遮挡物的。
- 核心思想: 我们将采样的范围从“场景中的所有光源”缩小到“当前像素的可见光列表”。这样一来,每一次采样都将是有意义的,因为我们只向那些已知可见的光源投射光线。右侧的对比图清晰地展示了这种高效的采样方式,所有光线都对最终结果有贡献,图像也因此变得干净。
拥有“可见光列表”的核心优势
-
提升采样效率,显著降低噪声
- 这是最直接的优势。由于避免了对被遮挡光源的无效采样,每一条光线追踪的成本都花在了“刀刃”上。
- 在相同的采样数量(Sample Budget)下,由于大部分采样的贡献都不再是零,像素颜色的估计值的方差会大幅降低,从而得到更平滑、更少噪点的图像。
-
降低采样相关性,助力降噪器 (Denoising-Friendly)
- 这是一个更深层次的优势。有了可见光列表后,我们可以实施更高级的采样策略,特别是对于时域降噪器(Temporal Denoiser)。
- 我们可以做到在时间上(跨帧)随机地(stochastically) 从可见光列表中选择不同的光源子集进行采样。
- 这种做法可以打破帧与帧之间的样本相关性 (Sample Correlation),将难以处理的、成片的噪点(blotchy noise)转化为更均匀、高频的噪点模式。这种“白噪音”或者“蓝噪音”式的模式对于现代的降噪器来说,处理起来要容易得多,可以获得更高质量的降噪结果。
Sample Guiding: 利用时间连续性指导光线采样
核心思想:利用历史帧信息
为了更智能地选择采样哪个光源,一个非常有效的思路是利用时间上的连续性。其基本假设是:上一帧可见的光源,在当前帧很大概率下仍然是可见的。因此,我们可以基于上一帧的可见性信息,来构建一个“高价值”光源列表,从而指导当前帧的采样,避免将算力浪费在被遮挡的光源上。
- 核心观点: 时间连续性 (Temporal Coherence) 是一个强大的工具,可以显著提升光源采样的效率。
- 关键术语: Sample Guiding (样本指导), History / Temporal Information (历史/时间信息)。
实现方法:基于Tile的可见光列表 (Visible Light List)
直接为每个像素维护一个可见光列表会带来巨大的内存开销。一个更实际的折中方案是,在屏幕空间上将像素划分为一个个图块(Tile),并为每个图块维护一个可见光列表。
- 基本单元: 8x8 屏幕空间图块 (8x8 screen space tile)。同一图块内的相邻像素很可能共享相似的光源可见性。
工作流程
-
列表构建 (上一帧)
- 在光线追踪阶段完成后,GPU线程协作收集每个 8x8 Tile 内所有被成功命中的(即“可见的”)光源样本。
- 利用 Wave Intrinsics (如
WaveActiveMin指令) 在一个Warp/Wavefront内高效地生成一个紧凑且排好序的可见光列表。这比传统的原子操作或共享内存方法要快得多。
-
列表使用 (当前帧)
- 在当前帧的光源采样阶段,对正在处理的像素进行时间反投影 (Reprojection),找到其在上一帧屏幕空间中的对应位置。
- 根据反投影的位置,定位到上一帧对应的 8x8 Tile,并从该 Tile 存储的可见光列表 (Visible Light List) 中选择一个光源进行采样。
关键优化:解决Tile边界不连续问题
由于可见光列表是基于离散的 Tile 生成的,当一个物体或像素从一个 Tile 移动到相邻 Tile 时,它所使用的光源列表会发生突变,从而在画面上产生明显的块状接缝或不连续的瑕疵。
- 问题: Tile边界的不连续性 (Discontinuities between tiles)。
- 解决方案: 随机双线性查找 (Stochastic Bilinear Lookup)。
- 实现方式:
- 一个像素不再是“非黑即白”地只从它所在的一个Tile中查找光源列表。
- 而是根据它在当前Tile内的相对位置,找到周围最近的4个Tile。
- 然后,通过一个随机化的双线性插值过程,从这4个Tile的可见光列表中进行采样。这有效地模糊了Tile之间的硬边界,实现了平滑过渡。
- 额外好处: 这种方法还能加速新出现的可见光信息在屏幕空间的传播,因为一个Tile的可见光信息可以更快地“渗透”到相邻的Tile中。
实践中的思考与迭代
在最终确定方案之前,团队也进行了一些其他的尝试和权衡。
-
可见性权重 vs. 二元可见性
- 曾尝试的方案: 不仅记录光源是否可见,还根据命中/未命中射线的比例为其赋予一个权重。
- 实践效果不佳的原因: 这种加权方案会降低半影区域(Penumbra)中光源的采样率。然而,半影区域通常是噪声最严重的区域,我们恰恰希望在这里投入更多的采样来减少噪声,而不是减少采样。因此,简单的二元可见性(Visible/Occluded) 列表效果更好。
-
显式列表 vs. 布隆过滤器 (Bloom Filter)
- 早期方案: 使用布隆过滤器这种概率性数据结构来记录可见光。
- 切换到显式列表的原因:
- 存储额外数据 (Payload): 显式列表允许为每个光源附加额外的信息(例如亮度、颜色等),这在采样时非常有用。
- 高效采样: 显式列表可以被直接、无偏地采样,而不需要遍历光照网格(Light Grid)中的所有潜在光源来检查它们是否存在于过滤器中。
-
列表大小的限制
- 可见光列表的长度可以设置一个较小的硬编码上限。
- 根本原因: 在每像素仅1个样本(1SPP)并依赖时间累积(Temporal Accumulation)的渲染管线中,一个像素在有限的时间内能够有效累积的光源贡献是有限的。因此,为每个Tile维护一个过长的可见光列表并不会带来明显的质量提升,反而会增加内存和计算开销。
Hidden Lights - 发现动态场景中的新光源
在光照渲染中,为了效率,我们通常会为每个像素或屏幕区块(Tile/Cluster)维护一个“可见灯光列表”(Visible Light List)。然而,在动态场景中,仅对这个列表进行采样是远远不够的。当摄像机移动、物体移动或遮挡物消失时,原先被遮挡或在屏幕外的“隐藏灯光”(Hidden Lights)可能会突然变得可见。如果我们不主动去发现它们,画面就会出现延迟更新或光照错误。本页的核心就是解决这个问题:如何在维持性能的同时,高效地发现并融入这些新出现的光源。
核心问题:静态的“可见光列表”无法应对动态变化
在依赖时序信息(Temporal Reprojection)的渲染管线中,我们常常复用前一帧的分析结果,例如哪些灯光对某个区域有贡献。
- 问题根源: 如果一个光源在当前帧因为遮挡关系的变化而变得可见,但它不在上一帧的“可见光列表”中,那么仅靠这个列表进行采样,我们将完全错过这个光源,直到某个随机过程“意外”地采样到它为止。
- 带来的影响: 导致光照收敛缓慢,尤其是在解遮挡(Disocclusion) 或场景内容发生剧烈变化时,会产生明显的光照延迟或闪烁。
解决方案:为“隐藏灯光”分配专属采样预算
为了主动发现新光源,我们必须将一部分采样预算(Sampling Budget) 分配给那些存在于当前光照网格(Light Grid Cell)但并未被列为“可见”的灯光。
这里的实现策略非常巧妙,它利用了两个独立的蓄水池(Reservoir) 来分别处理可见光和隐藏光,最后再将它们智能地合并。
-
双蓄水池结构 (Dual Reservoirs):
- 可见光蓄水池 (Visible Light Sample Reservoir): 专门用于对已知的可见光列表进行采样。
- 隐藏光蓄水池 (Hidden Light Sample Reservoir): 专门用于对该区域内其他所有“隐藏”的灯光进行采样。
-
关键设计: 这两个蓄水池使用相互独立的随机变量进行采样,确保它们的采样过程不相关,从而更有效地探索整个灯光空间。
关键机制:预算控制与动态调整
简单地采样隐藏灯光还不够,关键在于如何控制预算,避免在没有必要时浪费过多的性能,并在需要时加大发现力度。
1. 固定预算上限:权重裁剪(Weight Clamping)
在合并两个蓄水池之前,我们对“隐藏光蓄水池”的权重进行一次关键的限制操作。
- 核心操作: 将隐藏光蓄水池的权重,限制(Clamp) 在不超过灯光总权重的 20% 以内。
- 这意味着,无论隐藏灯光有多亮,它最多只能获得总采样机会的约20%。
- 为什么这样做更优越?:
- 相较于简单地降低隐藏灯光的权重(downweighting),这种固定预算上限的方法更加稳健。
- 它可以有效防止一个亮度极高但完全被遮挡的灯光“劫持”采样过程。如果只是降低权重,这个超亮光源的权重可能依然很高,导致采样器频繁地向它投射光线,而这些光线最终都会被遮挡,造成大量噪声和性能浪费。
- 固定上限确保了隐藏光的探索始终处于一个可控范围内,保证了画面的稳定性。
2. 动态预算调整:智能适应场景变化
这个20%的比例不是一成不变的,系统会根据上下文动态调整,让采样策略更加智能。
-
当可见光非常暗淡时:
- 如果当前区域的可见光总贡献(即权重之和)非常小,系统会放宽(Relax)20%的限制。
- 目的: 允许更多的采样预算流向隐藏灯光,从而加速在新区域或黑暗区域发现主要光源的过程,提升收敛速度。
-
当时序信息复用失败时 (History Reprojection Fail):
- 当发生剧烈的相机或物体移动,导致上一帧的历史数据完全不可信时(例如,移动到一个全新的场景区域)。
- 系统会采取更激进的策略:将隐藏灯光的采样预算提升至50%。
- 目的: 在失去可靠历史数据的情况下,最大化新光源的发现速率,帮助渲染系统快速建立起对当前场景光照环境的认知,尽快达到稳定状态。即使在这种情况下,系统仍会尝试复用空间上最邻近区块的数据作为引导,但加大“探索”力度是关键。
MegaLights 渲染管线概览
本页概述了 MegaLights 技术的核心渲染管线,其关键创新在于引入了一个可见光源列表(Visible Light List) 来指导光线追踪采样,从而大幅提升效率和质量。
核心管线流程
与传统路径追踪管线类似,但增加了一个关键的“可见性(Visibility)”阶段,用于构建和利用历史信息。
-
采样 (Sampling):
- 基于上一帧的可见光源列表,为每个像素选择 N 个光源样本。
- 这是一个引导性采样(Guided Sampling) 过程,而非完全随机选择。
-
追踪 (Tracing):
- 为每个光源样本投射一条遮挡光线(Occlusion Ray)来检测可见性。
-
可见性 (Visibility):
- 本管线的核心阶段。
- 以 8x8 像素的屏幕空间瓦片(Tile) 为单位,统计并构建当前帧实际可见的光源列表。
- 这个列表将被存储为历史信息(History) ,供下一帧使用。
-
着色 (Shading):
- 对于通过可见性测试的光源样本,计算其 BRDF,完成光照着色。
-
降噪 (Denoising):
- 对最终的漫反射(Diffuse)和镜面反射(Specular)光照结果进行降噪处理。
关键设计思想
1. 基于历史信息的采样引导
- 核心观点: 利用前一帧的可见光信息来指导当前帧的采样。这个过程极大地提高了光线追踪的“命中率”。
- 显著的效率提升: 管线可以做到每像素追踪大约 1 条光线,就能获得约 0.8 个有效的光源样本(~0.8 spp) 。这意味着绝大多数光线都成功地找到了一个可见的光源并对最终像素颜色做出了贡献,极大地减少了浪费。
- 低成本构建: 构建这个可见光源列表的操作本身开销很小,使其成为一个高性价比的优化。
2. “探索”与“利用”的平衡
- 核心观点: 采样策略并非完全依赖历史信息,而是结合了“利用”已知信息和“探索”未知信息。
- 利用 (Exploitation): 大部分光线被投向历史列表中已知的可见光源,这是效率的主要来源。
- 探索 (Exploration): 系统会分配一小部分光线预算,去探测那些上一帧中不可见的光源。这确保了当有新光源进入视野或遮挡物移开时,系统能及时发现它们,避免了光源突然“延迟”出现的视觉问题。
3. 为降噪器优化采样模式
- 核心观点: 可见光源列表使我们能够生成对降噪器更友好的采样模式。
- 无相关性的样本 (Uncorrelated Samples): 知道哪些光源可见后,我们可以在这些光源中进行更智能的采样(例如分层采样、蓝噪声采样),而不是纯粹的随机蒙特卡洛采样。
- 提升降噪质量: 这种分布更均匀、模式更优良的“漂亮图案”(nice patterns),可以被降噪器更高效地处理,从而在相同的样本数量下获得更高质量、更少噪点的最终图像。
Denoiser-Friendly Sampling (为降噪器优化的采样)
本页的核心目标是,如何从一个庞大的光源列表中,为每个像素智能地挑选出少数几个(N个)光源样本,使得最终的渲染结果在经过降噪器处理后,能够获得更高质量的图像。这套采样策略主要由三个关键部分组成:采样算法、权重计算和随机数生成。
核心采样策略:加权蓄水池采样 (Weighted Reservoir Sampling)
为了从光源列表中高效地选取样本,讲座采用了 加权蓄水池采样 (Weighted Reservoir Sampling, WRS) 算法。
- 核心观点: WRS 是一种非常高效的“在线”算法,它只需要遍历一次光源列表,就能根据每个光源的权重随机地选择一个最终样本。这避免了需要预先计算所有光源权重总和的复杂步骤。
- 关键术语: Weighted Reservoir Sampling (WRS) 是一种从一个项目集合(即使集合总大小未知)中按权重随机抽取一个样本的算法。
- 算法伪代码:
// Weighted Reservoir Sampling WeightSum = 0; Selected = null; for (i : N) // 遍历N个光源 { Wi = CalculateWeight(i); // 计算当前光源的权重 WeightSum += Wi; // 以 Wi / WeightSum 的概率选择当前光源i if (rand() < Wi / WeightSum) { Selected = i; } } // 循环结束后,Selected中存储的就是最终被选中的光源
权重设计:基于感知和降噪的考量
如何为每个光源赋予一个合理的权重,是决定采样质量的关键。一个好的权重函数可以让采样更集中于对最终画面贡献大的光源。
- 核心观点: 权重函数的设计目标是符合人类视觉感知,并主动降低那些可能给降噪器带来麻烦的光源的采样概率。
- 权重公式:
- Luminance(BRDF): 权重的基础是光源在当前着色点上通过BRDF反射后贡献的亮度。
- Log2 对数加权: 使用对数函数(特别是
Log2)进行 感知加权 (perceptual weighting)。人眼对暗部区域的亮度变化比亮部区域更敏感。对数变换可以压缩高亮度区域的权重差异,使得采样分布更符合人眼的感知特性。 - 关键优势: 这种加权方式能有效降低极亮光源的权重。在渲染中,一个非常亮但被部分遮挡的光源可能会产生一个“萤火虫”(firefly)噪点。这个噪点虽然亮度值极高,但在经过色调映射(Tonemapping)后,其对最终像素颜色的影响会被压缩。然而,这个高强度的噪点对于降噪器来说却是极大的挑战。通过对数加权,可以减少对这类光源的采样,从而从源头上缓解“强光被遮挡”问题,提升降噪效果。
随机数来源:时空蓝噪声 (Spatio-Temporal Blue Noise)
高质量的随机数是随机采样的基础。相比于传统的伪随机数,使用具有特定频谱分布的噪声模式可以生成在空间和时间上更均匀、更优质的噪点,从而让降噪器更容易处理。
- 核心观点: 使用专为降噪器优化的 时空蓝噪声 (Spatio-Temporal Blue Noise, STBN) 来替代传统的随机数生成器,以获得在空间和时间维度上都表现更优的噪声分布。
- 关键术语:
- Blue Noise (蓝噪声): 一种高频噪声,其能量主要分布在高频区域,在空间上表现为均匀分布、没有明显聚集的采样点。这种噪点模式对人眼更友好,也更容易被降噪算法识别和抹除。
- Spatio-Temporal (时空): 意味着这种噪声模式不仅在单帧图像的空间上(Spatio)具有良好分布,还在连续的帧之间(Temporal)保持了良好的相关性和稳定性,这对于时间性降噪(Temporal Denoising)至关重要,可以有效避免噪点闪烁。
- 实践应用: STBN 通常以预计算的纹理形式提供,使用时只需在着色器中进行一次纹理采样,成本极低,效果显著。
实践中的挑战:随机数的需求与供给矛盾
将上述技术整合时,出现了一个实际的工程问题。
- 核心观点: WRS算法在循环中需要为每个候选光源生成一个独立的随机数,而STBN纹理的设计初衷是每个像素每帧只提供一个高质量的随机数。
- 矛盾点:
- WRS的需求: 在遍历N个光源的循环中,每次迭代都需要调用
rand(),即需要 多个随机数。 - STBN的供给: STBN纹理为了保持其优良的蓝噪声特性,被设计为每个像素只采样一次,提供 一个随机数。
- WRS的需求: 在遍历N个光源的循环中,每次迭代都需要调用
- 严禁操作: 不能简单地对STBN纹理进行多次采样来获取多个随机数,因为这会破坏其精心设计的蓝噪声频谱特性,使其失去“降噪友好”的优势。
- 引出的问题: 如何从STBN提供的单个高质量随机变量中,派生出WRS循环所需的多个随机变量,同时又不破坏原有的噪声分布特性?这成为了下一阶段需要解决的关键技术难题。
复用随机数并保持时空蓝噪声(STBN)特性
当我们拥有一个高质量的,具备时空蓝噪声(Spatio-Temporal Blue Noise, STBN)特性的随机数序列时,一个核心挑战是如何在单个像素上多次使用这个随机数,而又不破坏其优秀的分布特性。本页探讨了两种在实践中行之有效的技术。
单样本/像素场景:样本变换 (Sample Warping)
当我们需要在一个像素内进行一系列连续的随机选择(例如,从一个光源列表中逐个尝试挑选光源)时,可以使用样本变换技术。
-
核心观点: 每当我们使用一个随机数
r从一个子区间[a, b]中做出选择后,我们可以将这个子区间[a, b]重新映射(Warp)回[0, 1]标准区间,从而生成一个新的、仍然保持原有蓝噪声相对分布特性的随机数,用于下一步的决策。 -
关键术语: 样本变换 (Sample Warping)
-
工作流程(如图 A→B→C 所示):
- 初始状态 (A): 我们有一个在
[0, 1]区间内的 STBN 随机数,例如 0.6。 - 选择与消耗 (B): 假设我们用这个随机数在某个任务中选择了
[0.4, 1]这个子集。我们的随机数 0.6 落在了这个区间内。 - 变换与再生 (C): 为了进行下一次随机选择,我们将
[0.4, 1]这个区间“拉伸”回[0, 1]。原先的 0.6 在这个新区间中的相对位置就成了新的随机数。- 变换公式为:
new_rand = (old_rand - range_start) / (range_end - range_start) - 在例子中:
(0.6 - 0.4) / (1.0 - 0.4) = 0.2 / 0.6 ≈ 0.333。这个新的0.333就可以用于下一次采样。
- 变换公式为:
- 初始状态 (A): 我们有一个在
多样本/像素场景:抖动采样 (Dithered Sampling)
当我们需要在一个像素内同时生成多个样本(例如,为抗锯齿或软阴影发射多条光线)时,抖动采样是一种更高效的方法。
-
核心观点: 利用一个 STBN 随机数,为 N 个样本生成一组分层(Stratified)的采样点。具体来说,它将
[0, 1]区间等分为 N 份,然后利用 STBN 值作为偏移量(抖动),在每个子区间内生成一个随机数。这确保了 N 个样本均匀地分布在整个[0, 1]区间,避免了样本聚集。 -
关键术语: 抖动采样 (Dithered Sampling), 分层采样 (Stratified Sampling)
-
核心算法:
(SampleIndex + STBN_Mask) / NumSamplesNumSamples: 每个像素所需的样本总数。SampleIndex: 当前是第几个样本(从 0 到NumSamples-1)。STBN_Mask: 原始的、在[0, 1)区间内的 STBN 随机数值。
示例: 若
NumSamples = 4,STBN_Mask = 0.7:- 第 0 个样本值 =
(0 + 0.7) / 4 = 0.175(落在区间[0, 0.25]) - 第 1 个样本值 =
(1 + 0.7) / 4 = 0.425(落在区间[0.25, 0.5]) - 第 2 个样本值 =
(2 + 0.7) / 4 = 0.675(落在区间[0.5, 0.75]) - 第 3 个样本值 =
(3 + 0.7) / 4 = 0.925(落在区间[0.75, 1.0])
实践中的考量
-
精度损失: 任何形式的重映射(remap)都会消耗随机数的一点浮点数精度。但这在实践中通常不是问题,因为浮点数精度足够高,且性能限制了我们迭代的次数。
-
风险分摊: 为了进一步减小精度损失的影响,可以采用多个独立的STBN序列。例如,讲座中提到使用一个随机变量序列处理可见光源列表,另一个独立的序列处理隐藏光源列表。这样可以将精度损耗分散到不同的随机变量上。
-
性能约束: 现实中,由于性能预算的限制,我们不可能在一个像素上对海量光源进行迭代采样。这个天然的性能瓶颈也意味着我们不会进行过多次的样本变换,因此精度损失的影响也得到了控制。
融合多种采样技术的优化策略
本页介绍了一种集大成的采样优化技术,它将纯随机SBTN、样本变换和抖动采样三种方法结合起来,实现了性能与质量的双重飞跃。
核心优势:性能与质量的“免费午餐”
这种组合方法的核心思想是在不牺牲甚至提升渲染质量的前提下,大幅优化采样性能。
-
核心观点: 通过将纯随机时空蓝噪声(Pure Random SBTN) 、样本变换(Sample Warping) 和抖动采样(Dithered Sampling) 三种技术巧妙地融合,可以将复杂的采样过程最终简化为单次纹理查找(a single texture lookup) 。
-
关键优势:
- 极致的性能提升: 将原本可能需要复杂计算的采样过程,优化为一次简单的纹理读取操作,极大地提升了运行效率,这对于实时渲染是至关重要的。
- 保留高质量的噪声特性: 该方法最重要的成果是它完整地保留了时空蓝噪声(STBN)的优良特性。STBN生成的噪声在空间和时间维度上都具有高频、均匀分布的特点,这种噪声模式对人眼更友好,也更容易被后续的抗锯齿和降噪算法(如TAA)所处理。
- 零额外计算成本: 这项技术带来的画质提升是完全免费的(completely free) 。它不需要引入任何额外的计算负载或进行额外的光线追踪,意味着开发者可以在不增加GPU负担的情况下,获得更干净、更稳定的渲染结果。
光源采样 (Sampling Lights)
在现代渲染管线中,场景可能包含成百上千的光源。对于每个像素,如果都去计算所有光源的贡献,性能开销将是无法承受的。因此,必须采用高效的光源采样策略来选择性地评估一部分光源,以在性能和质量之间取得平衡。
采样策略:解决海量光源的性能问题
面对海量光源,核心的挑战在于如何以较低的成本,智能地选取对当前像素贡献最大的光源子集。
-
核心问题: 当一个光源网格 (Light Grid) 的单元格内包含数百个光源时,逐一遍历和计算是极其昂贵的。
-
混合采样方案: 为了解决这个问题,讲座提出了一种结合两种光源列表的混合采样方法:
- 可见光源列表 (Visible Light List): 这是一个经过预筛选的、可能对整个画面有重要影响的光源列表(例如,在视锥内的主要光源)。对此列表中的光源,我们会全部进行评估。
- 光源网格 (Light Grid): 对于像素所在的光源网格单元,我们只评估其中的一个随机子集 (stochastic subset),例如每隔 N 个光源采样一个。为了避免重复计算,我们会跳过那些已经在“可见光源列表”中被评估过的光源。
-
核心观点: 通过结合“全量评估高重要性光源”和“随机采样局部光源”的混合策略,在控制计算成本的同时,保证了渲染的完整性和对光照变化的快速响应。 每个像素采样的随机子集都不同,这虽然会造成渲染结果在空间上的不连贯性(incoherent),但能非常有效地让整个画面快速响应光照变化。
动态调整与实现细节
一个静态的采样率无法适应动态变化的游戏场景。当场景发生变化时,尤其是遮挡关系改变时,需要动态地调整采样密度。
-
动态采样率: 当检测到像素的历史信息丢失 (History Miss) 时(通常发生在遮挡剔除解除/disocclusion 的区域,即之前被遮挡的表面现在可见了),系统会增加从光源网格中采样的光源数量。这相当于在该像素上投入更多的计算资源,以帮助它更快地收敛到正确的着色结果。
-
高效实现: 从两个列表中采样并去重的过程,可以通过一个简单的技巧高效实现:将两个光源列表预先排序,然后使用不同的步长(stride)同时遍历这两个列表,在每一步总是选择并处理两个列表中索引值最小的那个光源即可。
-
核心观点: 采样率应是动态的,在场景变化剧烈(如遮挡关系改变)的区域投入更多计算资源,以加速画面收敛,提高时间稳定性。
采样权重与优化
在选择了光源之后,还需要进一步优化计算过程和处理采样结果,以提升最终的渲染质量和GPU效率。
-
基于BRDF的权重: 光源采样的重要性(权重)是根据 BRDF的亮度 (Luminance) 来决定的。这确保了材质反射能力强的方向上的光源会被优先考虑。
- 灰度计算优化: 一个有趣的优化点是,虽然将整个BRDF计算(包括所有输入)都转为灰度会引入过多的噪点,但可以将某些中间计算环节(如光照累加器
light component accumulator)改为灰度处理。这样做可以在不显著影响视觉质量的前提下,有效减少GPU的VGPR (向量通用寄存器) 使用量。
- 灰度计算优化: 一个有趣的优化点是,虽然将整个BRDF计算(包括所有输入)都转为灰度会引入过多的噪点,但可以将某些中间计算环节(如光照累加器
-
基于曝光的样本剔除:
- 剔除低贡献样本: 我们可以设置一个与相机曝光相关的阈值 (exposure-relative threshold),并丢弃那些计算出的贡献度低于该阈值的光源样本。
- 质量优化而非性能优化: 这个操作的主要目的不是为了提升性能,而是为了提高渲染质量。阈值通常设置得很低,以避免引入明显的能量损失 (energy loss) 或偏见 (bias)。
- 带来的好处:
- 重分配采样预算: 将本应分配给这些“无效”样本的计算资源(例如,一条用于检测可见性的光线)重新分配给更重要的采样任务。
- 抑制萤火虫 (Fireflies): 有效地移除了那些由概率极低但瞬时权重可能很高的微弱光源所引起的噪点(即“萤火虫”)。
-
核心观点: 通过智能地评估和剔除低贡献度的样本,不仅可以优化GPU资源使用,还能将有限的采样预算重新分配给更关键的地方,从而在提升渲染质量的同时抑制噪点。
降采样光照 (Downsampled Light Sampling)
本页探讨了一种通过在较低分辨率下进行光照采样来优化性能的技术。其核心思想是利用像素间的局部相似性,用更少的计算量来逼近全分辨率的渲染结果。
核心动机:利用空间局部性
- 核心观点:在很多情况下,相邻像素如果其深度(depth)和法线(normal) 相近,那么它们计算出的光照权重(Light weights) 也会非常相似。
- 优化思路:既然结果相似,就没有必要为每一个像素都独立进行完整、昂贵的光照采样计算。我们可以只对一部分像素进行采样,然后通过插值重建出完整图像。这种方法可以显著减少计算BRDF等昂贵操作的次数。
实现方法:稀疏采样与抖动
这项技术并非简单地将分辨率降低到1/4,而是采用更智能的稀疏采样策略。
- 采样模式:替代为每个像素计算1个样本的传统方式,我们采用一种稀疏的采样模式,例如在每
2x2的像素块中只对其中1个像素进行采样(总采样率降为1/4)。 - 关键采样模式:为了避免产生规律性的瑕疵(aliasing),必须使用高质量的采样模式,例如:
- 棋盘格模式 (Checkerboard Pattern)
- 4-Rooks 模式
- 时域与空域抖动 (Temporal and Spatial Jittering):
- 对上述采样模式在时间和空间上进行抖动至关重要。
- 空间抖动可以打乱固定的采样位置,避免摩尔纹等规律性瑕疵。
- 时间抖动(即每帧使用不同的采样位置)可以将瑕疵转化为高频噪声,这非常有利于后续的TAA(Temporal Anti-Aliasing)等时域降噪算法进行处理,从而在多帧上积分得到正确的结果。
图像重建:加权上采样
采样完成后,我们需要一个稀疏的采样结果图,必须将其重建(上采样)回全分辨率图像。
- 核心算法:随机双线性上采样 (Stochastic Bilinear Upsampling)。
- 加权机制:这不是简单的双线性插值。在为某个像素插值时,会检查其周围已采样的邻居像素。插值的权重会同时考虑深度和法线的差异。
- 如果邻居像素与当前像素的深度和法线差异很大(例如在物体的边缘),那么该邻居的权重就会很低,甚至为零,以防止光照信息“泄露”到不相关的表面上。
- “随机”体现在插值权重或样本选择上可能带有随机性,这有助于在多帧上更好地收敛到正确结果。
极端情况处理:上采样失败
- 问题描述:在某些罕见情况下,一个像素周围可能没有任何有效的采样点可供插值。例如,屏幕上有一根非常细的电线,而我们的稀疏采样模式恰好在这一帧完全错过了它上面的任何像素。此时,所有邻居的插值权重都会是零。
- 解决方案:当上采样失败时,直接复用上一帧的历史数据 (Reuse history)。
- 特别注意:在这种情况下复用历史数据时,不进行任何历史修正(History Rectification) ,如邻域钳制(Neighborhood Clamp)。因为当前帧没有有效信息,无法对历史数据进行有效性判断,只能完全相信上一帧的结果。
效果与权衡
- 性能优势:最显著的优点是速度。这种方法可以使光照采样的速度提升接近四倍,这是一个巨大的性能收益。
- 质量代价:
- 最终结果与全分辨率采样的结果并不完全相同。
- 由于上采样本质上是一种滤波过程,它可能会导致阴影和其他光照效果变得更柔和,其锐利度介于全分辨率和1/4分辨率之间。
- 结论:在实践中,这是一个非常有效的性能与质量的权衡(Tradeoff) 。
未来方向:自适应采样
- 目标:结合两种方法的优点,实现一个 自适应采样 (Adaptive Sampling) 方案。
- 愿景:在画面细节复杂、需要高质量的区域(如物体边缘)使用接近全分辨率的采样率,而在平坦、光照变化平缓的区域使用低分辨率采样,从而在保持高质量的同时获得更好的性能。
随机光线采样:处理定向光源(Directional Light)的挑战
在随机光源采样(Stochastic Light Sampling)中,定向光源(如太阳光)因其特殊属性,会带来一系列挑战,尤其是在处理室内外混合场景时。本页内容将探讨这些挑战以及相应的解决方案。
问题所在:定向光的“采样霸权”
定向光在场景中通常是亮度最高的光源,其能量可能比其他所有局部光源的总和还要强数千倍。这在基于重要性采样的系统中会引发一个严重问题。
-
核心观点:在进行光源选择时,系统会根据光源的贡献(BRDF * LightEnergy)来分配采样权重。由于定向光的能量极高,它的采样权重会变得极其巨大,从而导致几乎所有的采样光线都射向它。
-
关键影响:
- 局部光源“饿死”:绝大多数采样预算被定向光占用,导致场景中的点光源、聚光灯等局部光源几乎没有机会被采样。
- 室内场景失效:在室内或有遮挡的区域,定向光实际上是不可见的。但由于其权重过高,采样系统依然会浪费大量光线去尝试连接这个被完全遮挡的光源,而真正照亮场景的室内灯光却得不到采样,导致渲染结果严重偏暗或充满噪点。这极大地阻碍了系统发现新的可见光源。
解决方案一:独立的RT阴影通道(Separate RT Shadow Pass)
一种直接且常见的解决方案是,将定向光从随机采样池中分离出来,为其单独处理。
-
核心观点:为定向光运行一个专门的光线追踪阴影通道,独立于其他光源进行计算。
-
优点:
- 质量提升:可以为定向光设计独立的着色(Shading)和降噪(Denoising)流程,针对其特性进行优化,从而获得更高质量的阴影和光照效果。
- 采样公平:将定向光移除后,剩余的局部光源可以在随机采样中得到公平的采样机会。
-
缺点:
- 开销巨大(Expensive) :这意味着每像素需要追踪额外的光线,并增加一个完整的着色和降噪pass。对于有严格性能预算的游戏项目来说,这个方案可能过于昂贵。
解决方案二(本讲座采用):动态采样预算限制
为了在性能和质量之间取得平衡,讲座提出了一种更精巧的方案:对定向光的采样影响力进行动态限制。
-
核心观点:与其分配固定的光线数量,不如限制定向光在采样决策中的权重,使其不超过一个动态的上限,从而构成一种“软预算”。
-
实现机制:
-
权重限制(Weight Clamping) :将定向光的采样权重
W_dir进行钳制,其上限为所有局部光源权重总和Sum(W_local)的一个百分比(例如50%)。W_dir_clamped = min(W_dir, 0.5 * Sum(W_local)) -
动态阈值调节:这个限制并非一直生效。仅当局部光源的总权重
Sum(W_local)足够大(超过某个阈值)时,才激活此限制。- 当局部光较强时:激活限制,保证局部光源能获得足够的采样光线,避免被定向光“饿死”。
- 当局部光很弱或不存在时:放宽或移除此限制,允许系统将更多的采样预算自然地分配给场景中占主导地位的定向光。
-
-
关键术语:
- 软预算(Soft Ray Budget) :该机制并非硬性规定光线数量,而是通过影响采样概率来间接控制预算分配,会根据像素的局部光照情况自适应地增减射向定向光的光线。
扩展与思考
这个“采样霸权”问题理论上也可能发生在其他类型的超强光源上,例如一个用来模拟太阳的超强聚光灯。
- 讲座提到,在实践中,除了定向光外,其他光源引发此问题的场景较少。
- 现有机制的辅助:
- 感知加权(Perceptual Weighting) :对于不是那么极端强的光源,基于人眼感知的加权方式通常能很好地处理。
- 隐藏光源预算(Hidden Light Budget) :之前提到的为“隐藏”或“潜在”光源保留的固定采样预算(如20%),本身也对单个光源能占据的总预算起到了一个隐式的封顶作用。
- 未来方向:理论上,这套预算限制系统可以被扩展,允许美术师或引擎定义一个“超强光源列表”,对列表中的所有光源都应用类似的动态预算限制。
Area Light Guiding (面光源引导)
问题:大型面光源的采样效率问题
- 核心观点:对于大型面光源,简单的“可见/不可见”的二元可见性 (Binary visibility) 判断是远远不够的。
- 一个大型面光源(例如条形灯、巨大的发光面)可能只有一小部分对当前着色点可见,其余大部分都被场景中的其他物体遮挡。
- 如果我们仅知道该光源“部分可见”,然后在其整个表面上均匀采样,那么大部分光线样本都会射向被遮挡的区域,这些样本最终不会对结果产生贡献,从而导致采样浪费 (Wasted samples),降低了渲染效率和收敛速度。
解决方案:使用 2x2 Bitmask 进行引导
- 核心观点:我们为每个光源引入一个 2x2 的位掩码 (bitmask),用来标记该光源的哪些部分是可见的。
- 这个位掩码将每个面光源概念上地划分为四个象限(一个 2x2 的网格)。
- 每一位(bit)对应一个象限,如果该象限对当前着色点可见,则对应位为 1,否则为 0。例如,一个
1000的 bitmask 意味着只有左上角的象限是可见的。 - 这个 bitmask 作为一项额外的数据(payload),存储在 可见光源列表 (Visible Light List) 中,并与该列表一同构建。
技术原理:划分随机变量空间
- 核心观点:这个 2x2 bitmask 的本质是对用于面光源采样的二维随机变量空间进行划分。
- 关键术语:在对任意面光源进行采样时,我们通常会使用一个二维的随机变量(例如一对在
[0, 1]区间内的随机数u, v),然后通过一个采样函数将这个[0, 1]的正方形区域映射到光源的实际表面积上。 - 我们的 2x2 bitmask 实际上是将这个
[0, 1]的正方形预先划分为四个子区域([0, 0.5]x[0, 0.5],[0.5, 1]x[0, 0.5]等)。 - 在生成采样点时,我们只在 bitmask 中标记为“可见”的子区域内生成随机数
(u, v),从根源上避免了向注定被遮挡的光源部分发射光线。 - 这种在标准随机变量空间进行引导的方法具有很好的通用性,因为它不依赖于光源的具体形状(如胶囊体、球体、矩形等),适用于任何能够从
[0, 1]方形区域映射采样的光源。
局限性与未来方向
- 核心观点:固定的 2x2 划分并非在所有情况下都是最优的。
- 局限性分析:
- 对于某些特别巨大的光源,2x2 的划分粒度太粗,可能仍然存在大量的采样浪费。更精细的划分(如 4x4, 8x8)会更有效。
- 对于某些形状奇特的光源,如细长的线形光,均匀的 2x2 划分也不合适,采用非均匀的划分(如 4x1)会是更好的选择。
- 未来方向: 为了解决上述问题,未来的研究方向是实现一种自适应和层级化 (adaptive and hierarchical) 的方案。这意味着系统可以根据光源的大小、形状和遮挡情况,动态地决定划分的密度和方式(例如使用类似四叉树的结构),从而实现更高效、更精确的光源采样引导。
Area Light Sampling (面积光采样)
本页的核心是讲解在选定了要计算贡献的光源后,如何智能地在面积光的表面上选择采样点,以减少因遮挡而产生的噪点。
核心目标:对选定的面积光进行有效采样
在渲染方程中,我们需要对每个像素,从多个光源中采样。当一个光源被选定后(这是前序步骤),下一步就是在这个光源的表面上选择一个具体的点,然后从着色点向该光源上的采样点投射一条阴影光线(Shadow Ray)。
- 上下文: 此步骤发生在每像素N个光源选择之后,并针对每一个被选定的光源执行。
- 基本任务: 在光源表面上拾取一个点,用于后续的光照和可见性计算。
智能采样:优先处理可见区域 (Importance Sampling)
传统方法可能会在整个面积光表面上进行均匀采样。但如果光源有部分被场景中的其他物体遮挡,这种均匀采样会非常低效,因为大量光线会射向被遮挡的区域,最终对光照计算毫无贡献,徒增噪点。
-
核心思想: 降低被遮挡区域的采样权重(Downweight hidden parts) 。这是一种重要性采样 (Importance Sampling) 的思想,即优先在贡献更大的区域(在这里是可见区域)进行采样。
-
图示解读:
一个面积光被物体部分遮挡。采样过程会智能地将更多的采样点(例如70%和10%的样本)集中在两个可见的区域,而只分配很少的样本(例如10%和10%)到被遮挡的区域。
-
最终效果: 在总光线数量不变的情况下,将计算资源(光线)更集中地用于评估光源的可见部分,从而显著降低最终图像的噪点,提升收敛速度。
技术实现:2D STBN 与样本变换
为了实现上述的智能采样,讲座中提到了具体的技术组合。
-
关键技术: 2D STBN 噪声 (2D Spatio-Temporal Blue Noise) 配合 2D 样本变换 (2D Sample Warping)。
-
工作流程:
- 生成基础样本: 首先,在光源的2D参数化表面(例如一个矩形光源的UV坐标)上,使用 2D STBN 生成一组高质量、分布均匀的采样点。蓝噪声的特性保证了这些初始采样点在空间和时间上都有很好的分布,避免了采样点聚集。
- 执行样本变换: 接着,应用 2D 样本变换技术。这个“变换”或“扭曲”(Warping) 过程会根据光源表面各区域的可见性信息,重新分布(移动)这些初始的STBN采样点。
- 实现权重调整: 可见性高的区域会“拉拢”更多的采样点,而可见性低的(被遮挡的)区域则会“推开”采样点。这样,采样点的最终密度就与该区域的可见性(即重要性)成正比,从而自然地实现了对隐藏区域的“降权”。
-
关键术语:
- 2D STBN: 这是之前可能在1D或其他场景下介绍过的STBN技术在2D平面上的应用,专用于在面积光表面生成高质量的初始采样模式。
- 2D Sample Warping: 这是实现重要性采样的核心机制。它不是简单地拒绝/接受样本,而是通过一种映射函数,将一个均匀分布的样本集“扭曲”成一个根据重要性(可见性)进行非均匀分布的样本集,从而保留了样本数量和STBN的良好分层特性。
- [Clarberg et al. 2016]: 这是该技术的学术出处,表明这是一个基于已发表研究成果的成熟技术。
避免追踪重复的光线 (Don't Trace Duplicated Rays)
本页讨论的是一个在光线追踪渲染中的重要性能优化技巧:识别并跳过那些本质上重复的、无法提供新信息的光线,从而减少不必要的计算开销。
问题的根源:随机采样中的冗余光线
在现代图形渲染中,为了实现诸如软阴影之类的效果,我们通常会从一个着色点向面光源上的多个不同位置发射光线,这个过程被称为随机采样 (Stochastic Sampling)。然而,在特定情况下,这种随机采样会产生大量重复或效果上无法区分的光线。
-
核心观点:随机过程可能导致从同一像素发出的多条光线在路径和目标上完全相同或极其相似,追踪所有这些光线是一种计算资源的浪费。
-
常见场景:
- 点光源: 当一个像素内的多个采样点都向同一个点光源发射阴影光线时,这些光线拥有完全相同的起点和终点,它们是绝对重复的。
- 微小/远处的光源: 当一个面光源非常小,或者距离着色点非常远时,它在屏幕上的投影可能小于一个像素。此时,从该像素内不同位置射向光源的光线,其路径差异微乎其微。产生的半影(Penumbra) 区域会小于一个像素的覆盖范围,人眼无法分辨其差别,因此这些光线在效果上是冗余的。
优化策略:检测并复用光线结果
既然追踪这些重复光线是浪费的,那么解决方案就是主动识别它们,并只追踪其中的一条。
-
核心观点:通过检测光线的冗余性,我们可以只追踪一条“代表性”光线,然后将其可见性结果(即是否被遮挡)复用于所有其他等效的重复光线。
-
判断光线冗余的条件:
- 相同的起点:所有光线都源自同一个着色点(在同一个像素的处理上下文中)。
- 等效的目标:光线的目标区域(光源)极小,导致不同光线方向上的差异所产生的视觉效果(如半影)小于一个像素的精度。
-
优点:当这种情况自然发生时(例如,场景中确实存在很多小型光源),这是一种无损的性能优化。它在不牺牲任何视觉质量的前提下,实实在在地减少了光线追踪的负载。
实践与延伸:作为性能伸缩性的调节手段
这个优化思路还可以被主动利用,变成一个强大的性能/质量权衡工具,特别是在需要适配不同性能等级硬件的场景下。
-
核心观点:我们可以通过一个全局参数,在运行时人为地缩小光源的有效尺寸,从而主动创造更多重复光线的场景,以换取更高的性能。
-
关键术语:全局半影尺寸乘数 (Global Penumbra Size Multiplier)
- 这是一个可调节的全局参数,用于在计算阴影光线时缩放面光源的尺寸。
- 当乘数 < 1.0 时:
- 效果: 光源被视为比其实际尺寸更小,因此阴影会变得更加锐利(半影区域减小)。
- 性能: 更多光源会满足“半影小于像素尺寸”的条件,导致更多的光线被识别为重复并被跳过,从而显著提升光线追踪的性能。
-
应用场景:
- 这是一个非常实用的性能伸缩性(Performance Scalability) 工具。
- 对于性能较弱的平台(如 Steam Deck 或高端移动设备),可以适当调低这个乘数,牺牲一部分阴影的柔和度来换取流畅的帧率。
- 这样做的好处是,开发团队可以使用同一套美术资源和场景设置,仅通过调整这个渲染参数就能适配从高端PC到移动端的多样化硬件,避免了美术师为不同平台重新布光的巨大工作量。
Ray Reuse (光线复用)
本页介绍了一种重要的性能优化技术——光线复用(Ray Reuse) 。其核心目标是在保证画面质量基本稳定的前提下,大幅减少每个像素所需追踪的光线数量,甚至实现低于 1 SPP(Sample Per Pixel) 的渲染。
核心思想:邻域共享
传统的做法是每个像素独立地追踪自己的光线来计算光照。而光线复用的思路则打破了这种像素间的独立性,让一个像素可以“借用”或“复用”其屏幕空间邻域内其他像素的光线追踪结果。
-
核心观点: 通过在屏幕空间邻近像素间共享已有的光线追踪结果,用远低于 1 SPP 的成本,来合成一个视觉上完整、稳定的光照效果。 这是一种空间上的降噪与信息填充方法。
-
关键术语:
- SPP (Sample Per Pixel): 每个像素的采样数。低于 1 SPP 意味着平均每个像素追踪的光线数量少于一根,例如通过棋盘格渲染或本页讨论的光线复用技术实现。
实现方法:基于像素的动态旋转核 (Per-pixel Rotated Kernel)
为了智能地从邻域像素中拾取可用的光线信息,该技术采用了一种在屏幕空间上操作的采样核(Kernel)。
-
动态调整核大小: 为了适应不同场景的复杂性,避免产生视觉瑕疵,这个采样核的大小不是固定的,而是动态变化的。
- 核心观点: 采样核的尺寸主要由两个因素决定:1. 中心像素本身的深度(与摄像机的距离);2. 中心像素光线的命中距离(
RayHitT)。 - 原理:
- 距离摄像机较远的物体,或光线传播距离很长才命中物体的情况,通常意味着光照变化较为平缓,可以在一个更大的屏幕空间邻域内进行复用。
- 反之,对于近处的物体,为了保留细节,复用的邻域范围(核尺寸)应该更小。
- 核心观点: 采样核的尺寸主要由两个因素决定:1. 中心像素本身的深度(与摄像机的距离);2. 中心像素光线的命中距离(
-
基于深度的边缘停止函数 (Edge Stopping Function): 直接在邻域内模糊或复用信息会在物体边缘产生明显的光照泄漏(Light Leaking)或光晕问题。边缘停止函数就是为了解决这个问题。
- 核心观点: 在决定是否复用一个邻域像素的光线信息前,会先比较它与中心像素的深度值。如果深度差异超过某个阈值,就认为它们不属于同一个连续表面,从而停止复用。
- 作用: 这有效地保护了物体的轮廓,确保光照信息不会从背景“泄漏”到前景物体上,反之亦然,维持了画面的清晰度。
权重与权衡 (Reweighting and Trade-offs)
直接平均邻域像素的贡献是不正确的,需要进行数学上的校正,同时这种方法也带来了固有的优缺点。
-
结果重加权 (Reweighting):
- 核心观点: 复用邻域像素的光照结果时,必须对其贡献进行重新加权。
- 原因: 这本质上是一个蒙特卡洛积分中的重要性采样问题。从邻域像素“借用”一个光线结果的概率,与在中心像素位置独立采样得到该结果的概率是不同的。为了得到在数学上(能量上)正确的结果,必须通过加权来补偿这种采样概率上的变化。
-
优缺点权衡:
- 优点:
- 大幅降低成本: 最大的优势是显著减少了光线追踪的数量,是实现低于 1 SPP 渲染的绝佳方案。
- 平台可伸缩性: 对于性能有限的平台(例如上一代主机或更低规格的硬件),这是一个非常实用的“降级(Scale Down)”选项。
- 稳定性: 相比其他低采样率技术,它能在保持光照相对稳定和锐利的同时降低开销。
- 缺点:
- 柔化接触阴影 (Soften Contact Shadows): 由于信息是在一个屏幕空间的小区域内混合的,不可避免地会引入一定程度的模糊。这对需要清晰边缘的接触阴影影响最为明显,会使其变得更柔和、不够锐利。
- 优点:
Shading with Pre-Integrated Irradiance
在通过光线追踪确定了哪些光源样本是可见的之后,我们进入了着色(Shading)阶段。此阶段的目标是利用这些可见性信息来计算最终的像素光照贡献。
Shading 计算流程
此处的着色流程可以分解为两个主要步骤,其核心思想是将可见性(Shadowing)和光照(Shading)的计算分离开来。
- 核心观点: 最终的光照贡献是 所有可见光源样本的权重之和 与 预先计算好的光源辐照度(Irradiance) 相乘的结果。
-
累积可见样本权重 (Accumulate Visible Sample Weights)
- 对于屏幕上的每个像素,我们将前一阶段中所有被确定为可见的光源样本的权重(sample weight)累加起来。
- 这个累加后的总权重可以被看作是该像素的宏观可见性或平均遮挡项。
-
乘以预积分光照 (Modulate by Pre-integrated Lighting)
-
将上述累加得到的总权重,与光源自身的光照属性相乘,得到最终的光照结果。
-
这个计算过程可以概括为以下概念性公式:
Final_Lighting = (Accumulated_Weight) × (Pre-integrated_Irradiance) × (IES) × (Light_Function)
-
- 关键术语:
- Pre-integrated Irradiance: 指的是预先计算或通过解析方式得到的光源辐照度。它代表了在没有遮挡物的情况下,光源对一个表面能产生的全部光照贡献。通过预积分,我们将光源的复杂求值过程变成了一个相对简单的查询或计算,从而降低了运行时的开销和噪声。
- IES / Light Function: 这些是标准的光源属性,用于定义光源的形状、角度衰减(如聚光灯)和空间分布模式。
核心近似:分离遮挡与着色
这个方法最关键的特点,也是其被称为"近似"的原因,在于它做出了一个重要的简化假设。
- 核心观点: 该技术假设遮挡(Shadowing) 和着色(Shading) 是两个可以独立计算然后相乘的项。
在物理上,这是不完全正确的。真实世界的光照应该在渲染方程的积分中将可见性函数(Visibility)、光照函数(Lighting)和材质反射函数(BRDF)三者共同考虑,即 ∫ V(ω) * L(ω) * f(ω) dω。
将它们分离为 (∫ V(ω) dω) * (一个预计算的光照项) 会在某些情况下导致能量损失或与真实物理光照的偏差,特别是在处理具有复杂高光的材质和大型面光源时。
深度阅读: [Heitz et al. 2018] 的论文引言部分对这种近似及其可能导致的问题有非常精彩的论述。
采用此近似的理由与权衡
尽管存在物理上的不精确性,但在实时渲染,尤其是游戏引擎中,这种近似因其巨大的实践优势而被广泛采用。
-
核心观点: 这种近似以微小的精度损失,换取了性能、降噪和工程兼容性上的巨大收益。
-
优势:
- 降低噪声 (Less Noise): 使用解析或预计算的辐照度,避免了在着色阶段对光源进行蒙特卡洛采样,从而从根源上减少了光照计算引入的噪声,使最终画面更平滑。
- 向后兼容性 (Backwards Compatibility): 这是在大型项目和商业引擎中至关重要的一点。采用这种方法,可以确保新的、基于随机采样(Stochastic)的光源渲染出的结果,与引擎中原有的、非随机采样的传统光源看起来完全一样。这使得新技术可以平滑地集成到现有渲染管线和美术工作流中,而不会造成视觉效果的不一致。这也是高端PC游戏中ReSTIR实现采用此方案的重要原因。
-
权衡:
- 这种近似对于追求极致物理精确度的非游戏领域(如影视特效、建筑可视化)可能不够理想。在这些场景下,更精确地耦合遮挡和着色计算会是未来的一个重要优化方向。
Denoising: 基于时域方差引导的空域-时域滤波
本页内容介绍了在渲染管线中,着色(Shading)步骤之后专门用于处理光线追踪等技术引入的噪声的降噪(Denoising) 流程。尽管前面的TSR(Temporal Super Resolution)已经能提供不错的基础效果,但一个专用的降噪器对于高质量的最终图像至关重要。
核心策略:统一处理与分离信号
-
统一降噪通道 (Single Denoising Pass): 为了效率,所有光源(直接光、间接光等)的着色结果会先累积到两个独立的渲染目标(Render Targets)中,然后通过一个统一的降噪通道进行处理。
-
分离漫反射与高光信号 (Diffuse and Specular Signals): 光照信号被分为漫反射(Diffuse) 和高光(Specular) 两部分,并分别进行降噪。这是因为它们的噪声特性和频率分布不同,分开处理可以取得更好的效果。
-
信号解调 (Demodulation): 在降噪之前,一个关键的预处理步骤是信号解調。
- 核心观点: 将材质本身的属性(如Albedo、BRDF)从光照信号中分离出去。
- 目的: 降噪器的目标是平滑(模糊)随机的、高频的噪声,而不是静态的、确定性的材质细节。如果不进行解调,降噪器在模糊噪声的同时也会模糊掉材质的纹理细节(比如Albedo贴图),导致画面变糊。
- 实现: 通常通过除法来实现,例如
DenoisingInput = ShadedColor / Albedo。降噪完成后,再将材质属性乘回去(Remodulation)。
算法基础:SVGF (Spatiotemporal Variance-Guided Filtering)
整个降噪器的设计理念基于业界经典的 SVGF (空域-时域方差引导滤波) 算法。其核心思想是结合时域滤波(Temporal Filter) 和空域滤波(Spatial Filter) ,并利用时域方差(Temporal Variance) 来智能地控制滤波强度。
阶段一:时域滤波 (Temporal Filter)
- 核心观点: 利用历史帧信息来稳定当前帧的像素,并计算信号的稳定性。
- 流程:
- 将前一帧已经降噪过的结果(History Buffer)通过运动矢量(Motion Vectors)重投影(Reproject) 到当前帧。
- 将重投影的历史信息与当前帧的原始、带噪的着色结果进行混合(Accumulate) 。
- 在混合过程中,计算信号的时域方差(Temporal Variance) 。这个方差值衡量了一个像素的颜色值在连续帧之间的变化剧烈程度。
- 低方差意味着像素颜色稳定,可能是干净的区域或噪声已被有效抑制。
- 高方差意味着像素颜色剧烈跳动,原因可能是:① 仍然存在大量噪声;② 场景发生了变化(如物体移动、遮挡变化)。
阶段二:空域滤波 (Spatial Filter)
- 核心观点: 根据时域方差的大小,自适应地对像素进行空间模糊。
- 流程:
- 使用前一阶段计算出的时域方差作为噪声指示图(Noise Indicator) 。
- 对图像进行空间滤波(例如,使用一个带边缘感知的滤波器,如 Cross-Bilateral Filter)。
- 关键在于自适应性(Adaptive Filtering):
- 对于方差高(即噪声嫌疑大)的像素,使用一个更强的滤波(更大的滤波核、更高的混合权重),以有效地平滑噪声。
- 对于方差低(即信号稳定)的像素,使用一个很弱的滤波甚至不进行滤波,从而最大程度地保留图像细节。
- 最终效果: 这种方法实现了“只在需要的地方进行模糊”,在有效去除噪声的同时,避免了对整个画面的无差别模糊,实现了高质量的降噪效果。
Temporal Filter: Accumulation and Rectification
这是整个时间抗锯齿和超分辨率(TSR)流程中的核心步骤之一,主要负责融合历史帧与当前帧的信息,并确保融合过程的稳定性和准确性,避免产生鬼影(Ghosting)等瑕疵。
核心数据积累
在时间滤波阶段,我们的主要目标是积累(Accumulate)光照信息,以平滑噪声并构建更完整的图像。为了更智能地处理历史数据,我们不仅积累颜色,还积累了颜色的统计数据(矩)。
-
光照数据积累:
- 格式: 使用两个
R11G11B10F格式的渲染目标(RT),分别存储漫反射(Diffuse)和高光(Specular)光照。这是一种32位的浮点格式。 - 关键技术: 随机浮点量化 (Stochastic Float Quantization)。这是一个非常关键的优化。直接使用低精度浮点格式(如
R11G11B10F)来累积颜色会因为精度不足而产生色带(Banding)或色彩偏移。通过在存入数据时加入一个微小的随机噪声,可以将量化误差分散成高频噪声,这种噪声在时间上累积时会被平均掉,从而在不增加存储成本的情况下,达到接近64位浮点缓冲区的视觉效果。
- 格式: 使用两个
-
矩(Moments)积累:
- 格式: 使用
R16G16B16A16F格式的RT,存储光照亮度(Luminance) 的第一和第二矩(1st and 2nd moments)。同样,漫反射和高光各有一套。 - 用途: 第一矩本质上就是颜色的平均值,而第二矩则用于计算方差(Variance) 。方差可以告诉我们历史数据在一个邻域内的变化剧烈程度,是后续做历史数据筛选(Rectification)的关键依据。
- 格式: 使用
-
HDR数据处理:
- 核心观点: 为了防止在高动态范围(HDR)场景中,亮度值超出浮点格式(如
Float11或Float16)的可表示范围而导致数据被截断(Clamp),所有的光照和矩数据都存储在预曝光空间(Pre-exposed Space) 中。这意味着在存入RT前,已经将场景的曝光应用到了颜色值上,将其映射到了一个更合适的数值区间。
- 核心观点: 为了防止在高动态范围(HDR)场景中,亮度值超出浮点格式(如
历史数据修正 (History Rectification)
当我们将上一帧的颜色(历史数据)通过运动矢量投影到当前帧时,它不一定总是有效的(例如,物体被遮挡后又出现)。直接使用无效的历史数据会产生鬼影。因此,我们需要一个机制来验证和修正这些历史数据,这个过程称为历史修正(History Rectification) 。
-
5x5邻域钳制 (Neighborhood Clamp):
- 核心思想: 我们认为,有效的历史颜色应该与当前帧像素周围的颜色相似。因此,我们在当前帧中取当前像素周围的一个 5x5 邻域,计算出这个邻域内颜色的最小值和最大值,形成一个包围盒(AABB)。然后,我们将重投影过来的历史颜色钳制(Clamp) 在这个包围盒内。
- 性能优化: 5x5的邻域采样(25次)对于每个像素来说开销很大。为了优化,通常在计算着色器(Compute Shader)中,会将这个邻域的数据预先加载到高效的组共享内存(Groupshared Memory) 中,供线程组内的所有线程共享和快速访问。
-
关键技术与技巧:
-
YCoCg空间下的方差裁剪 (Variance Clipping):
- 直接在RGB空间对颜色进行钳制,可能会导致色彩偏移(Color Shift) 。例如,一个偏红色的历史颜色被钳制后,可能会丢失其红色分量,变成灰色。
- 为了解决这个问题,钳制操作在 YCoCg 色彩空间中进行。这个空间将亮度(Y)和色度(Co, Cg)分离。通过主要对亮度分量进行严格的裁剪,同时对色度分量采用更宽松的策略,可以在修正亮度的同时最大限度地保留原始的色彩,显著减少颜色失真。
-
基于邻域距离的动态历史权重:
- 核心思想: 当一个历史颜色值远远超出了当前帧邻域的包围盒时,它很可能是无效的(比如来自一个刚刚被遮挡的物体)。传统方法只是简单地将其钳制到边界,但这仍然可能产生鬼影。一个更智能的方法是:历史值离包围盒越远,我们对它的信任度就越低,就越应该加速丢弃它,转而相信当前帧的数据。
- 实现方式: 计算历史颜色与被钳制后的颜色之间的距离,并将这个距离归一化。这个归一化的距离越大,代表历史数据越不可信。
// 计算历史颜色被钳制后的结果 float3 ClampedHistoryDiffuseLighting = clamp(HistoryDiffuseLighting, DiffuseNeighborhood.Center - DiffuseNeighborhood.Extent, DiffuseNeighborhood.Center + DiffuseNeighborhood.Extent); // 计算历史颜色与邻域边界的归一化距离 float NormalizedDistanceToNeighborhood = length(abs(ClampedHistoryDiffuseLighting - HistoryDiffuseLighting) / max(DiffuseNeighborhood.Extent, 0.1f)); // 距离越大,信任度越低 float DiffuseConfidence = saturate(1.0f - NormalizedDistanceToNeighborhood);- 这个
DiffuseConfidence值后续会用来降低历史帧的混合权重(或者说减少历史积累的帧数上限) ,从而快速淡出无效的历史信息,极大地减少鬼影。
-
对重建样本放宽钳制:
- 背景: 在使用时间超分辨率(TSR)时,当前帧只有一部分像素是真实渲染的,另一部分是靠历史信息重建的。这些重建的样本本身就不如真实渲染的样本可靠。
- 问题: 在一些高频细节区域(如细小的金属光栅),由于亚像素抖动,每一帧的输入数据可能会有巨大差异。如果对这些区域的重建样本使用过于严格的邻域钳制,可能会错误地频繁拒绝有效的历史信息,导致图像闪烁不稳定。
- 解决方案: 对重建的像素样本,适当放宽(Relax)邻域钳制的范围。这提高了在这些困难区域的稳定性,允许历史信息在一定程度上“跳变”,以适应几何细节的剧烈变化。
-
空间降噪滤波器 (Spatial Filter)
在时间滤波(Temporal Filtering)之后,我们引入一个空间滤波器,其核心目标是清理时间累积后仍然残留的噪点。这个滤波器被设计为在时间历史累积之后运行,这样做的好处是避免了模糊效果在帧间循环传递(Recurrent Blurring) ,从而让画面在发生遮挡剔除(Disocclusion)后能更快地收敛到清晰、正确的结果。
核心设计:单通道稀疏核 (Single-Pass Sparse Kernel)
为了在性能和效果之间取得平衡,这个空间滤波器采用了与传统方法(如多遍 A-Trous 滤波)不同的设计。
- 核心观点: 我们放弃了昂贵的多遍 A-Trous 滤波,转而采用一个单通道的稀疏卷积核(Single-pass sparse kernel) 。
- 关键技术:
- 逐像素旋转 (Per-pixel Rotation): 这个稀疏核在每个像素上都会进行旋转。这会在屏幕空间上形成一个高频、随机的采样模式,而不是一个固定的网格。
- 与 TSR 协同工作: 单独看,稀疏旋转核会在图像上留下“洞”(未被采样的区域)。但这里的巧妙之处在于,后续的 TSR (时间超分辨率) 能够非常有效地平滑掉这些高频的“洞”,最终整合出干净的图像。这是一种典型的空间与时间协同处理的思路。
智能激活:基于相对方差的条件性滤波 (Smart Activation: Relative Variance)
为了保护图像细节并提升性能,这个空间滤波器并不会作用于屏幕上的每一个像素,而是有条件地激活。
- 核心观点: 仅在相对时间方差(Relative Temporal Variance) 较高的像素上运行空间滤波,这样既能保证效率,又能最大程度地保留稳定区域的图像锐度。
- 激活条件:
(Variance / Lighting) > Threshold - 关键术语:
- 相对方差 (Relative Variance): 通过将方差(代表噪声水平)与像素亮度(Lighting)进行比较,我们可以判断噪声的“可见”程度。在非常明亮的区域(如高光),即使有微小的数值精度误差,也可能导致很大的绝对方差,但人眼并不觉得它是噪声。使用相对方差可以有效避免在这种情况下进行不必要的模糊。
边缘保护:SVGF 边缘停止函数 (Edge-Stopping)
在进行空间滤波(模糊)时,最关键的是不能模糊掉物体的边缘,否则会产生漏光或轮廓不清的问题。
- 核心观点: 采用 SVGF (时空方差引导滤波) 中经典的边缘停止函数来保护图像的结构。
- 判断边缘的依据:
- 深度 (Depth): 防止跨越几何边缘进行采样。
- 法线 (Normal): 防止跨越不同朝向的曲面进行采样。
- 时间方差 (Temporal Variance): 防止将稳定区域的像素与刚被揭示的、充满噪声的区域混合。
特殊处理:新像素的收敛策略 (Disocclusion Handling)
对于因物体或相机移动而新出现的像素(Disoccluded Pixels),它们没有历史信息,因此噪声非常严重,需要特殊处理。
- 核心观点: 对新出现的像素(最多追溯 4 帧),采用一套更激进的策略来加速其收敛,并在累积足够数据后平滑地过渡回常规模式。
- 关键策略:
- 增加空间采样数 (Increase Spatial Samples): 对这些高噪声像素,使用更多的空间样本进行滤波,以更快地压制噪声。
- 在色调映射空间累积 (Accumulate in Tonemapped Space): 这是抑制 “萤火虫” (Fireflies)——即那些异常明亮的噪点——的有效技巧。通过在非线性的色调映射空间进行累积,可以有效压缩这些极端亮度的像素值,防止它们对画面产生污染。
- 随时间淡出 (Fade Out): 上述两种强化处理会随着像素累积的有效帧数增加而逐渐减弱。当一个像素累积了 4 帧或更多的历史数据后,这些特殊处理将完全关闭,像素转为常规的滤波流程。
时间抗锯齿升级(Temporal Upscaling)与降噪(Denoising)的冲突
核心矛盾:分辨率不匹配
当渲染管线中同时存在降噪(Denoising)和时间超分辨率(Temporal Upscaling)时,会出现一个根本性的问题:它们在不同的分辨率下积累历史信息。
-
降噪器 (Denoiser): 在 渲染分辨率 (Render Resolution) 下工作。它会维护一个渲染分辨率的历史信息缓冲(History Buffer),用于在时间维度上平滑噪声。
-
时间超分 (Temporal Upscaler): 在 显示分辨率 (Display Resolution) 下工作。它利用历史帧(同样是显示分辨率)来重建当前帧的细节,从而将渲染分辨率的图像提升到显示分辨率。
这个流程导致了一个关键的错位:降噪器在低分辨率下的一个历史像素,经过超分后会对应到显示分辨率下的多个像素。当下一帧进行降噪时,这多个高分辨率像素在做历史信息重投影(Reprojection)时,可能会追溯到同一个低分辨率的历史像素。
- 核心观点: 降噪器被迫在一个低分辨率的历史信息上进行累积,而这个历史信息需要服务于一个更高分辨率的当前帧。这导致降噪器在累积时混合了本不相关的像素信息,最终的视觉表现就是光照变得模糊,丢失了高频细节。这本质上是一个信息采样率不匹配的问题。
问题的影响:取决于降噪策略
这个分辨率不匹配问题造成的影响程度,与你使用的降噪器类型密切相关。
逐光源降噪器 (Per-Light Denoisers)
- 工作方式: 这类降噪器不直接处理最终的光照结果,而是只对随机采样的部分进行降噪,例如阴影项 (shadow term),如阴影遮蔽(shadow mask)或光照比率(ratio estimator)。而每个像素的光照计算本身是每帧都重新、非随机地执行的。
- 影响: 问题不那么显著。因为只有阴影部分会被时间累积所模糊,而大部分光照信息是每帧重新计算的,保持了清晰度。模糊通常只在半影区域 (penumbras) 比较明显。
合并辐照度降噪器 (Merged Irradiance Denoisers)
- 工作方式: 这类降噪器直接对多个光源计算后得到的完整的、合并后的光照结果(辐照度) 进行降噪。
- 影响: 问题非常严重。因为它模糊的是全部的光照信息,包括高光的细节。这在特写镜头(例如人脸)上尤其致命,因为人眼对高光细节 (specular detail) 的缺失非常敏感,模糊的高光会让材质看起来像塑料一样廉价。
一个不成功的尝试:模拟逐光源降噪
讲师团队曾尝试将逐光源降噪的思路应用到合并辐照度的降噪上,以期减轻模糊问题。
-
思路:
- 在每个像素上,找到贡献最大的 “最重要光源” (most important light) 或者说BRDF。
- 将这个最重要光源的贡献从总光照中“分离”出去(factor out)。
- 只对剩余的、贡献较小的光照部分进行降噪。
- 最后再将之前分离出去的最重要光源的贡献乘回去。
-
失败原因:
- 引入新噪声: “最重要光源”的选择过程本身是随机和不稳定的,这会引入一种新的“光源选择噪声”,在复杂光照场景下尤为明显。
- 滤波基础错误: 将BRDF分离出去后,后续的时间和空间滤波器都是在非物理、不正确的数值上进行操作,破坏了光照的能量守恒和物理正确性。
- 空间瑕疵: 在相邻像素间,“最重要光源”的选择可能发生突变(不连续)。当空间滤波器跨越这种边界时,会混合来自不同基准的值,产生诡异的块状瑕疵。
理想的解决方案与现实的瓶颈
-
理想方案: 最直接的解决办法是让降噪器的历史缓冲区 (history buffer) 也工作在显示分辨率下。这样,当前帧的每个像素都能与历史帧中的一个像素进行精确对应,从根本上消除了“混合不相关像素”的问题。
-
现实瓶颈: 性能开销过大 (Prohibitively expensive)。
- 关键术语: 这种方案的性能瓶颈在于内存带宽和计算成本。
- 以主机为例,常见的做法是从 1080p (渲染分辨率) 升级到 4K (显示分辨率)。如果要求降噪器的时间滤波阶段在4K分辨率下运行,那么这一步的像素处理量将是原来的4倍,导致整个Pass的耗时增加约4倍,这在性能预算紧张的主机平台上是难以接受的。
-
未来展望: 尽管当前代价高昂,但这仍然是一个值得为高端PC GPU进一步研究的方向,可以作为一种质量分级选项,为拥有足够性能的硬件提供更好的视觉效果。
着色置信度 (Shading Confidence)
本页的核心思想是引入一个名为 “着色置信度 (Shading Confidence)” 的动态指标,用于自适应地调整降噪算法的强度。其基本原则是:如果我们有理由相信当前帧的随机采样着色结果已经足够接近“真实”结果,那么就应该减少降噪的力度,以保留更多细节并避免不必要的模糊。
核心思想:自适应地调整降噪强度
对于每个像素,我们并非总是需要最大强度的降噪处理。某些像素可能在本帧的随机光线采样中已经“足够幸运”,捕捉到了大部分的光照能量。
- 核心观点:当一个像素的着色结果在当前帧已经具有很高的可信度时,我们应该信任当前帧的数据,减少对历史数据(时间滤波)和邻域像素(空间滤波)的依赖。
- 关键术语:着色置信度 (Shading Confidence),一个用于量化当前帧着色结果可靠性的度量。
"置信度"的启发式计算方法
为了量化“置信度”,讲座提出了一种非常有效的启发式方法,它利用了“可见光照列表(Visible Light List)”提供的信息。
-
计算原理:通过比较 “当前帧实际采样到的能量” 与 “理论上可能影响该像素的总能量” 的比例来得出置信度。
-
关键术语:可见光照列表 (Visible Light List),这是一个预计算的数据结构,它记录了对于一个像素(或一个tile),哪些光源可能对其产生贡献以及它们可能贡献的总能量上限。
-
计算公式:
- :当前帧通过随机采样成功命中的光源所贡献的能量总和。
- :根据可见光照列表,所有可能影响该像素的光源的潜在能量总和。
-
实践案例:想象一个场景,某个像素的颜色主要由一个非常亮的高光点决定,该高光贡献了80%的能量。如果我们的光线采样在本帧成功命中了这个高光,那么我们的“着色置信度”就至少是80%,这是一个非常高的值。
如何利用置信度
计算出置信度后,我们可以用它来指导后续的降噪和时间超分辨率(TSR)流程。
- 高置信度像素的处理:
- 当一个像素的置信度很高时(例如 > 80%),意味着当前帧的“噪声”信号其实已经非常接近最终结果。
- 执行操作:我们可以将这个信号更直接地传递给 TSR (Temporal Super Resolution) 模块,并相应地降低历史帧的权重和减弱空间滤波的强度。
- 低置信度像素的处理:
- 如果置信度低,说明当前帧的采样丢失了大量重要信息,此时则需要更强的降噪,更依赖历史帧和邻域像素来填充缺失的细节。
实践中的挑战与解决方案
直接使用每帧计算出的置信度会引入新的问题。
- 挑战:时间上的不稳定性 (Temporal Instability)
- 由于光线采样是随机的,我们可能在第 N 帧命中了一个重要光源(高置信度),但在第 N+1 帧又错过了它(低置信度)。这种置信度的剧烈波动会导致降噪强度频繁变化,从而在画面上产生闪烁。
- 解决方案:时间上的稳定化处理 (Temporal Stabilization)
- 为了解决这个问题,需要对计算出的置信度值本身进行时间累积(Temporal Accumulation) 。通过平滑多帧的置信度结果,可以得到一个更稳定、变化更平缓的控制信号,从而避免闪烁。
主要优势
这种基于置信度的自适应降噪策略带来了显著的好处:
- 提升图像锐度 (Increased Sharpness):这是最直接的优势。对于高置信度的区域(如清晰的高光),我们减少了不必要的模糊,从而保留了更多的图像细节,使最终画面更加清晰锐利。
- 缓解降噪瑕疵 (Mitigating Denoising Artifacts):
- 高光鬼影 (Specular Highlight Ghosting):传统的时间降噪在处理移动的高光时,由于过度依赖历史帧,容易产生拖影或“鬼影”。提高对当前帧高置信度高光的信任,可以有效抑制这种现象。
- 高光模糊 (Specular Blurriness):在非平坦或复杂的表面上,对历史高光进行精确的运动矢量重投影非常困难,常常导致模糊。本方法通过在当前帧直接保留清晰的高光,避免了这一难题。
光线追踪阴影:挑战与优化
为什么选择光线追踪处理阴影
-
核心观点: 现代渲染引擎倾向于使用硬件光线追踪(Hardware Ray Tracing) 来计算阴影,以替代传统的阴影贴图(Shadow Maps)技术。
-
主要优势: 这种方法的核心优势在于避免了为每个光源维护和渲染多张阴影贴图的巨大开销。尤其是在处理大量动态光源的场景中,管理海量的 Shadow Maps 会成为严重的性能瓶颈,而光线追踪提供了一个更统一、可扩展的解决方案。
光线追踪在复杂场景中的核心挑战
-
核心观点: 尽管光追是理想的阴影解决方案,但我们不能直接将用于主视图渲染的超高精度几何体(例如 Nanite 级别的模型)直接用于光线追踪。这样做的代价是无法承受的。
-
具体挑战:
- 高昂的内存开销 (High Memory Overhead): 用于光线追踪的加速结构 BVH (Bounding Volume Hierarchy) 对每个顶点都有不小的内存占用。对于现代游戏中动辄数亿甚至数十亿三角形的场景,直接构建 BVH 会消耗海量内存。
- 高昂的构建与追踪成本 (Expensive Build and Tracing):
- 构建成本: 为极其复杂的场景几何构建 BVH 本身就是一个非常耗时的过程。
- 追踪成本: BVH 结构过于庞大和复杂,会导致光线追踪的效率显著下降。
- 严重的实例重叠问题 (Instance Overlap): 在现代游戏场景制作中,美术师经常使用 "kitbashing" 的方法,即通过大量重复、堆叠、穿插预制件来搭建场景。这会导致大量的几何实例在空间中重叠,从而急剧增加光线追踪的成本。一条光线在找到最终的表面前,可能需要与许多重叠的包围盒(Bounding Box)进行无效的求交测试,严重拖慢追踪速度。
解决方案:为光追优化场景表示
-
核心观点: 为了让光线追踪在复杂场景中变得可行,我们必须对用于构建 BVH 的场景几何进行简化和优化,而不是直接使用渲染用的高精度模型。
-
关键优化策略:
- 简化的代理网格 (Simplified Proxy Meshes): 为高精度的渲染模型创建一个低多边形的代理版本,专门用于光线追踪和阴影计算。这个代理模型在保持物体大致轮廓和遮挡能力的同时,大幅减少了几何复杂度。
- 激进的实例剔除 (Aggressive Instance Culling): 制定更严格的剔除策略,将对阴影贡献较小或者远离摄像机的物体实例从光追场景中移除,从而精简 BVH 的规模。
- 聚合表示 (Aggregate Representations): 对于远处的或者成群的复杂物体,不再使用单独的三角形网格表示,而是采用更宏观、更抽象的聚合形式。例如,使用公告板(Impostor)、体素(Voxel)或者其他简化形式来代表一片森林或一座远处的城市,以极低的成本提供近似的遮挡信息。
World Traces (世界场景追踪)
本页介绍了一种针对大规模世界场景进行光线追踪的优化策略。其核心思想是为不同距离的场景几何体采用不同复杂度的光线追踪表示,这是一种针对光线追踪加速结构(AS)的LOD (Level of Detail) 方案,旨在平衡性能与视觉精度。
Near Field (近场) 追踪
核心观点: 在靠近玩家的区域,使用中等复杂度的代理模型进行光线追踪,以在性能和近处细节的精确性之间取得平衡。
- 作用范围: 定义一个以玩家摄像机为中心的特定半径区域,例如 150米。所有在此范围内的光线追踪计算都属于近场追踪。
- 关键技术:Proxy Meshes (代理网格)
- 这不是用于最终光栅化渲染的高精度模型,而是一个多边形数量较低的简化版本。
- 如示意图所示,光栅化时使用的可能是高模(Rasterized Triangles),而光线追踪时则会使用这个简化后的代理模型(Ray Tracing Proxies)。
- 目标: 在保证近距离光线追踪效果(如阴影、反射)足够精确的同时,显著降低构建和遍历底层加速结构 (BLAS) 的开销。
Far Field (远场) 追踪
核心观点: 对于远离玩家的区域,使用极度简化的几何体和独立的、更简单的顶层加速结构(TLAS),以最大限度地降低长距离光线的追踪成本。
- 触发条件: 当一条光线没有命中任何近场中的代理网格,并延伸至近场半径(150米)以外时,它将继续在远场中进行追踪。
- 关键技术与优化:
- 重度简化的几何体: 对模型进行非常激进的多边形削减。
- 实例合并 (Instance Merging): 将大量独立的物体实例合并成一个或少数几个大的几何体。这能极大简化场景的结构。
- 独立的TLAS (Top-Level Acceleration Structure):
- 远场的所有简化几何体被组织在一个完全独立的TLAS中。
- 核心优势: 这个TLAS的层级更浅、结构更简单,因此BVH(Bounding Volume Hierarchy)的遍历速度极快。追踪远距离光线时,无需遍历复杂的近场TLAS,从而大幅提升了性能。
Implementation Note (实现说明)
核心观点: 在当前世代的主机上,默认采用内联光线追踪(Inline Ray Tracing)以获得更佳性能。
- 关键术语:Inline Ray Tracing (内联光线追踪)
- 这是一种在通用着色器(如Compute Shader或Pixel Shader)中直接调用光线追踪指令(例如
TraceRay)的技术。 - 它与传统的、依赖于专门的Ray Generation, Miss, Hit着色器管线(DXR / Vulkan RT Pipeline)的方法相对。
- 选择原因: 根据实践,这种方式在当代主机硬件上能提供更高的性能,可能是因为它提供了更灵活的控制流和更少的调度开销。
- 这是一种在通用着色器(如Compute Shader或Pixel Shader)中直接调用光线追踪指令(例如
网格表示不匹配问题 (Mesh Representation Mismatches)
本页探讨了在混合渲染管线(Hybrid Rendering Pipeline)中使用光线追踪时,一个常见且棘手的问题:用于光线追踪的代理网格 (Proxy Mesh) 与用于光栅化的原始几何体 (Rasterized Geometry) 之间存在差异,从而引发一系列渲染瑕疵。
核心观点:代理网格与原始几何体的不一致性
在现代渲染引擎中,为了加速光线追踪(尤其是BVH的构建和遍历),我们通常不会直接使用高精度的、用于最终光栅化的渲染网格。取而代之的是一个经过简化的、拓扑结构更优的代理网格。
- 根本问题: 这个代理网格和最终在屏幕上通过光栅化渲染的高精度网格并不完全匹配。这种几何上的不匹配(Mismatch) 是许多光追瑕疵的根源。
不匹配导致的具体渲染瑕疵
1. 源于几何差异的自遮挡 (Self-shadowing near ray origin)
这是最典型、最常见的瑕疵,通常被称为“阴影粉刺 (Shadow Acne)”的变种。
- 问题成因:
- 当一个表面点(比如在G-Buffer中)需要计算阴影时,我们会从这个点(光线起点 Ray Origin)沿着光线方向发射一根阴影光线。
- 这个光线起点位于光栅化网格的表面上。
- 然而,这根阴影光线的相交测试是在代理网格(及其BVH)上进行的。
- 由于代理网格与光栅化网格存在细微偏差(例如,代理网格可能略微“包裹”或“内陷”于原始网格),导致光线起点可能已经处于代理网格的内部或与其表面极其接近。
- 最终结果: 光线一发射就立即与它“出发”的那个代理三角面相交,错误地判断该点处于阴影中,从而在物体表面产生错误的自遮挡斑点。
2. 动画与Alpha蒙版几何体 (Animated / Alpha Masked Geometry)
对于动态变化的物体,这种不匹配问题会更加突出和复杂。
-
动画几何体 (Animated Geometry):
- 问题: 对于骨骼动画(Skinned Meshes)或顶点动画,高精度的光栅化网格每帧都在进行复杂的形变。而用于光追的代理网格为了性能,可能更新频率较低,或者使用了更简化的形变方法(例如,只更新包围盒)。
- 结果: 这会导致光追产生的效果(如阴影、反射)与物体在屏幕上实际渲染的位置和形状产生时空上的不同步。你可能会看到一个角色的影子与他当前的姿势不完全匹配。
-
Alpha蒙版几何体 (Alpha Masked Geometry):
- 问题: 使用Alpha Masking技术的物体(如树叶、铁丝网)在光栅化时,通过在像素着色器中
discard操作来实现复杂的轮廓。 - 挑战: 它的代理网格通常只是一个简单的四边形(Quad)或基础模型,完全忽略了透明贴图提供的精细镂空信息。
- 结果: 光线追踪会把这个物体当作一个实体来处理。例如,一棵树的树冠,在光栅化下可以看到叶片间的缝隙,但它投射出的光追阴影可能是一个密不透风的、与代理网格形状一致的“方块”或“球体”,完全丢失了Alpha Masking带来的细节。
- 问题: 使用Alpha Masking技术的物体(如树叶、铁丝网)在光栅化时,通过在像素着色器中
网格表示不匹配问题 (Mesh Representation Mismatches)
在混合渲染管线(Hybrid Rendering Pipeline)中,我们通常需要为光线追踪和光栅化分别准备几何体。这两套几何体之间的差异,是导致渲染瑕疵(Artifacts)的一个重要来源。
核心问题:渲染与光追的几何体不一致
在实践中,用于光线追踪的几何体(通常称为代理网格或 Proxy Mesh)往往无法与最终用于光栅化的几何体完全匹配。这么做的主要原因是性能考量,因为为光线追踪构建加速结构(BLAS/TLAS)需要处理干净、稳定且相对简化的网格。
- 核心观点: 光线追踪所使用的代理网格(Proxy Mesh) 和光栅化所渲染的高精度几何体(Rasterized Geometry) 之间存在的差异,是导致瑕疵的根本原因。
- 主要表现: 这种不匹配最常导致的视觉问题是错误的自阴影(Incorrect Self-Shadowing) 。
“自阴影”瑕疵的产生机制
当一个物体的表面细节在两套几何体中不一致时,就会出现问题。光线追踪通常从光栅化渲染出的精确表面位置发射光线,但这些光线随后是与不那么精确的代理网格进行求交测试的。
- 光线起点: 光线的起始点(Ray Origin)位于光栅化几何体的表面上。
- 求交对象: 光线与光线追踪代理网格进行相交测试。
- 问题成因: 由于代理网格与原始光栅化网格不完全吻合(例如,代理网格的某个三角面比光栅化表面更“凸出”),导致从光栅化表面发射出的光线,在离开其起点的瞬间就立即与代理网格的某个三角面相交。
- 最终效果: 系统会错误地认为光线被物体自身遮挡,从而在该点产生阴影,形成不自然的暗斑或条纹,这种现象通常被称为 “阴影粉刺” (Shadow Acne)。
常见导致不匹配的场景
以下是一些在游戏引擎中极易引发几何体不匹配问题的典型场景:
-
曲面细分 (Tessellation)
- 光栅化管线可以通过硬件曲面细分在运行时动态增加模型细节,生成非常平滑和复杂的表面。
- 但为了性能,送入光线追踪管线的代理网格通常是未经细分的基础控制网格(Base Control Mesh) 。讲座中的墙壁就是典型的例子。
-
动画与形变几何体 (Animated / Deformed Geometry)
- 包括角色蒙皮、顶点动画、布料模拟等。这些技术会逐帧修改顶点位置。
- 为了避免频繁重建光追加速结构(BLAS)带来的巨大开销,可能会使用一个简化的、或更新不那么频繁的代理网格,从而导致与每帧精确的光栅化结果不一致。讲座中的角色衣服就是这个情况。
-
Alpha Masked 几何体
- 例如用一个简单的四边形(Quad)面片加上带透明通道的贴图来渲染复杂的树叶或铁丝网。
- 光栅化会根据 Alpha Test 形成精细的镂空轮廓,但光线追踪的代理网格仍然是那个实体四边形,导致阴影形状完全错误。
网格表示不匹配问题 (Mesh Representation Mismatches)
本页探讨了在混合渲染管线(Hybrid Rendering, 即光栅化与光线追踪结合)中一个常见且棘手的问题:用于光栅化的几何体与用于光线追踪的几何体之间存在差异,从而引发各种渲染瑕疵。
光追代理网格与光栅化几何体的不匹配
在混合渲染中,为了加速光线追踪,通常不会直接使用高精度的、用于光栅化的渲染网格(Render Mesh)来构建 BVH(Bounding Volume Hierarchy,包围盒层次结构) 。取而代之的是,我们会使用一个简化的版本,称为 代理网格(Proxy Mesh) 。这种不完全匹配是导致瑕疵的主要根源。
-
核心观点: 为了光追性能,我们牺牲了几何精度,用简化的代理网格来构建加速结构,但这导致了光追所“看到”的场景与光栅化渲染出的场景并非完全一致。
-
关键问题: 自遮挡(Self-shadowing)
- 现象: 当从一个物体表面发射光线(例如,为了计算阴影)时,如果光线的起始点位于高精度渲染网格上,但这个点却不幸地落在了低精度代理网格的内部,那么光线在出发的瞬间就会与代理网格自身相交。
- 后果: 系统会错误地认为该点处于阴影中,导致物体表面出现不自然的暗斑或噪点。这个现象在业界通常被称为“阴影粉刺 (Shadow Acne)”。
- 典型解法: 在发射光线时,将光线的起始点沿着表面法线方向向前推移一个极小的距离(常被称为 Ray Epsilon 或 Ray T-min),以确保它处于代理网格的外部,从而避免错误的自相交。
动态与Alpha-Masked几何体的挑战
除了静态不透明物体外,动画和使用Alpha Masking的几何体进一步加剧了表示不匹配的问题,因为要精确地在光追中表示它们,代价非常高昂。
-
核心观点: 对于动画和Alpha-Masked这两类在光栅化中处理相对高效的几何体,要在光线追踪中实现精确表示,会带来巨大的性能开销。
-
动画几何体 (Animated Geometry)
- 挑战: 角色蒙皮、布料模拟等动画几何体,其顶点位置每帧都在变化。
- 光追代价: 这意味着用于光追的 BVH 需要每帧进行重建(Rebuild)或重构(Refit) 。这是一个计算量巨大的操作,会严重影响性能。因此,开发者可能会选择使用更简化的、更新不那么频繁的物理代理(如胶囊体)来进行光追计算,但这显然会加剧与实际渲染网格的不匹配。
-
Alpha-Masked 几何体 (Alpha Masked Geometry)
- 定义: 指利用纹理的Alpha通道来“镂空”一块几何体,常见于树叶、铁丝网、格栅等。
- 光栅化方式: 非常廉价。在片元着色器中进行 Alpha测试(Alpha Test) ,不符合条件的片元直接被
discard即可。 - 光追难题:
- 几何表示: 一个简单的面片(Quad)在BVH中是完全不透明的。光线一旦命中,就会停止,无法表现出“镂空”的效果。
- 精确方案与代价:
- 方案一:细分网格。根据Alpha贴图的形状预先将面片细分成复杂的、真正镂空的多边形。但这会急剧增加三角形数量,导致BVH构建成本和内存占用飙升。
- 方案二:自定义相交着色器。在光线命中面片时,调用一个特殊的着色器(例如 DXR 中的 Any-Hit Shader),在着色器中采样Alpha贴图,判断此次命中是否有效。如果处于透明区域,则忽略本次命中,让光线继续传播。这种方式虽然灵活,但会显著增加光线遍历的开销。
代理网格(Proxy Mesh)的表示不匹配问题
本页的核心是探讨在光线追踪中使用代理网格(Proxy Mesh) 进行加速时,会遇到的一个关键问题:代理网格与实际渲染网格之间的几何差异(Mismatch) ,以及为什么简单的剔除策略无法完美解决由此引发的渲染错误。
几何不匹配导致的错误阴影
使用一个比实际渲染网格更简单的代理网格进行光线追踪相交测试,虽然能提升性能,但两者几何形状上的不一致会导致错误的渲染结果,尤其是阴影。
-
核心问题:光线可能会与代理网格相交,而实际上它本应穿过该区域并命中后方的真实表面,反之亦然。这会导致错误的遮挡(Incorrect Occlusion) ,即不该出现阴影的地方出现了阴影。
-
尝试的解决方案及其局限:一个直观的想法是使用正面/背面剔除(Front/Back Face Culling) 来过滤掉不正确的相交。然而,这种方法并不能完全解决问题。
- 剔除有效的情况:当光线先穿过代理网格的背面时,开启背面剔除可以成功忽略这次相交,让光线继续前进,最终正确地命中真实表面。
- 剔除失效的情况:当光线在命中真实表面前,先命中了代理网格的正面时,剔除策略会失效。因为从光线的角度看,这是一个有效的“正面”命中,系统会错误地认为光线被遮挡,从而产生一个本不该存在的阴影。
剔除策略带来的额外性能开销
即便不考虑视觉错误,强制启用正面或背面剔除本身也会带来性能上的负面影响。
-
关键观点:为光线追踪启用正面或背面剔除,会带来大约 10% 的性能开销(Overhead) 。
-
原因分析:这个开销主要源于它阻止了光线遍历加速结构(如BVH)时的提前退出(Early Exits) 。
- 在典型的阴影光线(Shadow Ray)检测中,我们只需要知道光线在到达光源前是否命中任何物体即可(Any-Hit)。一旦找到第一个遮挡物,无论其朝向,遍历过程就可以立即终止。
- 但如果启用了剔除(例如背面剔除),即使光线已经命中了物体的背面,遍历器也不能立即停止。它必须继续搜索,以防后面还有一个有效的“正面”遮挡物。这种无法“提前退出”的机制延长了遍历时间,从而导致了性能下降。
结论:需要回退机制
综合以上两点——无法完全解决的视觉错误和显著的性能开销,本页得出的结论是:
- 核心结论:我们不能单纯依赖代理网格和剔除策略来确保光线追踪的正确性。
- 解决方案方向:必须设计回退机制(Fallback Mechanisms) 来专门处理这些代理网格引发的不匹配问题,以保证最终渲染结果的鲁棒性和正确性。
Screen Traces (屏幕空间追踪)
本页探讨了一种利用屏幕空间信息来优化光线追踪效果的技术,主要目标是解决自遮挡问题,并在此过程中获得高质量的接触阴影。这是一种将屏幕空间方法的优点(高精度几何细节)与世界空间光线追踪的优点(不受屏幕限制)相结合的混合追踪 (Hybrid Tracing) 策略。
核心问题:不正确的自遮挡 (Incorrect Self-Shadowing)
在光线追踪中,当从一个表面发射光线(例如,用于计算阴影或环境光遮蔽)时,一个常见的问题是光线会立即与它自身所在的几何体相交。
- 问题根源: 光线追踪通常使用一个简化的代理网格 (Proxy Mesh) 或其加速结构(如 BVH)进行求交。由于浮点数精度问题或光线起点恰好在表面上,导致光线起点被判断为在几何体内部,从而产生错误的自身遮挡,形成“暗斑”或“阴影痤疮 (Shadow Acne)”。
解决方案:混合追踪策略
为了解决自遮挡问题,我们引入一个两步走的混合追踪策略:先在屏幕空间进行短距离追踪,再切换到世界空间。
-
核心观点: 利用屏幕空间深度缓冲的高精度信息,将世界空间光线的起点安全地“推”离原始表面,从而避免立即与自身相交。
-
具体步骤:
- 第一步:屏幕空间追踪 (Screen Trace)
- 从着色点开始,沿着光线方向在屏幕空间进行追踪。
- 这次追踪的求交对象是光栅化阶段生成的深度缓冲 (Depth Buffer),它包含了场景中所有可见物体的精确几何信息,远比用于光追的代理网格精细。
- 由于追踪的是像素化的最终图像深度,所以它自然地会“离开”原始表面,而不会发生自相交。
- 第二步:偏移世界追踪起点 (Offset World Trace Origin)
- 屏幕空间追踪会行进一段距离(直到碰到其他物体或达到最大距离)。
- 我们将这次屏幕空间追踪的终点作为新的、安全的起点。
- 第三步:世界空间追踪 (World Trace)
- 从这个被偏移后的新起点,发射真正的世界空间光线,在场景的 BVH 中进行求交测试,以确定远距离的遮挡物。
- 第一步:屏幕空间追踪 (Screen Trace)
-
图示分析 (“With Screen Traces”):
Screen Trace首先从表面出发,行进一小段距离。然后,World Trace从Screen Trace的终点开始,安全地向场景深处进行探索。
优势与挑战
优势:高质量的接触阴影 (Contact Shadows)
- 核心观点: 屏幕空间追踪是针对高精度的深度缓冲进行的,因此它能捕捉到代理网格(BVH)中不存在的高频几何细节。
- 效果: 这相当于免费获得了一次高质量的接触阴影计算。例如,角色衣服上的褶皱、地面的微小起伏等细节都能投射出精确的接触阴影,极大提升了画面的真实感和细节表现力。
挑战:精度与性能
-
挑战一:像素级精确 (Pixel Accurate)
- 与通常可以接受少量采样步进(tap)的屏幕空间效果(如SSAO)不同,此处的屏幕空间追踪必须是像素级精确的。
- 如果追踪步进过大,可能会“跳过”场景中一些很薄的遮挡物(比如栏杆、铁丝网),导致漏掉阴影,产生错误的结果。
-
挑战二:世界空间定义的追踪长度 (Length defined in world space)
- 光线的追踪距离通常是在世界空间中定义的(例如,阴影光线需要追踪到光源的距离)。
- 当一个表面与视线接近平行(grazing angle)时,一段较短的世界空间距离可能会映射到屏幕上非常长的像素距离。
- 在这种情况下,使用传统的固定步进光线步进(Fixed Stepping Ray Marching)会非常昂贵,因为它需要迭代大量步骤才能覆盖整个屏幕轨迹。因此,需要更高效的屏幕空间遍历算法(如使用层级深度缓冲或类似DDA的算法)来应对这一挑战。
Screen-Space Ray Tracing (Screen Traces)
本页主要探讨了在混合渲染管线中,如何高效、高质量地执行屏幕空间光线追踪(Screen-Space Ray Tracing) ,并如何处理其固有的局限性。核心技术是利用层级深度缓冲(Hierarchical Z-Buffer, HZB) 进行加速,同时通过多种策略来规避常见的视觉瑕疵。
HZB Tracing: 高效空间跳跃
为了在屏幕空间中快速追踪光线,我们不采用简单的固定步长前进,因为这会在空旷区域浪费大量计算。取而代之的是利用 HZB(Hierarchical Z-Buffer) 进行追踪。
-
核心观点: HZB 本质上是深度图的 mipmap 版本,每一层级存储了其覆盖区域内的最远深度值。这使得光线可以在屏幕空间的空白区域进行大步长的安全跳跃,而无需逐像素检查,从而极大地提升了追踪效率。
-
关键术语:
- HZB (Hierarchical Z-Buffer): 层级深度缓冲,用于加速空间查询和光线步进。
- 固定步长追踪 (Fixed Step Tracing): 效率低下的追踪方式,在空白区域浪费性能。如下图左侧所示,需要大量采样点。
- 分层追踪 (Hierarchical Tracing): 利用HZB的层级结构,实现高效的空间跳跃。
优化追踪质量:规避屏幕空间瑕疵
屏幕空间追踪技术虽然高效,但会带来一些特有的视觉问题。为了最小化这些瑕疵,我们采取了以下几种策略。
-
保守的表面厚度 (Conservative Surface Thickness)
- 核心观点: 默认假设所有表面的厚度都非常薄。当一条屏幕空间光线追踪到某个表面背后时,我们不轻易判定光线与该物体相交,而是倾向于认为光线“穿过”了它。在这种情况下,系统会回退到更精确的硬件光线追踪(Hardware Ray Tracing, HWRT) 来寻找真正的交点。
- 目的: 这种保守策略可以有效避免因深度信息不完整而导致的错误遮挡和漏光问题。
-
限制光线长度 (Limited Ray Length)
- 核心观点: 将屏幕空间光线的最大追踪长度限制在一个较短的距离内(例如本例中的20cm)。
- 原因: 较长的屏幕空间光线在追踪过程中,更容易受到深度缓冲区走样(depth buffer aliasing) 的影响,导致追踪路径出现偏差,从而产生条纹、断裂等明显的视觉瑕疵。限制长度是一种简单有效的规避手段。
-
混合深度采样 (Mixed Depth Sampling)
- 核心观点: 在判断光线是否与表面相交时,通过结合点采样(Point Sampling) 和双线性采样(Bilinear Sampling) 的深度值,并取其最小值,来有效避免自阴影(self-shadowing) 问题。
- 关键算法:
final_depth = min(PointSample(depth_buffer, uv), BilinearSample(depth_buffer, uv)) - 原因: 当光线非常贴近一个斜面时,仅使用点采样或双线性采样都可能因为采样位置的微小偏差,导致光线错误地与自身所在的表面相交。取两者中的最小值可以得到一个更“靠前”的深度值,从而帮助光线“安全”地掠过表面。
特殊处理: 应对未加入HWRT的实例
在一些场景中,为了优化性能,某些物体(例如大量的草、粒子等小规模实例)可能只会被渲染到G-Buffer和深度图中,但并不会被包含在硬件光追所需的加速结构(如BVH)里。
- 核心观点: 当屏幕空间追踪遇到这类特殊物体时,需要有一种机制来补偿HWRT数据的缺失,以便它们也能产生正确的阴影效果(特别是接触阴影)。
- 解决方案:
- 标记: 使用模板缓冲(Stencil Buffer)的一个比特位来标记这些仅存在于光栅化阶段的实例。
- 动态调整: 当屏幕空间光线追踪到一个被标记的像素背后时,系统会动态地增加预估的表面厚度。
- 目的: 通过“加厚”这些物体在屏幕空间中的表示,使得光线更容易与它们发生“相交”,从而有效地为这些没有HWRT数据的物体生成接触阴影(contact shadows) 。
Alpha Masking for Ray-Traced Shadows
The Challenge: Precision in Shadows
在处理光线追踪中的透明表面(例如树叶、栅栏等)时,直接阴影的计算比全局光照(GI)或粗糙反射要求更高的精度。
-
核心观点: 用于GI或反射的近似技巧(如在构建BVH时剔除或缩小带Alpha贴图的三角形)对于生成清晰、准确的直接阴影是不可行的。阴影的边缘必须精确,任何近似都会导致明显的视觉瑕疵。
-
关键挑战: 现代游戏引擎使用复杂的材质图(Material Graphs) 来定义物体的Alpha值,这意味着透明度不再是简单的贴图采样。它可以是程序化生成的,或是多种计算的结果。这种复杂性使得在光线追踪硬件中实现一种简单的“固定功能(fixed function)”Alpha测试变得不切实际。因此,我们需要依赖更灵活但开销也更大的着色器逻辑。
Solution 1: Full Any-Hit Shader (AHS) Tracing
这是最直接、最精确的方法,但性能开销也最大。
- 核心观点: 为每一条阴影光线都启用Any-hit Shader (AHS)。当光线与一个三角形相交时,会触发AHS。AHS会执行完整的材质评估,检查交点处的Alpha值:
- 如果该点是透明的,AHS会指示硬件忽略这次命中,让光线继续前进。
- 如果该点是不透明的,则光线被遮挡,搜索结束。
- 优点:
- 结果精确:能够完美处理任何复杂的材质逻辑。
- 缺点:
- 性能开销高:无法利用内联光线追踪(Inline Ray Tracing) 带来的性能优势,因为每次潜在的命中都需要调用一个完整的着色器。这在主机等性能受限的平台上尤其是一个问题。
Solution 2: Hybrid - Inline Trace + Conditional Retrace
这是一种混合方法,旨在平衡性能与精度,也是讲座中推荐的方法。
-
核心观点: 该方法将光线追踪分为两步,结合了内联光线追踪的速度和AHS的精确性。
-
工作流程:
- 初次追踪 (Inline Trace): 首先,发射一条轻量级的内联光线。这种光线追踪非常快,它只会报告最近的命中点,而不会执行任何材质评估。
- 条件性重追踪 (Conditional Retrace): 检查初次追踪命中的物体实例。
- 如果该物体是完全不透明的,那么我们就确认光线被遮挡,流程结束。这是绝大多数情况,性能很高。
- 如果该物体需要Alpha Mask评估,我们就从光线的原始起点,以相同的方向,发射一条新的 “延续光线” (Continuation Ray)。但这一次,我们会为这条光线启用Any-Hit Shader,以执行精确的材质评估。
-
优点:
- 两全其美: 对于绝大多数击中不透明物体的情况,我们享受了内联光追的极高速度。
- 按需付费: 仅在必要时(即击中需要Alpha测试的物体时)才承担AHS的性能开销,从而在保证精度的前提下最大化了整体性能。
两种追踪方式对比
Inline Trace (内联追踪)
- 特点: 轻量、快速,在当前着色器内直接执行。
- 流程: 光线 → 寻找最近的命中点 → 返回结果。
- 适用场景: 简单的遮挡查询,如AO或初步的阴影测试。
AHS Trace (Any-Hit追踪)
- 特点: 灵活、精确,但开销大。
- 流程: 光线 → 每次潜在命中都执行AHS → AHS决定是否忽略命中 → 直到找到最终遮挡物或光线逸出。
- 适用场景: 需要逐像素透明度测试的精确阴影。
阴影图采样 (Shadow Map Sampling)
本页探讨了在硬件光线追踪(HWRT)不适用时,如何使用虚拟阴影图(Virtual Shadow Maps - VSM)作为一种备选(Fallback)方案来生成阴影,并分析了这种方法的优缺点。
为何需要备选方案?HWRT的局限性
核心观点: 硬件光线追踪 (HWRT) 在处理某些特定类型的游戏内容时,性能开销会变得非常巨大,以至于在当前硬件上不切实际。
- 高密度Alpha蒙版植被 (Animated / Alpha Masked Foliage):
- 对于树叶、草地这类由大量微小、重叠的三角形构成的物体,并且使用了Alpha Masking,光线追踪需要频繁调用 Any-Hit Shader (AHS) 来处理透明部分。这个过程会带来极高的计算开销。
- 大量实例化的动画网格 (Heavily Instanced Animated Meshes):
- 如果场景中有大量重复且带有动画的角色或物体,为它们每一帧都重新构建或更新 包围盒层次结构 (BVH) 会消耗大量的内存和计算时间。
解决方案:虚拟阴影图 (Virtual Shadow Maps - VSM)
核心观点: 为了解决HWRT的性能瓶颈,系统支持将特定光源的阴影计算回退到使用 虚拟阴影图 (Virtual Shadow Maps - VSM) 技术。
- 这并非一个全局开关,而是提供了一种灵活的选择。美术师或开发者可以手动标记 (Manually Tag) 哪些光源应该使用VSM,以及哪些网格需要被渲染进VSM中。
- 这种方式允许 HWRT 和 VSM 在同一场景中混合使用,甚至可以做到同一个光源下,部分物体使用HWRT阴影,另一部分使用VSM阴影。
VSM作为备选方案的优势
核心观点: VSM不仅是一种备选,其自身的技术特性使其能够生成高质量的阴影,并且与光追阴影无缝融合。
- 高质量的柔和阴影:
- VSM能够产生可信的柔和阴影 (Plausible soft shadows) 和 接触硬化 (Contact Hardening) 效果(即阴影在靠近遮挡物的地方更锐利,远离时更模糊)。这使得VSM产生的阴影在视觉上与光追阴影非常接近,混合使用时不会有违和感。
- 高效的渲染管线:
- GPU驱动的页面标记 (GPU driven page marking): 在采样着色阶段(Lighting Pass),GPU可以标记出视野中实际需要被采样的VSM页面(Pages)。这样,在后续的阴影图生成阶段,引擎就只需要渲染几何体到这些被标记的页面中,避免了对不可见区域的无效渲染。
- 静态页面缓存 (Static page caching): 对于静态物体的阴影,可以将其缓存起来,进一步提升性能。
核心限制:可扩展性问题 (Scaling Issues)
核心观点: VSM作为备选方案的最大缺点是它没有解决传统阴影图的扩展性问题。其开销会随着光源数量的增加而线性增长。
-
成本模型对比:
- 硬件光追 (HWRT): 主要成本在于为整个场景构建一次BVH。这个成本虽然高昂,但属于一次性投入。之后,每个光源利用这个BVH进行追踪的逐光源开销 (per-light overhead) 非常低。
- 虚拟阴影图 (VSM): 每个使用VSM的光源都需要自己的一套阴影图。这意味着每增加一个光源,就需要付出一次准备和渲染阴影图的开销。即使有各种缓存和优化,当光源数量增多时,这个成本会迅速累积,对性能(如60Hz的渲染预算)造成巨大压力。
-
实践中的应用:
- 正是因为这种扩展性限制,VSM回退方案在实践中主要用于方向光 (Directional Light)。
- 原因:
- 对于方向光,整个场景的阴影范围非常大,如果完全依赖HWRT,就需要一个覆盖全场景的巨大BVH,成本极高。
- 对于植被等HWRT不擅长处理的物体,其在方向光下的阴影瑕疵(比如低面数模型代理产生的错误阴影)会特别明显。使用VSM可以更好地解决这些特定物体的阴影质量问题。
混合光线追踪管线总览 (Hybrid Tracing Pipeline Overview)
本页介绍了一种现代渲染引擎中常见的高性能光线追踪管线设计。其核心思想是采用分阶段(Staged) 和混合(Hybrid) 的策略,将不同特性和成本的光线追踪技术组合起来,以最高效的方式处理光线。
核心思想:瀑布式(Waterfall)光线处理
整个追踪管线并非一次性将所有光线投射到完整的场景中,而是像一个瀑布一样,分层、分阶段地处理。每一阶段都使用特定的技术尝试解决一部分光线。只有在前一阶段“失败”(即光线未命中)的光线,才会被传递到下一个、通常计算成本更高的阶段。
- 优先使用廉价技术:管线从计算成本最低的追踪技术(如屏幕空间追踪)开始。
- 逐级增强精度与范围:后续阶段逐步引入更精确、范围更广但更昂贵的追踪技术(如近场/远场几何追踪)。
- 针对性处理特殊情况:为特定材质(如Alpha Mask)或光源类型(如VSM)设计了专门的处理路径。
- 关键优化:在每个阶段之间都执行光线压缩(Ray Compaction) ,以维持GPU计算的高效性。
管线追踪阶段详解 (Tracing Stages in Detail)
管线按照以下顺序依次执行,每个阶段处理上一阶段遗留下来的“未命中”光线:
1. 屏幕空间追踪 (Screen Traces)
- 核心观点:这是管线的第一步,也是最快速的追踪方式。它利用已经渲染好的深度缓冲区(Depth Buffer)或G-Buffer信息在屏幕空间进行追踪。
- 关键目的:
- 快速找到与屏幕上可见物体的交点。
- 有效避免错误的自阴影(Self-Shadowing) ,因为屏幕空间信息能最准确地反映最终像素的表面位置。
2. 近场追踪 (Near Field Traces)
- 核心观点:这是整个管线的主力阶段,负责处理绝大多数在屏幕空间无法解决的光线。
- 实现方式:在相机周围一个预定义的 “近场”半径内,对高精度的场景几何(通常是BVH加速结构)进行硬件光线追踪。这是最消耗性能但也是最通用的追踪方式。
3. 带材质评估的近场重追踪 (Near Field Traces w/ Material Eval - 可选)
- 核心观点:这是对近场追踪的增强处理,专门用于解决半透明或镂空材质的正确求交问题。
- 触发条件:当一条近场光线首次命中了一个带有 Alpha Masked 属性的材质时(例如铁丝网、树叶)。
- 操作流程:由于标准的硬件光追只会返回最近的几何交点,而不管该点在材质上是否透明,因此需要重新发起一次追踪。在这次重追踪中,光线求交测试会与材质评估(Material Evaluation) 相结合,当光线与三角形相交时,会采样其纹理并执行Alpha Test,只有在命中不透明部分时才算作有效命中。
4. 远场追踪 (Far Field Traces - 可选)
- 核心观点:这是一种针对长距离光线的LOD(Level of Detail)追踪策略,用于处理超出近场范围的遮挡。
- 触发条件:当光线走完了整个近场半径后,仍然没有命中任何物体。
- 实现方式:将光线投射到一个简化的远景场景表示中进行追踪。这个远景表示可以是SDF(有向距离场)、Mesh SDF、Nanite的代理几何体或其他低成本的结构。
5. 虚拟阴影贴图追踪 (VSM Traces - 可选)
- 核心观点:这是混合渲染的典型体现,它将光线追踪与传统的光栅化阴影技术(Virtual Shadow Maps)相结合。
- 适用场景:当处理来自使用VSM的光源的阴影光线时,系统不会进行几何追踪,而是直接采样对应的VSM来判断光线是否被遮挡。这对于处理大规模场景和海量光源的阴影非常高效。
关键技术:光线压缩 (Ray Compaction)
- 核心观点:光线压缩是连接上述各个追踪阶段的关键优化步骤,是维持整个管线高性能的基石。
- 工作原理:
- 在每个追踪阶段结束后,光线被分为两组:已命中(Hit) 和未命中(Miss) 。
- Compaction步骤会丢弃所有已命中的光线(因为它们已经完成了任务)。
- 然后,它将所有未命中的光线紧凑地打包到一个新的缓冲区中。
- 这个新的、更小的光线包将被传递给下一个追踪阶段。
- 主要优势:
- 提升GPU线程连贯性 (Coherency):GPU以线程组(Warps/Wavefronts)的形式执行指令。如果一个线程组中部分线程处理已命中的光线(空闲),部分处理未命中的光线(活跃),会导致效率下降。Compaction确保了进入下一阶段的线程组中几乎所有线程都在执行有效工作,最大化了SIMD/SIMT单元的利用率。
- 减少计算负载:避免了在后续更昂贵的追踪阶段中,为那些已经找到交点的光线执行不必要的计算。
- 实现细节:讲稿中提到,此步骤以 16x16 的追踪瓦片(Trace Tiles) 为单位进行处理,以最大化局部数据和执行的连贯性。
无约束的光照设置 (Unconstrained Lighting Setups)
本页内容旨在阐述现代游戏渲染面临的新挑战:艺术家们期望在场景中放置海量且类型复杂的光源,而传统的渲染管线和引擎架构并未为此做好充分准备。
核心趋势:迈向海量动态光源
- 核心观点:现代渲染的目标之一是实现 无约束的光照设置(Unconstrained Lighting) ,即允许美术在单个视锥体或关卡中放置成千上万(1000s) 的光源,而无需担心严格的性能预算。
- 这一趋势对渲染管线的各个环节(如剔除、数据管理、着色)都带来了巨大的压力,迫使引擎架构进行革新。
引擎的挑战:历史架构与性能瓶颈
- 核心观点:尽管支持海量光源是未来的方向,但大多数现有游戏和成熟引擎(如Unreal Engine)的底层架构,在设计之初并未针对如此庞大的光源数量进行优化,因此存在显著的性能提升空间。
- 关键佐证:以UE的 灯光数量热力图(Light Count Heatmap) 为例,其默认的显示阈值上限仅为8个光源。这清晰地反映出,在实现该功能时,业界普遍认为单个区域的光源重叠数量非常有限。当光源数量远超这个量级时,原有的系统就会成为性能瓶颈。
复杂度的提升:从光源数量到光源类型
- 核心观点:挑战不仅在于光源的 数量,还在于其 复杂度。艺术家越来越多地使用比传统点光源更复杂、计算成本更高的光源类型。
- 关键术语:
- 矩形光(Rect Lights) :即面光源,能产生更柔和、更真实的阴影和高光。
- 纹理光(Textured Lights) :也称为投射光(Projector Lights)或"Gobos",可以将一张纹理投射到场景中,常用于模拟窗户、灯罩图案等效果。
- 这要求引擎必须具备能够高效、统一处理各类复杂光源的解决方案,而不是将它们作为少数特殊情况进行特殊处理。
Light Grid
核心思想:一种优化的Froxel光照剔除结构
本页介绍了一种为支持海量光源(数千个)而优化的光照网格(Light Grid)构建方案。该方案基于 Froxel(Frustum Voxel,视锥体素) 结构,并通过多项优化技术,在性能和内存使用上都做了提升,旨在解决大规模光照场景下的性能瓶颈。
核心优化点包括:两阶段剔除、紧凑化光照列表 和 HZB遮挡剔除。
两阶段剔除 (Two-Pass Culling)
为了高效处理数以千计的光源,传统的单次剔除方法压力巨大。该方案采用了一种“分而治之”的两阶段策略,将光源注入过程分解,大幅降低了计算复杂度。
- 核心观点: 通过先粗后精的两步筛选,避免在精细网格的每个单元上都遍历全部光源,从而实现数量级的性能提升。
- 第一阶段: 粗粒度网格剔除 (Coarse Grid Culling)
- 目标: 初步筛选,为每个较大的空间区域(粗粒度单元)生成一个可能相关的光源列表。
- 实现: 由于需要遍历场景中的所有光源,这个阶段的计算量很大。因此,为每个粗粒度单元分配一个完整的 线程组 (Thread Group) 来并行处理,以保证效率。
- 第二阶段: 主网格注入 (Main Grid Injection)
- 目标: 利用粗粒度阶段的结果,为最终用于渲染的精细网格(主网格)生成精确的光源列表。
- 实现: 在这个阶段,每个精细单元格只需要检查其对应的粗粒度单元格筛选出来的、数量已大大减少的光源子集。因此,每个单元格通常只需要 一个线程 (a single thread) 即可完成工作。
- 动态工作负载: 系统可以根据粗粒度阶段统计出的光源数量,动态地决定为每个单元格分配一个线程、一个 Wave(例如32个线程,在支持的硬件上)还是一个完整的线程组,以达到最佳的硬件利用率。
- 性能成果: 在 MegaLights 演示中,此优化将光照网格的构建时间从超过 0.6ms 降低到了 0.2ms 以下。
紧凑化光照列表 (Packed Light Lists)
在光照网格中,为每个单元格预分配最坏情况下的内存(例如,能容纳所有光源)会造成巨大的内存浪费。解决方案是为所有单元格的光源列表创建一个全局的、紧凑的缓冲区。
- 核心观点: 避免内存浪费和双重遍历开销,通过结合使用LDS和全局内存链表作为临时存储,实现一次遍历就完成光源索引的计数和写入。
- 挑战: 传统实现紧凑列表的方法需要两次遍历:第一次遍历计数,第二次遍历写入。这会带来额外的性能开销。
- 高效的单次遍历实现:
- 写入LDS: 线程组首先将当前单元格相关的光源索引写入高速的 局部数据共享内存 (LDS, Local Data Share)。
- 溢出处理: 如果LDS空间不足,多余的索引会被写入一个位于全局内存的共享缓冲区,形成一个 链表 (Linked List) 结构进行暂存。
- 原子分配: 当一个单元格的所有相关光源都找到后,根据LDS中的数量和溢出链表的长度,计算出总共需要的空间,然后在最终的全局光照列表缓冲区中 原子地分配 出一块连续的内存。
- 最终拷贝: 将LDS和溢出链表中的所有光源索引拷贝到上一步分配好的连续内存中。
HZB 遮挡剔除 (Hierarchical Z-Buffer Culling)
场景中大量的网格单元格可能被前景物体完全遮挡,对它们进行光源剔除是无效计算。HZB剔除可以快速跳过这些被遮挡的单元格。
- 核心观点: 利用HZB(层级深度图)快速进行遮挡判断,跳过对被完全遮挡的网格单元的处理,尤其能高效剔除计算成本最高的远处单元格。
- 实现: 在处理每个Froxel单元格之前,先将其包围盒与HZB进行遮挡测试。如果该单元格被完全遮挡,则直接跳过该单元格的所有光源剔除和写入操作。
- 对Froxel结构的特殊优势:
- Froxel结构的一个特点是,单元格的体积会随着深度 非线性地增大。
- 这意味着远处的单元格覆盖了巨大的空间范围,它们更有可能与大量光源相交,导致处理这些单元格的开销非常大(需要检查和写入大量光源索引,容易成为 带宽瓶颈)。
- HZB剔除对于剪裁掉这些昂贵但又不可见的远处单元格尤其有效,从而带来显著的性能提升。
利用挡光板(Barn Doors)优化矩形光剔除
矩形光剔除的性能挑战
-
核心观点:光源剔除(Light Culling)的效率直接影响渲染性能。 一个高效的剔除算法能够确保GPU只在真正被光源影响的像素或区域上进行光照计算。
-
关键问题:传统的矩形光剔除包围体(Bounding Volume)通常过于宽松。 对于矩形光(Rect Light),如果不加以特殊处理,其影响范围在剔除阶段通常会被估算为一个非常大的区域(例如,一个覆盖整个半球的锥体),远超其真实的光照范围。
-
性能影响: 不精确的剔除会导致GPU在大量实际上不受该光源影响的单元格(Cells/Tiles)上浪费宝贵的计算资源,执行不必要的光照计算。
-
业界趋势: 随着实时渲染(尤其是在游戏引擎中)越来越多地使用矩形光(Rect Lights) 来模拟真实世界的面光源(如窗户、天花板灯),优化其剔除算法变得愈发重要。
解决方案:引入挡光板(Barn Doors)概念
-
核心术语:挡光板(Barn Doors)
- 这个概念源自影视和舞台灯光,指的是安装在灯具前的可调节叶片,用来塑造光束的形状和范围。
- 在计算机图形学中,它被用作一个虚拟的参数,用于限制矩形光向外发光的角度范围,从而将原本宽泛的光照区域收紧为一个更精确的锥形或棱锥形区域。
-
核心思想:通过考虑挡光板来收紧光源的剔除边界(Culling Bounds)。 与其假设矩形光向整个前方半球发光,不如利用挡光板定义的精确角度来构建一个更紧凑、更贴合实际光照范围的剔除体积(通常是一个视锥体 Frustum)。
-
效果对比:
- 无挡光板的情况 (Without Barn Doors): 剔除体积非常庞大,导致矩形光被分配到很多它根本照不到的屏幕空间单元格中,造成性能浪费。
- 使用挡光板的情况 (With Barn Doors): 剔除体积被精确地收紧,仅覆盖光源实际照亮的区域。这使得受该矩形光影响的单元格(Cells)数量显著减少。
-
最终收益: 通过实现更紧凑的剔除边界(tight culling bounds) ,可以最大化剔除效率,大幅提升渲染性能,尤其是在场景中存在大量矩形光的应用场景下。
Tile Classification (着色器优化)
本页内容承接前序的Tiled Lighting/Deferred Rendering管线,介绍了一种关键的性能优化技巧:分块分类(Tile Classification) 。其核心目标是在像素着色阶段,通过智能调度来降低GPU的寄存器压力,从而提升渲染性能。
问题背景:寄存器压力与GPU占用率
在现代渲染管线中,为了处理各种复杂的材质和光源,通常会编写一个功能全面的“超级着色器”(Uber-shader)。
-
挑战: 这种单一的、庞大的着色器需要处理场景中可能出现的所有情况(例如,标准PBR材质、皮肤材质、清漆材质,以及点光源、聚光灯、矩形光、带纹理的光源等)。这导致着色器逻辑分支复杂,需要占用大量的向量通用寄存器(VGPRs) 。
-
核心观点: 过高的寄存器压力(Register Pressure) 会直接影响GPU的性能。GPU的计算单元(Compute Unit)上的寄存器总量是固定的。如果单个着色器线程(Wavefront/Warp)占用的寄存器过多,那么能够同时在该计算单元上并发执行的线程数量就会减少。
-
关键术语:
- 寄存器压力 (Register Pressure): 指单个着色器线程为了执行所需使用的寄存器数量。压力越高,并发能力越差。
- 占用率 (Occupancy): 指一个计算单元(CU)或流式多处理器(SM)上,实际并发运行的线程数与硬件理论上能支持的最大线程数的比率。高占用率是隐藏内存访问延迟、提升GPU利用率的关键。我们的目标就是通过降低寄存器压力来提高占用率。
简单来说,我们不希望屏幕上一个只受简单点光源影响的普通材质像素,也为其根本用不到的、处理复杂纹理光源的着色器代码付出性能代价。
解决方案:基于材质与光源类型的分块分类
为了解决上述问题,讲座提出了一种更精细的分类策略,在对每个Tile进行光照计算前,先对其内容进行分析和分类。
-
核心观点: 分类的依据不仅包括Tile内的材质类型(material type) ,还创新性地加入了光源类型(light types) 。
-
实现流程:
- 在正式执行光照计算的Pass之前,插入一个简短的分类(Classification)Pass。
- 这个Pass会检查每个Tile覆盖了哪些G-Buffer中的材质ID,以及影响该Tile的光源网格(Light Grid)中包含了哪些类型的光源。
- 根据分析结果,为每个Tile打上一个或多个标签(例如,“仅含标准材质”、“包含皮肤材质”、“仅受点光源影响”、“受矩形光影响”等)。
- 在后续的光照计算Pass中,根据Tile的标签,调度(Dispatch)一个与之对应的、高度优化的着色器变体(Shader Permutation) 。
实现细节与收益
这种方法的关键在于为不同的组合预编译不同的、轻量化的着色器版本。
-
具体案例: 讲座中特别提到了矩形光(rect lights) 和纹理光源(textured lights) 。处理这两种光源的着色器代码通常比处理简单的点光源和聚光灯要复杂得多,因此会带来显著的寄存器压力。
-
优化实践:
- 我们可以为“仅受点/聚光灯影响的Tiles”准备一个不包含矩形光/纹理光逻辑的、非常轻量化的着色器变体。
- 只有当一个Tile被分类为确实受到矩形光或纹理光影响时,才为其分派包含了复杂计算逻辑的重量级着色器变体。
- 这种“按需付费”的策略,确保了性能开销只花在刀刃上。
-
性能收益:
- 在MegaLights演示中,通过增加基于光源类型的分类,占用率(Occupancy)平均提升了约20%。这是一个非常可观的性能增益。
-
开销分析:
- 这种分类步骤的额外开销很小。因为在构建光源网格(Light Grid)的阶段,我们已经知道了每个网格单元(cell)受到了哪些类型光源的影响,这些信息可以被直接复用于分块分类阶段。
总结: 通过在Tiled Rendering管线中引入基于材质和光源类型的双重分类机制,并结合使用着色器变体(Shader Permutations) ,可以极大地降低平均寄存器压力,显著提升GPU占用率和整体渲染性能。这是现代渲染引擎中一种非常实用且高效的优化手段。
体积雾与半透明材质的光照
核心问题:如何为体积效果(Volumetric Effects)提供高效的光照和阴影
在现代渲染引擎中,为体积雾、粒子等非实体效果提供真实的光照是一个重要的课题。虚幻引擎(UE)采用两种核心数据结构来计算和存储这些效果所需的光照信息。
UE中的两种体积光照数据结构
1. 体积雾 (Volumetric Fog): 视锥体素网格 (Froxel Grid)
- 核心观点: 为了高效地渲染覆盖整个屏幕的体积雾,UE使用了一种与摄像机紧密相关的数据结构。
- 关键术语: Froxel Grid (视锥体素网格),是 Frustum (视锥体) 和 Voxel (体素) 的组合词。
- 工作原理:
- 它将摄像机的视锥体沿深度方向切分成许多片(Slices),再将每个切片划分成二维网格(Tiles),从而形成一个三维的体素网格。
- 这个网格是与摄像机对齐的(camera aligned),意味着它会随着摄像机的移动和旋转而变化。
- 这样做的好处是,越靠近摄像机的区域,体素精度越高,细节更丰富;越远的区域,体素越大,节省了计算和存储资源,与人眼的视觉感知相匹配。
2. 半透明材质 (Translucency): 世界空间体素网格 (World Space Voxel Grid)
- 核心观点: 对于粒子效果等局部、独立的半透明物体,UE采用了一个固定在世界空间中的网格来存储光照。
- 关键术语: World Space Voxel Grid (世界空间体素网格),Spherical Harmonics (球谐光照)。
- 工作原理:
- 这个数据结构是一个围绕摄像机的、在世界空间中固定的三维网格。
- 它不像Froxel Grid那样随视锥体变形,因此更适合计算和缓存那些位置相对固定的粒子或半透明效果的光照。
- 每个体素(Voxel)中存储的是2阶球谐函数 (2-band Spherical Harmonics)。这是一种高效的数据压缩技术,可以用很少的系数(2阶SH只需要9个浮点数)来近似表示一个体素接收到的来自四面八方的低频环境光照。
传统方法及其在新系统中的挑战
传统光栅化管线 (The Traditional Approach)
- 更新方式: 这两种体积数据结构通常是逐帧更新的。
- 核心算法:
- 光照注入 (Light Injection): 遍历场景中的光源,将它们的光照贡献注入到其影响范围内的体素中。
- 阴影计算: 通常依赖于传统的光栅化技术生成的 阴影图 (Shadow Maps) 来判断某个体素是否处于阴影中。
转向光线追踪带来的挑战 (The Ray Tracing Challenge)
- 核心观点: 当渲染管线主要依赖光线追踪时,传统的体积光照更新方式会遇到两大瓶颈。
- 挑战 1: 阴影图的缺失
- 在以光线追踪阴影 (Ray Traced Shadows)为主的渲染流程中,可能根本不会生成传统的阴影图。这使得体积结构无法获取阴影信息。
- 挑战 2: 性能开销巨大
- 现代场景的光源数量可能非常庞大。对每一个光源都执行一次光照注入操作,将其贡献累加到巨大的三维体素网格中,这个过程的计算开销非常昂贵。
结论:系统升级的必要性
为了适应以光线追踪为核心的现代渲染管线,UE原有的这套体积光照系统必须进行升级。其目标是找到一种新的方法,使其能够高效地与光线追踪系统集成,解决阴影信息获取和海量光源注入的性能问题。
Volumetric Grid Pipeline
核心思想:将渲染不透明物体的管线思路拓展至体积渲染
本页的核心观点在于,我们可以将为不透明物体(Opaque Objects)设计的、已经非常成熟的现代光照渲染管线(例如 Tiled/Clustered Lighting)进行改造和复用,以高效地处理体积效果(如体积雾)的渲染,而无需为其设计一套完全独立的系统。
这种方法的本质是将屏幕空间的像素(Pixel)概念,延伸到三维空间的体素(Voxel)。
适用于体积光照的渲染管线步骤
整个管线围绕一个核心循环展开,并且利用了时间连续性(Temporal Coherence)来优化下一帧的计算。
1. 光源采样 (Sampling)
- 核心任务:为每个体素(Voxel) 挑选出最重要、最可能对其产生光照贡献的 N 个光源样本。
- 优化策略:
- 降分辨率处理:此阶段可以在较低的分辨率(例如半分辨率)下运行,以显著降低计算开销。
- 利用历史信息 (History):这一步并非从零开始,而是会利用上一帧生成的可见光源列表(Visible Light Lists) 作为输入,从而更智能、更高效地选择本帧的光源样本。
2. 光线追踪 (Tracing)
- 核心任务:对每个体素选出的 N 个光源样本,进行可见性测试。
- 具体实现:从体素的位置向每个光源样本追踪阴影光线(Shadow Rays) ,以判断该光源是否被场景中的不透明物体遮挡。
3. 着色 (Shading)
- 核心任务:根据上一步的可见性测试结果,计算可见光源对体素的光照贡献。
- 关键区别:针对不同类型的体积,需要使用不同的光照模型。
- 标准体积雾 (Volumetric Fog):使用相函数 (Phase Function) 来模拟光线在参与介质(如雾气、尘埃)中的散射行为。这是物理上更精确的模型。
- 半透明体积 (Translucency Volume):使用漫反射BRDF (Diffuse BRDF) 进行着色。这表明该体积被当作由大量微小漫反射表面组成的集合来处理,可能用于实现风格化的次表面散射(Subsurface Scattering)或浓厚的粒子效果。
4. 可见性信息生成 (Visibility)
- 核心任务:为下一帧的计算做准备。
- 具体实现:基于本帧的着色结果,为每个体素构建或更新一个可见光源列表。这个列表包含了所有对该体素有实际光照贡献的光源。
- 作用:该列表将作为下一帧光源采样 (Sampling) 阶段的输入,形成一个高效的时域反馈循环(Temporal Feedback Loop) 。
针对多体积效果的执行流程
- 讲座中提到的 “x 2” 标记指出,上述完整的渲染管线需要独立执行两次。
- 第一次执行:处理标准体积雾。
- 第二次执行:处理一种特殊的半透明体积。
这表明该渲染管线是一个通用模块,可以灵活地应用于场景中不同性质的体积效果,只需在着色(Shading) 阶段切换到对应的光照模型即可。
体积光照网格:现有方案的问题
本页讨论了在体积光照中直接使用两种独立的网格(世界空间网格和视锥体素网格)所带来的核心问题。这两种网格虽然目的不同,但在实践中会引发效率和精度上的挑战。
核心问题一:稀疏的探针覆盖 (Sparse Probe Coverage)
这种方法的主要缺陷在于探针的分布过于稀疏,尤其是在世界空间网格中。这导致了两个关键的负面影响:
-
邻近探针的可见性关联性差 (Poorly Correlated Neighbor Visibility)
- 核心观点: 由于探针之间距离较远,一个探针的可见性信息(例如,是否被阴影遮挡)对其邻居的参考价值很低。场景中的一个微小遮挡物就可能完全改变某个探针的受光情况,但这个变化无法被其远处的邻居探针所感知。
-
在高频区域引导效果不佳 (Ineffective Guiding in High-Frequency Regions)
- 核心观点: 在包含复杂几何或精细阴影的区域(即高频区域),稀疏的探针无法捕捉到光照的快速变化。因此,如果依赖这些探针的稀疏数据来进行更精细的计算(如重要性采样),其“引导”作用会非常有限,甚至产生错误的结果,导致渲染细节丢失或出现瑕疵。
核心问题二:大量的重复工作 (Duplicate Work)
系统同时维护和计算两个独立的体积网格,导致了严重的性能浪费。
-
探针覆盖区域重叠 (Overlapping Probe Coverage)
- 核心观点: 如下图所示,世界空间网格 (World Grid) 和 视锥体素网格 (Froxel Grid) 中的探针在空间上存在显著的重叠。这意味着,对于场景中的同一个区域,我们可能在两个网格中都放置了探针,并为它们分别执行了类似的昂贵计算。
-
计算资源的浪费
- 核心观点: 两种网格中的探针都需要执行类似的操作,例如:重要光源选择 (Picking important lights) 和 阴影光线追踪 (Tracing shadow rays)。由于覆盖区域的重叠,这些计算在很大程度上是重复的,造成了不必要的性能开销,违背了优化的初衷。
使用Froxel Grid处理半透明效果
本页探讨了一个看似高效但实践中存在诸多问题的想法:复用为不透明物体光照剔除而构建的 Froxel Grid 来为粒子和半透明效果提供光照。
核心思路:复用Froxel Grid进行光照计算
这个方案的基本想法是,既然已经有了一个按视锥体划分的 Froxel Grid 数据结构,我们能否将其扩展,不仅用于光源剔除,还用来存储体积光照信息(例如 球谐光照 Spherical Harmonics, SH),并直接应用于半透明物体和粒子效果的着色。
这个思路的潜在优势在于:
- 效率提升: 避免为半透明物体和粒子维护一套独立的世界空间光照体积(如 Light Probe Grid),从而减少重复的计算和内存开销。
- 精度更高: Froxel Grid 具有近处密集、远处稀疏的特性。这意味着靠近摄像机的粒子和半透明物体可以获得分辨率更高的光照信息,理论上能提升光照引导的质量。
实践中的问题与挑战
尽管这个想法在理论上很有吸引力,但在实际应用中会引入一系列难以解决的视觉瑕疵(Artifacts),最终导致该方案通常是不可行的。
-
1. 网格结构暴露 (Underlying Structure is Noticeable)
- 核心观点: 当使用 Froxel Grid 存储的光照信息来渲染半透明或体积效果时,其底层的体素(Froxel)结构会变得肉眼可见,产生明显的块状感或光照不连续的现象。
-
2. 摄像机移动时的不稳定性 (Instability when Camera Moves)
- 核心观点: 这是该方案最致命的缺陷。Froxel Grid 是一个视图空间(View-Space)的数据结构,它会随着摄像机一起移动。当摄像机平移或旋转时,对于世界中静止的半透明物体来说,它在每一帧都会被不同的 Froxel 单元覆盖。这导致其采样到的光照信息会发生跳变,产生非常干扰视觉的闪烁和滑动效果。
- 关键对比: 传统的世界空间网格(World-Space Grid) 虽然也可能存在块状瑕疵,但由于其位置在世界中是固定的,因此光照信息是稳定的。物体在网格中移动产生的光照变化是自然的,而摄像机移动导致的光照在物体表面“滑动”则非常不自然。
-
3. 时间性滤波引入的重投影误差 (Reprojection Errors)
- 核心观点: 为了平滑光照结果并降低渲染成本,时间性滤波(Temporal Filtering)是必不可少的。然而,在视图空间的 Froxel Grid 上进行时间性滤波,重投影(Reprojection)会引入严重的误差。
- 原因: 由于网格随摄像机移动,上一帧的 Froxel 数据和当前帧的 Froxel 结构无法完美对齐。将上一帧的数据重投影到当前帧时,会产生模糊、拖影等难以消除的扩散性误差(Diffusion Errors) 。
- 重要提示: 讲座中特别指出,即使尝试使用更高级的插值算法(如 Bicubic Filter)和边缘处理技巧(如 Neighbor Clamp),也无法彻底解决这些由重投影引起的问题。
混合方法 - 共享采样与追踪
本页介绍了一种优化体积渲染的混合方法,旨在通过共享计算密集型阶段来提高效率,同时服务于两种不同的体积效果:光照透射(Lit Translucency)和体积雾(Volumetric Fog)。
核心思想:共享计算密集型阶段
该方法的核心在于,与其为两种不同的体积数据结构(世界空间网格和Froxel网格)分别执行完整的构建流程,不如将最耗时的采样(Sampling)和光线追踪(Tracing)阶段进行共享。
- 共享的计算: 采样 (Sampling) 和 光线追踪 (Tracing) 这两个步骤是构建体积数据时性能开销最大的部分。通过只执行一次,可以显著减少计算量。
- 分离的着色: 在共享阶段完成后,系统会运行两个独立的着色(Shading)通道,分别将共享的采样和追踪结果应用到各自的体积数据结构中。
- 性能收益: 这种方法避免了重复计算,根据讲稿,该优化可以节省大约 25% 的体积构建时间。
具体流程
整个流程可以分解为两个主要阶段:共享阶段和分离着色阶段。
-
共享采样与追踪 (Shared Sampling and Tracing)
- 采样基础: 该方法选择以 Froxel 网格的位置为基础进行采样。
- 选择原因: Froxel 网格(视锥体素网格)通常比世界空间网格更小、更密集。使用更密集的采样点作为基础,可以:
- 为光线追踪提供更有效的引导(guiding) 。
- 使得相邻的采样探针(sampling probes)可以有效地共享可见性数据,同时不牺牲引导的准确性。
- 执行追踪: 在确定了采样点后,为这些采样点统一执行光线追踪,计算出每个点的光照和可见性信息。
-
分离着色 (Separated Shading)
- 在获得共享的采样数据后,流程一分为二:
- 通道一:光照透射 (Lit Translucency)
- 将共享的采样结果着色(Shade)并累积到世界空间网格 (World Grid) 中。
- 这一步的输出用于渲染场景中的半透明材质的光照效果。
- 通道二:体积雾 (Volumetric Fog)
- 将同一份共享的采样结果着色(Shade)并累积到 Froxel 网格中。
- 这一步的输出用于渲染体积雾效果。
- 数据采集方式: 在这两个着色阶段,每个体积网格的单元(无论是World Grid还是Froxel Grid)都会从其最近的采样探针中随机采集 (stochastically gathers) 样本数据来计算最终的光照贡献。
方法优势与权衡
- 主要优势: 显著的性能提升。通过合并计算开销最大的采样和追踪步骤,避免了冗余工作,是针对多体积效果场景的有效优化手段。
- 关键设计决策: 选择基于更密集的 Froxel 进行采样是该混合方法的核心。这套密集的采样数据足以同时满足 Froxel 体积雾的精度需求和相对稀疏的世界空间网格的需求,从而实现数据共享,达到性能和质量的平衡。
半透明渲染需要更多采样 (Translucency Requires More Samples)
本页的核心观点是,用于不透明表面的诸多光照采样优化假设,在处理半透明材质时会失效。这导致为了达到高质量且稳定的渲染效果,我们必须为半透明光照计算存储和处理更多的样本。
主光源假设失效
在渲染不透明物体时,我们常常依赖一个关键优化假设:场景中某一点的绝大部分光照能量(例如 80%)来自于最主要的光源。这使得我们可以集中精力对这个主光源进行高质量采样,而忽略或简化其他次要光源,从而大幅提升性能。
- 核心观点: 对于半透明材质,“主光源贡献大部分能量”的假设不再成立。
- 原因: 光线会进入材质内部并发生散射(subsurface scattering)。这意味着来自多个不同方向、甚至是较弱的光源,其光线都可能在材质内部累积,共同对最终的着色效果产生显著影响。因此,仅仅采样一个主光源会丢失大量细节,导致渲染结果不真实。
采样时缺乏表面信息
在传统的不透明渲染管线(如延迟渲染)中,我们在进行光照计算时,可以从 G-Buffer 中获取到精确的表面信息,如法线、粗糙度、材质ID等。这让我们可以针对每一个像素的独有属性,进行高度优化的重要性采样,精确地挑选出对该像素贡献最大的光照样本。
- 核心观点: 在为半透明效果构建光照体积时,我们无法预知将要使用这些光照信息的具体表面属性。
- 实现方式: 半透明光照通常被预计算并注入到一个空间数据结构中,例如体素(Voxel)或视锥体素(Froxel),并用球谐光照(Spherical Harmonics, SH) 等方式来表示该区域内的平均光照环境。
- 挑战: 这个光照体积是通用的,它独立于任何特定的表面。在填充这个体积时,我们不知道之后会是哪个法线、哪种材质来查询它。因此,我们无法进行针对性的重要性采样,只能存储一个更普适、更全面的光照表示。
粗糙的体素化结构带来的挑战
用于存储半透明光照的体素(Voxel)或视锥体素(Froxel)在空间上通常比像素大得多。一个体素内的光照信息会被其覆盖范围内的多个像素共享。
- 核心观点: 粗糙的体素颗粒度会引入稳定性和质量问题,需要用更多的采样来弥补。
- 问题: 如果每个体素只存储少量随机选择的光照样本,相邻像素或在动态场景中同一像素在不同帧之间,可能会采样到不同的体素或邻近体素,导致光照信息发生跳变,产生闪烁或噪点,这被称为不稳定性(instability) 。
- 解决方案:
- 增加样本数量: 在每个体素中存储更多的光照样本,使其能更稳定、更准确地代表该区域的光照环境。
- 更宽的滤波(wider filtering) : 在采样时,对邻近的多个体素进行模糊/滤波处理,以平滑过渡。但这会以牺牲光照细节和可能引入漏光为代价。
更均匀的光照重要性权重
在决定采样哪些光源时,我们需要一个“重要性函数”来评估每个光源的潜在贡献。
- 对于不透明表面: 这个函数主要是BRDF(双向反射分布函数) ,尤其是高光部分,它具有很强的方向性,让我们可以集中采样少数几个方向。
- 对于半透明表面: 情况更为复杂。光照贡献不仅取决于光线如何进入表面(由半透明BRDF描述),还取决于它如何在介质内部散射(由相位函数 Phase Function 描述)。
- 核心观点: 为了通用性,采样时的重要性函数需要同时考虑 BRDF 和相位函数(例如取两者的最大值
max(Phase function, BRDF))。这个组合函数通常比单纯的 BRDF 在方向上的响应更均匀。 - 结果: 这导致光照权重分布更加扁平,来自很多方向的光源都显得同等重要。我们无法再像处理高光反射那样只关注少数几个方向,而必须从一个更广泛的方向分布中进行采样。
结论:为何必须增加采样
综合以上所有因素,我们得出结论:为了获得高质量、无明显瑕疵的半透明渲染效果,我们必须在每个体素中计算并存储更多的光照样本。这直接弥补了因主光源假设失效、采样时缺乏表面信息、体素化结构粗糙以及光照重要性权重更均匀所带来的挑战。虽然这会增加计算和存储开销,但对于实现逼真的次表面散射效果而言是必要的妥协。
体积光栅着色质量提升 (Volumetric Grid Shading Quality)
本页探讨了在进行体积光栅化渲染时,如何以高效的方式提升每个体素(Voxel)的光照着色质量。核心挑战在于,如何在计算成本和渲染细节之间取得平衡。
核心问题:体素内的光照信息不足
当我们使用一个3D网格(Volumetric Grid)来存储体积光照信息时,最简单的方法是为每个网格单元(体素)计算一次光照,但这通常会导致光照效果显得粗糙和块状。为了解决这个问题,我们需要更丰富的光照信息。
- 关键术语: 体积光栅着色 (Volumetric Grid Shading)
- 一种将体积光照效果(如雾、云)预计算或实时计算到一个三维网格(即体素集合)中的技术。渲染时,通过查询这个网格来获取对应空间点的光照信息。
- 关键术语: 采样/可见性探针 (Sampling / Visibility Probe)
- 在一个点(通常在体素内)向光源投射光线,以判断该点是否被遮挡的过程。这是计算阴影和光照的核心步骤。
- 关键术语: 着色探针 (Shading Probe)
- 存储在体素中的最终光照计算结果,它整合了可见性、光照模型等信息。
方案一:暴力增加采样数 (Brute-Force Sample Increase)
这是最直接、最符合物理直觉的质量提升方法。
- 核心观点: 在每个体素内部执行多次采样和光线追踪,然后将结果平均,以获得更精确、更平滑的光照结果。
- 优点:
- 高精度: 能够捕捉到更精细的光照和阴影变化,效果最接近“正确”结果。
- 缺点:
- 成本极高: 这种方法会显著增加整个渲染管线的开销。
- 采样成本 (Sampling Cost): 需要生成更多的采样点。
- 追踪成本 (Tracing Cost): 需要投射更多的光线来检测可见性。
- 着色成本 (Shading Cost): 需要对每个采样点执行完整的光照计算。
- 成本极高: 这种方法会显著增加整个渲染管线的开销。
方案二:邻域采样信息共享 (Sharing Information from Neighboring Samples)
这是一种更智能、性能更优的替代方案,它基于一个核心思想:与其在当前体素内做更多昂贵的工作,不如巧妙地利用已经为邻居体素计算好的信息。
- 核心观点: 将 随机上采样 (Stochastic Upsampling) 的思想进行扩展,不仅仅从单个邻居体素获取信息,而是从多个相邻体素收集并融合它们的采样/着色结果,从而提升当前体素的着色质量。
- 实现逻辑:
- 在对着色网格进行计算时,对于当前体素,查找其周围的一个或多个邻居体素。
- 获取这些邻居体素已经计算好的光照采样信息(即着色探针的结果)。
- 将这些信息进行某种形式的混合或平均,作为当前体素的最终着色结果。
- 优点:
- 高效: 极大地节约了成本,因为它避免了额外的采样和光线追踪开销。我们复用了已经完成的昂贵计算。
- 缺点:
- 细节损失: 这种方法本质上是一种模糊操作。通过平均邻居的信息,会平滑掉高频的光照细节,尤其是可见性项 (Visibility Term)会被模糊,导致光照和阴影的边缘变得更柔和、细节更少。
最终处理:时域与空域滤波 (Final Polish: Temporal and Spatial Filtering)
无论采用哪种方案,为了进一步提升最终效果的稳定性并抑制噪声,通常会引入滤波步骤。
- 核心观点: 对生成的光照网格数据进行后处理,平滑瑕疵,提升画面在时间和空间上的连续性。
- 关键术语:
- 空域滤波 (Spatial Filtering): 在单帧内部,对相邻体素的值进行模糊或加权平均,以减少空间上的噪声和块状感。这与方案二的思想类似,但通常作为独立的后处理步骤。
- 时域滤波 (Temporal Filtering): 结合前一帧的结果来平滑当前帧,极大地提升了画面的时间稳定性,能有效抑制由随机采样等技术引入的闪烁和噪点。
前向着色:处理高质量半透明材质
在渲染管线中,特别是延迟渲染(Deferred Shading)管线,处理需要高质量光照(如精确镜面反射)的半透明材质(例如玻璃、水晶)是一个经典难题。本页探讨了两种解决此问题的方案及其优缺点。
方案一:前层半透明GBuffer (Front Layer Translucency)
这是一种为了追求最高光照质量而设计的直接方法。
-
核心观点:通过为最前景的半透明层单独完整地执行一次光照计算,来获得最精确的光照结果,但这是一种以巨大性能开销为代价的方案,且扩展性极差。
-
实现流程:
- 渲染半透明GBuffer:首先,为场景中的半透明物体单独渲染一次 G-Buffer,存储其材质和几何信息。
- 重跑光照管线:接着,对这个半透明 G-Buffer 完整地重新运行一遍主光照管线(讲座中称为 MegaLights pipeline)。
-
优点:
- 高质量光照:可以获得与不透明物体完全一致的、包含所有细节的精确光照,尤其是复杂的镜面高光 (specular)。
-
缺点:
- 性能开销巨大:如果玩家靠近大面积的半透明表面,光照计算的总成本可能接近翻倍,成为严重的性能瓶颈。
- 仅支持单层:这种方法本质上只能处理最前方的一层半透明物体,无法解决多层半透明物体的堆叠与光照问题。
方案二:球谐光照近似 (SH Light Approximation)
这是一种更具扩展性、成本更低的妥协方案,也是目前项目中采用的方法。
-
核心观点:利用场景中已有的低频光照信息(球谐函数),提取一个近似的主光源方向来模拟镜面高光。这是一种性能友好且可扩展的方案,但光照质量有限且存在稳定性问题。
-
实现流程:
- 利用现有数据:直接使用为体积雾或全局半透明探针准备的半透明体积 (Translucency Volume) 中的光照数据。
- 提取主方向:这些光照数据通常以球谐函数 (Spherical Harmonics, SH) 的形式存储。为了模拟镜面高光,算法会从给定的SH系数中分析并提取出一个主光源方向 (dominant light direction)。
- 计算近似高光:使用这个单一的主方向来计算镜面反射,从而在半透明表面上形成一个近似的高光。
-
优点:
- 成本低廉:复用了已有数据,计算量小。
- 可扩展性好:可以应用于多层半透明材质,解决了方案一的局限性。
-
缺点:
- 单一高光限制:由于只能提取一个主光源方向,因此每个像素点最多只能表现一个镜面高光,无法还原复杂光照环境下的多个高光效果。
- 稳定性问题 (Jitter):SH本质上是低频信息。当光照分布发生细微变化时,提取出的主方向可能会发生突变或跳动。这会导致即使在静态光源下,镜面高光也可能出现不稳定的抖动 (jitter) 现象。
总结与未来方向
- 当前状态:项目目前采用的是 球谐光照近似 (SH Light Approximation) 方案,作为性能和效果之间的平衡。
- 持续研发 (Ongoing R&D):团队清楚地认识到当前方案的局限性,尤其是在光照质量和稳定性方面。因此,如何为这类半透明表面提供更高质量、更稳定的光照效果,是一个正在积极研究和探索的方向。
Ray Traced Transmission (Thin-Surface Model)
核心概念:薄表面透射 (Thin-Surface Transmission)
- 核心观点: 该技术旨在通过光线追踪来模拟光线穿透薄表面(Thin Surfaces) 的效果,极大地提升了如植被(Foliage) 、树叶等材质的真实感。
- 基本原理: 为了计算光线穿透物体后的能量衰减,我们需要知道光线在物体内部走过的距离(即厚度) 。这个厚度是通过从物体的背面(Back-side) 向物体内部或光源方向发射一条光线来估算的。
实现细节:从物体背面进行光线追踪 (Tracing from the Back-Side)
当一个着色点位于物体的背面,并需要计算透射光时,光线追踪的设置需要进行以下特殊调整:
-
禁用屏幕空间追踪 (Disable Screen Traces)
- 原因: 屏幕空间追踪依赖于摄像机可见的深度和颜色信息。由于光线是从物体背面(即摄像机视野外)发出的,屏幕空间信息在此处是无效的,无法追踪到被遮挡的几何体,因此必须禁用。
-
处理自相交 (Handling Self-Intersection)
- 问题: 从一个表面发射光线时,一个经典的问题是光线可能会立即与它自身所在的三角形相交,导致追踪失败。
- 解决方案:
- 翻转法线偏移方向 (Flip Normal Bias Direction): 通常,为了避免自相交,光线起点会沿着表面法线方向进行微小的偏移。但在背面追踪时,光线是向物体内部或朝向光源发射的,所以偏移方向需要翻转,即朝着法线的反方向。
- 朝向光源偏移 (Offset Ray Towards Light): 进一步地,将光线的起点朝着光源方向进行一个微小的偏移。这能有效保证光线成功“离开”起始表面,进入物体内部或朝向另一侧表面前进,而不是被“卡”在原地。
计算物体厚度 (Estimating Thickness)
-
核心流程:
- 光线从物体背面(Back-side) 的着色点出发。
- 经过上述偏移处理后,光线向物体内部/光源方向行进。
- 光线与该物体的正面(Front-side) 发生相交。
-
厚度估算:
- 光线从起点到与正面相交点所行进的距离
rayT,就可以被用作该点物体厚度的近似值。
Thickness ≈ rayT - 光线从起点到与正面相交点所行进的距离
-
最终应用:
- 这个估算出的厚度值,最终会作为参数输入到着色模型的透射项(Transmission Term) 中,用以计算光线穿透不同厚度的叶片后所呈现的颜色和亮度。
性能分析 (Performance Analysis)
本页详细分析了在 PlayStation 5 平台上,这套集成的直接光照渲染系统的性能开销。这是一个压力测试场景,旨在展示该技术在处理海量动态光源时的表现。
核心性能指标总结
- 总计耗时: 5.51 ms
- 测试平台: PlayStation 5
- 渲染分辨率: 1080p
- 采样率: 每像素 1 个样本 (1 SPP)
- 测试条件: 异步计算 (Async Compute) 已关闭。这意味着这里的耗时是串行执行的结果,开启异步计算后有望进一步优化。
- 场景复杂度:
- 屏幕上同时存在 941 个面光源。
- 每个像素平均受到 20 到 80 个光源 的影响。
- 核心观点: 这个 5.51 ms 的开销 完全取代了 传统渲染管线中所有的直接光照着色(Shading)与阴影(Shadowing)计算。它不是一个额外的特效,而是一套完整的、针对海量光源的直接光解决方案。
各阶段耗时详解
以下是渲染管线中各个主要阶段的耗时分解,分别针对 不透明物体 (Opaque) 和 半透明物体/体积雾 (Translucency/Volumetric Fog) 的计算。
-
采样 (Sampling)
- 耗时: 0.7ms (不透明) | 0.11ms (半透明/体积雾)
- 核心观点: 这是光线追踪管线的起点,为屏幕上的每个像素生成随机样本和初始光线,为后续的追踪和着色做准备。
-
屏幕空间追踪 (Screen Space Tracing)
- 耗时: 0.47ms (不透明)
- 核心观点: 在进行昂贵的硬件光追之前,优先利用屏幕空间的深度和法线等信息(G-Buffer)进行快速求交。这是一种常见的性能优化手段,可以有效处理大量已经被渲染在屏幕上的物体遮挡关系。
-
硬件光线追踪 (HW Ray Tracing)
- 耗时: 1.35ms (不透明) | 0.48ms (半透明/体积雾)
- 核心观点: 这是计算阴影遮挡关系的核心开销。利用硬件光线追踪单元进行 BVH (Bounding Volume Hierarchy) 遍历和光线-三角形求交,以判断采样点与光源之间是否存在遮挡物。
-
样本着色 (Sample Shading)
- 耗时: 0.55ms (不透明) | 0.52ms (半透明/体积雾)
- 核心观点: 在光线可见性确定后(即光线命中了光源或被遮挡),根据命中信息、材质属性和光源特性计算该点的光照贡献度。这是执行着色计算(Shading)的阶段。
-
可见光源列表 (Visible Light List)
- 耗时: 0.05ms (不透明) | 0.1ms (半透明/体积雾)
- 核心观点: 这是一个针对 "Many-Lights" 场景的关键优化。通过构建或查询一个数据结构,快速剔除对当前像素点没有贡献的光源,从而减少需要追踪和计算的光源数量。
-
降噪 (Denoising)
- 耗时: 0.96ms (不透明) | 0.22ms (半透明/体积雾)
- 核心观点: 由于每像素仅使用 1 个样本(1 SPP),追踪结果会充满噪声。降噪器 (Denoiser) 是现代光追系统中不可或缺的一环,它利用时间域和空间域的相邻像素信息,将稀疏的采样结果重建为干净、稳定的最终图像。这是一个显著的性能开销,但对于低采样率的光追至关重要。
性能分析 (Performance)
这一页详细分析了该渲染技术在特定硬件和场景下的性能开销,并揭示了系统中不同模块的成本分布与瓶颈所在。
测试环境与场景复杂度
为了准确评估性能,所有数据均在以下统一的条件下测得:
- 硬件平台: PS5
- 渲染分辨率: 1080p
- 每像素采样数: 1 SPP (Sample Per Pixel)
- 异步计算 (Async Compute): 关闭
- 场景复杂度:
- 屏幕上共 941 个面光源 (area lights)
- 每个像素平均受 20 到 80 个光源 的影响
- 所有光源均投射阴影
性能开销分解
下表展示了渲染管线中各个主要阶段的耗时(单位:毫秒)。
| 渲染阶段 (Stage) | 不透明 (Opaque) | 半透明/体积雾 (Translucency/Volumetric Fog) |
|---|---|---|
| 采样 (Sampling) | 0.7ms | 0.11ms |
| 屏幕空间追踪 (Screen Space Tracing) | 0.47ms | - |
| 硬件光线追踪 (HW Ray Tracing) | 1.35ms | 0.48ms |
| 样本着色 (Sample Shading) | 0.55ms | 0.52ms (0.1 + 0.42) |
| 可见光列表 (Visible Light List) | 0.05ms | 0.1ms |
| 降噪 (Denoising) | 0.96ms | 0.22ms |
- 总计耗时: 5.51 ms
- 核心价值: 这个总成本 完全替代了 传统的直接光照着色与阴影计算管线,为拥有大量动态光源的场景提供了高效的解决方案。
核心观察与性能洞见
通过分析数据,可以得出几个关于性能瓶颈的关键结论。
采样成本 vs. 着色成本
- 核心观点: 一个值得注意的现象是,不透明物体的采样开销(0.7ms)显著高于其着色开销(0.55ms) ,尽管采样过程是在半分辨率下执行的。这揭示了该技术的核心成本所在。
为什么采样 (Sampling) 成本高昂?
采样阶段的性能主要受以下因素影响:
- 与光源数量强相关: 采样的计算成本会随着光源数量的增加而急剧增长。在这个拥有 941 个光源的极端场景中,该阶段自然成为性能热点。
- 光源类型: 场景中大量使用了矩形面光源 (Rectangular Area Lights)。这类光源的采样算法本身就比点光源复杂得多,计算开销更大。
- GPU占用率 (Occupancy): 复杂的采样函数会使用更多的寄存器和线程组共享内存,从而降低GPU的并行执行效率 (Occupancy),导致硬件无法被充分利用,执行时间变长。
为什么着色 (Shading) 成本相对稳定?
与采样不同,着色阶段的性能表现出更高的稳定性:
- 固定的样本上限: 系统为每个像素需要着色的样本数量设置了硬性上限。无论一个像素被多少个光源影响,最终进入完整着色计算的样本数是受控的。
- 成本与Tile类型相关: 着色成本主要由Tile的类型(例如,根据材质或光照复杂性对屏幕进行的划分)决定,而不是直接受光源总数的影响。
- 可预测的开销: 这种机制使得着色成本相对固定和可预测,不会因为场景中光源数量的爆炸性增长而失控,保证了整体性能的稳定性。
性能分析 (Performance)
本页内容提供了该光照技术在实际场景中的性能开销,并将其与处理不透明物体和半透明/体积雾的成本进行了详细对比。
测试环境与场景概览
为了准确评估性能,所有数据都在一个统一且具有挑战性的环境下测得:
- 硬件平台: PS5
- 渲染分辨率: 1080p
- 采样率: 1 SPP (每像素1个样本)
- 计算方式: 关闭异步计算 (Async Compute Off),这代表了更普遍或基准的性能表现。
- 场景复杂度:
- 屏幕内同时存在 941个面光源。
- 每个像素受 20到80个光源 影响。
- 所有光源均投射阴影。
- 总性能开销: 5.51 ms
- 核心定位: 这套技术方案旨在完全取代传统渲染管线中所有的直接光照着色与阴影计算,而非一个附加效果。
性能成本分解
下表详细列出了渲染不透明物体与渲染半透明+体积雾时,各个阶段的耗时对比。
| 渲染阶段 | Opaque (不透明) | Translucency + Volumetric Fog (半透明+体积雾) | 关键分析 |
|---|---|---|---|
| 采样 (Sampling) | 0.7ms | 0.11ms | 半透明/体积雾的采样基于空间中的探针网格(Voxel Grid),其数量远少于屏幕像素,因此初始采样开销极低。 |
| 屏幕空间追踪 | 0.47ms | - | 该技术仅用于屏幕空间的不透明表面,不适用于体积效果。 |
| 硬件光线追踪 | 1.35ms | 0.48ms | 与采样阶段同理,为探针进行光追的射线数量远少于为每个像素进行光追的射线数量,因此硬件光追开销显著降低。 |
| 样本着色 (Sample Shading) | 0.55ms | 0.52ms | 这是最关键的对比项。尽管探针数量少,但半透明/体积雾的着色成本几乎与不透明物体相当。见下文的核心观察。 |
| 可见光列表 (Visible Light List) | 0.05ms | 0.1ms | 为三维空间中的探针构建可见光列表比为二维屏幕像素构建更复杂,导致开销略高。 |
| 降噪 (Denoising) | 0.96ms | 0.22ms | 降噪同样作用于探针网格,其分辨率远低于屏幕分辨率,因此计算量和开销也大幅减少。 |
核心观察与结论
本页性能数据揭示了一个非常重要的现象,也是理解该技术性能特点的关键:
-
核心观点: 尽管半透明和体积雾的计算是在一个远比屏幕分辨率低的探针网格(Probe Grid)上进行的,但其核心着色成本(Sample Shading)却与全屏像素的不透明物体渲染成本惊人地接近。
-
根本原因: 这是因为半透明和体积雾渲染对时间与空间上的稳定性要求更高。为了避免闪烁和噪点,系统必须为每一个探针(Voxel)执行更多次的采样着色。这种“以量补质”的策略,极大地增加了单个探针的计算负担,最终抵消了探针总数较少所带来的性能优势。这解释了为什么
0.11ms的低采样成本最终导向了0.52ms的高昂着色成本。
实践与反馈 (Practice & Feedback)
美术师的接受度与工作流变革 (Artist Adoption and Workflow Transformation)
-
极高的美术接受度:该技术(在讲座中被称为 MegaLights)在美术师(Artists)中获得了极高的评价和欢迎。这证明了该技术在实际生产管线中的易用性和强大效果。
-
创作自由度的解放:讲稿中提到“他们甚至可能用得太多了(Maybe even too much…)”,这句玩笑话的背后,揭示了一个核心优势:该技术极大地解放了美术师的创造力。过去,由于性能和技术的限制,美术师在使用光源时必须非常克制。而新技术则打破了这些枷锁。
-
工作流的演进 (Workflow Evolution):美术师对新技术的适应过程体现了一种思维模式的转变。
- 初期试探阶段:刚开始接触时,美术师们还延续着旧有工作流的惯性思维,在严格的光照数量和性能预算下工作,因此只是小心翼翼地在场景中放置少量光源。
- 全面拥抱阶段:当他们意识到新技术的强大能力和低廉成本后,便迅速转变了工作方式。他们开始在关卡中自由地、大量地使用光源来实现想要的的艺术效果,而不再束手束脚。
-
核心观点:赋能创意而非设限
- 一项成功的渲染技术,其最终衡量标准并不仅仅是技术指标上的突破,更在于它能否为内容创作者(如美术师)带来思维模式的转变(a new mindset) 。
- 理想的工具应该让创作者专注于“我想要实现什么效果”,而不是“我能用多少资源”。MegaLights 的成功实践证明,当技术能够提供足够高的自由度时,它将极大地激发艺术创作的潜力,并带来有趣(fun) 的创作体验。
实践应用:美术师的广泛采用 (In Practice: Artist Adoption)
本页内容从理论和实现转向了技术的实际应用和成果,核心在于展示新引入的矩形光(Rectangular Lights)技术在开发团队中,尤其是美术师群体中的接受度和使用情况。
功能广受欢迎 (A Popular Feature)
-
核心观点:该技术不仅仅是技术上的成功,更重要的是它成功地赋能了美术创作,获得了美术师的积极反馈和高度认可。
-
关键术语:美术师采纳度 (Artist Adoption)
-
要点分析:
- “Artists love it”: 这句简短的话是对技术价值的最高肯定。对于引擎开发者来说,一个新功能是否成功,最终取决于它是否被目标用户(在这里是美术师)接受并高频使用。
- 这表明该技术解决了美术师在布光时遇到的实际痛点,为他们提供了过去所缺乏的、更符合物理直觉的工具,例如模拟窗户、天花板灯带或广告牌等真实世界中的面光源。
- 这种正向反馈是驱动渲染技术进一步迭代和优化的重要动力。
矩形光的普及与影响 (The Proliferation and Impact of Rect Lights)
-
核心观点:矩形光的使用率在项目中急剧攀升,几乎无处不在,这既体现了其价值,也带来了一些需要关注的新问题。
-
关键术语:功能普及 (Feature Proliferation), 性能预算 (Performance Budget)
-
要点分析:
- “Rect lights everywhere”: 这描述了一种普遍现象——一旦一个强大且直观的工具被提供,美术师们会倾向于在各种合适的场景中广泛应用它,以提升画面的真实感和艺术表现力。
- “Maybe even too much…”: 这句带有调侃意味的评论,揭示了功能普及后可能带来的挑战,值得引擎开发者深入思考:
- 性能考量: 虽然前面可能已经介绍了诸多优化,但任何高级光照功能的广泛使用都会对性能预算构成压力。当场景中矩形光的数量激增时,可能会触及性能瓶颈。这要求引擎开发者必须提供强大的性能分析工具(Profiler),帮助美术师理解他们所做选择的性能成本,并制定相应的最佳实践(Best Practices) 。
- 艺术指导: 技术上可行不代表艺术上总是最优解。过度或不恰当地使用某种技术,可能会导致视觉风格的单一化,或者在不必要的地方浪费性能。这暗示了技术团队与美术团队之间需要保持紧密沟通,共同探索新功能的艺术潜力与边界。
实践中的挑战:美术师工作流与光照塑形
本页探讨了在实际项目开发中,当先进的光照技术交到美术师手中时所遇到的现实问题,特别是围绕着光照塑形(Light Shaping) 的矛盾与解决方案。
核心问题:美术师倾向于使用物理几何体进行光照塑形
美术师非常喜欢使用新的光照功能,尤其是矩形光源(Rect Lights) ,因为它们能创造出更柔和、更真实的照明效果。然而,这也带来了一个普遍存在的工作流问题:
- 美术师的直觉:为了控制光线的形状和遮挡(例如模拟灯罩、百叶窗或谷仓门的效果),美术师会直观地在光源周围放置实际的几何模型(Light Fixtures) 。
- 渲染的挑战:这种基于物理遮挡的光照塑形方式,对渲染器来说非常棘手。它使得光源的采样和解析变得极其困难。传统的分析性光源(点、面、球)有精确的采样方法,但一个被任意网格遮挡的光源,其有效的发光形状变得复杂且不规则,难以高效且准确地进行采样。
- 具体的渲染错误:配图展示了一个典型问题。一个用于塑形的灯具网格因为距离太远或尺寸太小,被光线追踪的剔除系统(Culling System) 给优化掉了。结果就是,这个灯具对光线的遮挡效果消失了,导致阴影丢失和漏光(Light Leaking) ,严重改变了场景的整体光照氛围。
解决方案:理想 vs. 现实
面对这个问题,存在两种不同的解决思路:一种是技术上更优越的“理想方案”,另一种是项目开发中更具可行性的“实践方案”。
理想方案:分离光照定义与物理表现
从渲染管线的角度看,最高效、最准确的做法是:
- 使用光照函数(Light Functions) :光照的复杂形状和衰减应该通过光照函数来定义。这可以是一个贴图(类似 IES 配置文件),或是一段程序化逻辑。
- 核心优势:光照函数在光线采样阶段的求值成本极低,渲染器可以继续使用高效的采样策略,同时获得复杂的塑形效果。
- 跳过灯具几何体:为了避免灯具模型对自身的“自投影”问题,可以为每个光源设置一个光线末端偏移(Ray End Bias) 。
- 工作原理:当从场景中的某个点向该光源投射阴影光线时,这个偏移值会告诉光线追踪器忽略与指定灯具几何体的相交。这样,灯具本身不会遮挡自己发出的光,但它仍然可以被场景中的其他光源照亮,也可以在反射中可见。
核心观点:理想的解决方案是将光的发射属性(由光照函数定义)与其物理几何表现(模型)解耦,从而在保持艺术效果的同时,确保渲染的性能和准确性。
实践方案:手动干预剔除系统
尽管理想方案很完美,但在项目实践中(如此次演讲的Demo),团队并未完全采用。原因可能是时间限制,或问题在多数情况下并不严重。因此,他们采用了一个更直接的妥协方案:
- 问题根源:自动化的剔除系统无法分辨一个小的几何体是无关紧要的装饰,还是对光照至关重要的塑形物体。
- 实际对策:让美术师在BVH(Bounding Volume Hierarchy) 中手动标记(Manually Tag) 那些作为灯具的几何体。
- 效果:这个标记会告诉剔除系统:“无论这个物体多远或多小,都不要剔除它,因为它对最终的光照结果有决定性影响。”
核心观点:在无法实现理想技术方案时,通过扩展美术工作流,引入手动标记等“约定”,是一种有效的折衷办法,可以避免因自动化优化系统导致的严重视觉错误。
实践应用 (Practice)
本页内容从技术实现转向了该技术在实际开发流程中的应用和反响,特别是来自美术团队的反馈和创新的工作流。
美术的广泛采纳与热情 (Widespread Adoption and Enthusiasm from Artists)
- 核心观点: 讲座中讨论的(可能是区域光)照明技术在美术团队中获得了巨大的成功和喜爱,它不仅仅是一个技术上的突破,更是一个赋能美术创作的强大工具。
- 过度使用的趋势: 美术师们非常喜欢使用这项技术,以至于出现了“过度使用”的趋势("Maybe even too much...")。例如,场景中随处可见 矩形光 (Rect lights)。这从侧面证明了该技术的易用性和出色的视觉效果,使其成为美术师们的首选。
创新的美术工作流 (Innovative Art Workflows)
- 核心观点: 美术师们不仅在使用这些新光源,还在围绕它创造新的工作方法,以实现更真实、更具艺术感的光照效果。
- 关键术语: 灯具塑形 (Shaping lights using light fixtures)
- 这是一种非常重要的工作流程:美术师不再是简单地放置一个无形的“光源”,而是会先创建灯具的3D模型(例如灯罩、格栅、筒灯外壳),然后将光源(如矩形光)放置在模型内部。
- 这样一来,光线的形状、遮挡和柔和度会受到物理灯具模型的自然影响,从而产生极为逼真和可信的光照效果。
工具链的演进与自动化 (Evolution of the Toolchain and Automation)
- 核心观点: 随着该技术的成熟,工具链也随之发展,出现了自动化工具来进一步提升美术师的工作效率。
- 关键术语: 程序化光源生成器 (Procedural light spawners)
- 这类工具允许美术师高效地批量创建和放置光源。
- 一个典型的例子是,美术师可以沿着一条绘制的 样条线 (Spline) 自动生成一连串的光源。这对于布置长廊的顶灯、桥梁的灯带、或复杂的霓虹灯招牌等场景非常有用,极大地节约了手动放置和对齐的时间。
- 这也标志着该照明技术已经深度整合到生产管线中,成为一个成熟且不可或缺的组成部分。
内容优化 (Content Optimizations)
在采用了随机渲染技术(如随机光照采样)的现代渲染管线中,虽然对光源数量和复杂度的处理能力大大增强,但传统的内容侧优化方法依然具有其价值。
随机光照采样的宽容性
-
核心观点: 随机光照采样(Stochastic Light Sampling) 相比于传统的确定性光照算法(如 Forward+, Tiled Deferred),在处理大量光源时表现出更强的鲁棒性和宽容性。
-
性能扩展性更好: 系统的性能开销与每个像素的采样数量相关,而不再与影响该像素的光源总数直接强相关。这使得渲染器能够从容应对包含成百上千个光源的复杂场景。
-
对“坏”内容容忍度更高: 开发者发现,即使场景中存在一些不符合传统优化规范的设置,系统也不会像过去那样轻易崩溃或出现严重的性能瓶颈。
- 示例 1: 在墙体内部错误地放置了带有纹理的区域光。
- 示例 2: 使用大量独立的小光源来拼凑出一个复杂的光照效果,而实际上更适合使用一个带IES Profile的光源来模拟。
传统内容优化依然重要
-
核心观点: 随机光照采样并非没有代价的“银弹”,它将过去确定性的性能瓶颈问题,转化为了性能开销与画面噪点之间的权衡。因此,内容侧的优化仍然至关重要。
-
不进行优化的代价:
- 增加噪点 (Increase Noise): 场景中存在大量影响范围广但贡献低的光源时,有限的光线采样数可能无法有效地“命中”那些真正重要的光源,导致最终成像充满噪点或能量损失。
- 降低采样性能 (Reduce Sampling Pass Performance): 虽然性能不与光源数量直接挂钩,但大量复杂的光源会增加光照数据结构(如 BVH 或光照树)的构建和遍历开销,从而拖慢采样过程的整体性能。
-
仍然有效的优化手段:
- 衰减范围 (Attenuation Range): 尽可能精确并缩小光源的影响半径。这是最基本且极为有效的优化手段,可以显著减少光源对采样结构和噪点的影响。
- 聚光灯锥角 (Spot Light Cone Angles): 收紧聚光灯的照射范围,避免不必要的光照计算和采样。
- 矩形光的挡板 (Rect Light Barn Doors): 对于面光源,通过设置类似“挡板”的参数来限制其出光方向和范围。
- 光照函数 (Light Functions): (例如,在光源上投射一个纹理)虽然支持,但复杂的函数会增加采样时的计算开销,应谨慎使用。
总结: 实时光线追踪直接光照的实践与权衡
本页内容对前面介绍的基于实时光线追踪(RT)的直接光照技术进行了全面的总结,分析了其核心优势、质量与性能瓶颈,并探讨了在实际游戏项目中的应用策略与权衡。
核心优势: 解放直接光照的限制
这项技术最大的价值在于,它为直接光照的计算提供了全新的思路,即使在像主机这样计算资源相对有限的平台上也切实可行。
-
打破光源数量瓶颈: 传统的光照渲染管线(如延迟渲染)中,光源数量是一个主要的性能瓶颈。而基于随机采样(Stochastic Sampling) 的光追方法,其性能开销与场景中的光源总数关联性较弱,艺术家因此可以更自由地布置大量光源,创造更丰富、更具层次感的场景,而无需担心性能急剧下降。
-
灵活的性能与质量伸缩: 随机化方法天然具备出色的性能与质量的权衡(Tradeoff) 能力。开发者可以通过调整每个像素采样的光源数量或光线数量,轻松地在不同硬件平台上实现从高效率到高质量的平滑过渡,而无需为不同质量等级维护多套复杂的光照设定或进行大量手动调整。
质量瓶颈与挑战
尽管优势明显,这项技术的最终渲染质量依然受限于以下几个关键因素:
-
BVH 的几何表示精度: 光线追踪的效率和精度依赖于BVH(Bounding Volume Hierarchy) 加速结构。如果BVH为了性能而对场景几何体进行了过度简化,那么它将无法表示出精细的几何细节,从而导致阴影等效果出现失真或错误,例如小物体的阴影可能会消失。
-
每像素采样数(Samples Per Pixel, SPP) : 在性能预算紧张的情况下(尤其是在主机上),我们通常只能承担每像素发射1条光线(1 SPP) 的成本。这意味着原始的渲染结果会充满噪点,因此,一套高效的采样策略(Sampling Strategy) 和强大的降噪器(Denoiser) 对于获得干净、稳定的最终图像至关重要。
-
时间性瑕疵(Temporal Artifacts) : 这类随机采样技术严重依赖于时间累积(Temporal Accumulation) 来摊销采样成本,即复用前几帧的数据来减少当前帧的噪点。当镜头或物体快速移动时,历史数据会失效,导致累积中断,从而产生拖影、闪烁等视觉瑕疵。
性能考量与伸缩性
该技术的性能主要与以下两个因素直接相关:
-
每像素采样的光源数量: 每个像素需要评估的光源越多,追踪的光线就越多,性能开销也随之线性增长。这是控制性能的核心参数。
-
BVH 复杂度: 场景的几何复杂度(例如,三角形数量、实例数量)直接决定了BVH的复杂程度。一个更深、更复杂的BVH会增加光线遍历(Ray Traversal)的成本,从而降低整体性能。
实践中的混合方案与妥协
在真实的游戏开发环境中,单纯依赖光线追踪并非总是最优解。为了扬长避短,我们常常采用混合方案和一些巧妙的妥协。
-
处理局部光源(Local Lights) : 艺术家在使用区域光(Area Lights) 时,最关心的是物体与表面接触点附近的接触阴影(Contact Shadows) 。光线刚离开物体表面的“第一段(first segment)”路径通常较短,这一部分可以非常高效地通过屏幕空间追踪(Screen Space Tracing) 来处理。将屏幕空间追踪与世界空间的光线追踪结合,是解决局部光源阴影性价比极高的方案。
-
处理方向光(Directional Light) : 方向光(如太阳光)的挑战在于它需要在非常远的距离上投射出锐利的阴影,这对于有精度限制的BVH来说是一个巨大的挑战。在这种情况下,一个务实的选择是回退到传统的阴影技术,例如VSM(Variance Shadow Maps) 。我们可以完全使用VSM来处理方向光阴影,或者采用一种混合追踪方案,结合光线追踪和VSM的优势。
-
缓解时间性瑕疵:
- 对于较小的光源,我们可以只对每个像素最重要的那个光源进行采样,这样几乎可以获得“即时”的响应,不严重依赖时间累积。
- 对于大型光源或多个重要光源并存的情况,时间瑕疵会更明显。但在实践中,这些瑕疵通常可以被降噪器(Denoiser) 有效地隐藏起来。
- 在高端GPU上,我们可以负担更多的SPP,从而从根本上减少对时间累积的依赖,问题自然得到缓解。
未来工作 (Future Work)
本页内容概述了 MegaLights 技术在走向成熟和广泛应用过程中需要解决的几个关键问题和未来的发展方向。主要分为三大块:产品化准备、硬件可伸缩性以及与渲染管线后端(降噪、超分)的整合。
生产就绪 (Production Ready)
核心观点: MegaLights 目前仍处于开发阶段,要达到能在实际游戏项目中大规模使用的“生产就绪”状态,还需要在功能、性能和工具链上进行大量完善。
-
完善功能矩阵 (Feature Matrix):
- 当前系统尚未完全支持所有必需的渲染特性,需要继续开发以填补功能上的空白,使其成为一个完整的、通用的光照解决方案。
-
性能优化与问题修复 (Optimizations and Fixes):
- 混合采样策略: 计划将显式光源采样 (Explicit Light Sampling) 与 BRDF 采样 (BRDF Sampling) 结合。
- 显式光源采样对于采样远距离或体积较小的光源非常高效。
- BRDF 采样则更适合处理大面积光源或高反射率表面。
- 一个关键的优化点是 反射光线复用 (Reflection ray reuse):可以复用已有的反射追踪光线(例如 Lumen 系统中的光线)来对直接光进行采样,这是一种低成本提升直接光照质量的有效手段。
- 其他优化方向: 包括实现自适应采样 (Adaptive sampling) 来更智能地分配光线预算,以及改进区域光引导 (Area Light Guiding) 算法来提升采样效率。
- 混合采样策略: 计划将显式光源采样 (Explicit Light Sampling) 与 BRDF 采样 (BRDF Sampling) 结合。
-
前向着色支持 (Forward Shading):
- 需要改进对前向渲染管线的支持。一个可能的方向是利用 GPU 驱动的反馈机制 (GPU driven feedback),根据前向着色阶段实际渲染的物体表面信息,来动态地指导和优化光线采样过程。
-
内容审查与调试工具 (Content Linting Tools):
- 为了方便美术师和开发者使用,需要提供更强大的工具来调试、分析和优化使用了 MegaLights 的场景,帮助他们快速定位性能瓶颈和视觉问题。
硬件可伸缩性 (Scalability)
核心观点: 如何让使用了 MegaLights 技术的美术内容在从低端移动设备到高端 PC 的广阔硬件范围内都能良好运行,是一个亟待解决的开放性问题。
-
面向移动端的扩展 (Scaling to Mobile):
- 这是一个核心挑战。当美术师使用 MegaLights 创作了包含海量光源的场景后,如何自动地、优雅地将这些内容“降级”以适应性能有限的移动设备?
- 目标是避免让美术师为不同平台手动维护多套光照配置,这会极大地增加工作量和维护成本。
-
高端 PC 的适用性 (High-end PC Suitability):
- 需要反思和评估 MegaLights 对于顶级 PC 硬件是否仍然是最佳选择。高端 GPU 拥有强大的算力,或许可以通过更直接、暴力的路径(如传统的光线追踪)来达到相似或更好的效果。需要明确 MegaLights 在整个硬件谱系中的最佳定位。
联合降噪与超分辨率 (Joint Denoising and Upsampling)
核心观点: 当前 MegaLights 的降噪流程与引擎的全局时间性超分辨率方案(如 TSR)是分离的,这种分离会带来问题。未来的目标是让二者更紧密地结合,以提升最终图像质量和性能。
-
当前的问题:
- MegaLights 会先运行自己内部的独立降噪器。
- 降噪后的结果再被送入后续的时间性超分辨率 (Temporal Super Resolution, TSR) 流程进行处理。
- 这种“两步走”的流程可能会导致信息丢失、产生额外的瑕疵 (artifacts),并且不是最优的性能方案。
-
未来的探索方向:
- 增强信息传递: 让 MegaLights 的内部降噪器向 TSR 传递更多的辅助信息(metadata),帮助 TSR 做出更准确的重建决策。
- 统一降噪流程: 将所有的降噪工作完全移交给 TSR 处理,MegaLights 只输出原始的、带有噪声的信号。这需要 TSR 具备处理这种特定噪声模式的能力。
- 机器学习 (ML) 的应用: 关注并探索利用机器学习/深度学习技术在联合降噪与超分领域的前沿研究,这些技术在该问题上展现出了巨大的潜力。
未来挑战 - BVH
BVH: 硬件光线追踪的核心瓶颈
讲座的核心观点指出,BVH (Bounding Volume Hierarchy, 包围盒层次结构) 是当前硬件光线追踪技术发展中最主要的限制因素。尽管光追技术已经取得了长足进步,但BVH在以下几个方面依然是亟待解决的瓶颈:
- 内存占用 (Memory): BVH本身就是一种数据结构,需要占用大量的显存来存储。对于极端复杂的场景,BVH的显存开销会变得难以接受。
- 构建时间 (BVH Build Times): 尤其对于动态场景,实时地、高质量地重建或更新BVH非常耗时,这直接影响了帧率和性能。
- 遍历性能 (Traversal Performance): 光线与场景求交的过程就是遍历BVH的过程。如果BVH的结构不佳(例如,由大量零碎小物体组成的模型),遍历效率会急剧下降。
- 手动优化 (Manual Optimization): 为了获得理想的BVH性能,艺术家和开发者往往需要手动优化光线追踪专用的几何体代理(Proxy Mesh),这与现代渲染管线追求自动化和“所见即所得”的理念背道而驰。
几何复杂度的持续增长带来的新问题
随着渲染技术的发展,现代游戏引擎正在处理越来越复杂的几何形态,这进一步加剧了BVH面临的挑战。这些新型几何体难以用传统方式高效地表示在BVH中。
- 发丝 (Hair splines): 由大量曲线构成,传统基于三角形的BVH对其表达效率极低。
- Nanite 曲面细分 (Nanite Tessellation): Nanite作为一种虚拟化几何管线,能够渲染海量微观多边形,但如何将这种动态变化的、细节极其丰富的几何体高效地转换为光追所需的BVH是一个难题。
- Nanite 植被 (Nanite Foliage): 同样,使用Nanite技术渲染的巨量植被,其几何细节和实例数量都对BVH的构建和内存构成了巨大压力。
实践中的具体挑战与权衡
1. 代理模型(Proxy Meshes)的局限性
过去,我们可以使用低精度代理模型(Low Poly Proxies)来进行光线追踪计算,因为对于漫反射全局光照 (Diffuse GI) 和粗糙反射 (Rough Reflections) 这类比较模糊的效果,模型的微小瑕疵并不容易被察觉。
然而,对于高质量的直接光阴影 (Shadows for direct lighting),情况则完全不同。锐利的阴影会毫不留情地暴露低精度模型的轮廓和瑕疵,使得这种“偷懒”的方法在追求高画质的场景中不再适用。
2. 难以解决的动态几何难题
动态几何 (Dynamic Geometry) 至今仍然是一个未被完全解决的难题。在场景中表示大量精确的动画实例 (animated instances),会轻易地耗尽内存和性能预算,使其在当前技术条件下几乎不可能实现。
3. 低效的几何体布局与BVH重编(Rebraiding)
一些常见的美术工作流也会导致光追性能问题:
- “套件拼接” (Kitbashing): 用大量小部件拼合成一个大模型,会导致BVH结构臃肿、效率低下。
- 巨大稀疏网格 (Huge, sparse meshes): 例如,用一个单独的网格制作的巨大洞穴或天空盒,其内部包含大量空白区域,同样会降低BVH的遍历效率。
理论上,可以通过 BVH 重编 (BVH Rebraiding) 技术来优化这些结构不良的BVH。但这是一种高成本操作,不仅消耗大量计算资源,还需要更多内存,与当前BVH构建时间和内存已经捉襟见肘的现状相悖,因此并非理想的解决方案。
4. Nanite 与光线追踪的矛盾
Nanite 为光栅化管线解决了大部分网格优化问题,实现了几何体的虚拟化,极大地解放了美术师。但光线追踪的限制,使得这些被Nanite隐藏的问题重新浮现。为了获得好的光追性能,美术师不得不重新为BVH手动优化模型,这无疑是一种工作流上的倒退。
展望:未来的方向
尽管挑战重重,但业界也在不断进步。新的光追API扩展 (new extensions to ray tracing APIs) 已经开始出现,它们有望更高效地表示像Nanite这样的复杂虚拟化几何体。
然而,根本问题依然存在:几何体的复杂度在不断增长,新的内容类型(如发丝、程序化植被)对光追表达提出了更高的要求。在我们能够完全依赖纯光线追踪 (pure ray tracing) 进行所有渲染(尤其是阴影)之前,必须首先攻克几何体的高效表达和BVH的性能瓶颈。