全局光照 (Global Illumination)

你好!欢迎来到全局光照(Global Illumination, GI)的世界。这一章是实时渲染中非常核心且富有挑战性的部分。正如皮克斯技术总监 Jeremy Birn 所说,最顶级的计算机图形,是让你感觉不到它是计算机生成的。GI 正是实现这种真实感的关键。

我们之前学习的局部光照模型,只考虑了从光源直接照射到物体表面的光。而全局光照则更进一步,它模拟了光线在场景中bounces (反弹)的过程,例如光从墙壁反弹到天花板,再照亮整个房间。这带来了间接光照(Indirect Lighting),从而产生柔和阴影、颜色溢出(Color Bleeding)等关键的真实感效果。


11.1 渲染方程 (The Rendering Equation)

这是整个全局光照领域的理论基石,理解它至关重要。

  • 核心观点: 渲染方程是一个物理模型,它精炼地描述了场景中所有光线能量传输达到稳定状态后的样子。它的核心思想可以通俗地理解为:

    一个点看出去的光 = 它自己发的光 + 所有从别的地⽅射⼊、再被它反射出去的光的总和。

从反射方程到渲染方程

我们先回顾一下熟悉的反射方程 (Reflectance Equation),它只处理直接光照:

  • 它计算的是p点沿v方向的出射光,通过对整个半球上所有方向l入射光进行积分得到。
  • 这里的通常被假定为来自场景中的直接光源。

现在,我们来看完整的渲染方程 (Rendering Equation)

这个方程在反射方程的基础上,引入了两个关键变化:

  1. 自发光项 :

    • 关键术语: Emitted Radiance (自发光辐射度)
    • 这个很好理解,它代表了表面p自身作为光源向v方向发出的光。比如一个灯泡的表面,它自己就会发光。
  2. 递归的入射光项:

    • 这是渲染方程最核心、也是最难解的地方。注意看,积分内的被替换了:
    • 核心观点: 一个点的入射光,必然是场景中另一个点的出射光。
    • 关键术语:
      • Ray Casting Function : 一个函数,表示从点p沿方向l投射光线,所击中的第一个点。
      • Recursive Nature (递归特性): 为了求解p点的,你需要知道所有方向射入p点的。而根据公式(11.3),这些其实是其他点的。为了求解那些点的,你又需要知道更早之前的点的……这个过程会无限进行下去。这完美地用数学描述了光线在场景中不断反弹的物理过程。

光路表示法 (Path Notation)

为了更好地分析和归类各种复杂的GI算法,Heckbert提出了一套非常经典的光路表示法。

  • 核心观点: 我们可以用一个简单的正则表达式来描述一种渲染算法能够模拟的光线传播路径类型。

  • 关键术语/符号:

    • L: 代表光源 (Light)。
    • E: 代表眼睛或相机 (Eye)。
    • D: 代表一次漫反射 (Diffuse) 反弹。
    • S: 代表一次镜面 (Specular)光滑 (Glossy) 反弹。
    • *: 代表0次或多次。
    • |: 代表“或”。
  • 示例:

    • 局部光照 (Local Illumination): L(D|S)E。光线从光源发出,经过一次漫反射或镜面反射,直接进入眼睛。这是最基础的实时渲染管线。
    • 理想的全局光照 (Full Global Illumination): L(D|S)*E。光线从光源发出,经过任意次(0次或多次)的漫反射或镜面反射,最终进入眼睛。这完整地对应了渲染方程。
    • 简单的镜面反射: LSE。比如在物体上看到点光源的镜面高光。
    • 一次弹射的间接光: LDDE。光源照亮A点(漫反射),A点再照亮B点(漫反射),最终被眼睛看到。这就是颜色溢出的典型路径。

实时渲染的核心策略

完整求解渲染方程的计算量是无穷的。因此,在实时渲染领域,我们必须采取近似策略:

  1. 简化 (Simplification): 大幅简化光线传播模型。例如,只考虑一次或两次反弹的间接光,或者假设所有间接光照都是完全漫反射的。
  2. 预计算 (Precomputation): 对于场景中静态的部分,离线花费大量时间计算出高质量的GI结果,并将其“烘焙”到光照贴图(Lightmap)等数据结构中,运行时直接采样使用。

11.2 通用全局光照 (General Global Illumination)

在深入研究实时GI技术之前,有必要了解一下离线渲染中求解渲染方程的经典方法。它们是所有实时GI算法的理论源头和质量标杆。

  • 核心观点: 尽管离线GI算法本身速度很慢,不适用于实时渲染,但它们为实时技术提供了理论基础和预计算工具。

主要分为两大流派:

  1. 有限元法 (Finite Element) 辐射度 (Radiosity)

    • 核心思想: 将场景表面拆分成许多小的面片 (patches),然后计算这些面片之间如何相互传递能量。它求解的是一个大型的线性方程组。
    • 强项: 非常擅长模拟理想漫反射表面之间的光线反弹(LD*E路径)。能够非常精准地计算出颜色溢出和柔和阴影等效果。
    • 弱点: 难以处理镜面或光滑表面的反射。在90年代的游戏中,基于辐射度的光照烘焙非常流行。
  2. 蒙特卡洛法 (Monte Carlo) 光线追踪 (Ray Tracing) / 路径追踪 (Path Tracing)

    • 核心思想: 不去解复杂的积分方程,而是用概率和统计的方法来“暴力”求解。通过从相机向场景中发射大量随机光线,追踪它们的完整路径,并统计最终结果的平均值,以此来近似渲染方程的解。
    • 强项: 极其通用。天生就能处理各种复杂的光路(L(D|S)*E),无论是漫反射、镜面反射、折射、焦散,都可以在同一个框架下解决。是当前电影级渲染的工业标准。
    • 弱点: 计算成本极高,并且结果会带有噪声 (noise),需要发射海量光线才能收敛到干净的图像。
  • 对你的意义:
    • 预计算: 如今游戏引擎中的高质量光照烘焙(Baking),底层大多是基于路径追踪的变种。
    • 实时光线追踪 (RTX/DXR): 现代GPU提供的硬件加速光追功能,实际上就是在硬件层面加速了“发射光线-求交”这个核心操作,使得我们能在实时帧率下,运行简化版的路径追踪算法,实现更高质量的GI、反射和阴影。

接下来的章节将会深入探讨如何将这些理论,通过各种聪明的简化和预计算技巧,应用到实时渲染中。


我们已经确定渲染方程描述了光传输的物理学,但求解它的计算成本很高。现在,让我们探索为解决这一挑战而开发的两种经典的离线方法:辐射度(Radiosity)和光线追踪(Ray Tracing)。了解它们的核心原理至关重要,因为许多实时GI技术都是对这些基础算法的巧妙调整或简化。

11.2.1 辐射度 (Radiosity)

  • 核心观点: 辐射度是一种专注于模拟 漫反射表面间光能传递 的算法。它非常适合计算由大面积光源产生的软阴影和颜色溢出(Color Bleeding)效果。

  • 光路表示法: LD*E。这意味着它能完美地模拟从光源出发,经过任意次漫反射,最终到达眼睛的光路。注意,这里没有S(镜面),这是辐射度法的关键限制。

  • 核心思想与算法流程:

    1. 场景离散化: 将场景中的所有表面拆分成一系列小的面片 (patches)。这些面片是计算光能的基本单位。
    2. 计算形状因子 (Form Factor): 对每对面片 (i, j),计算一个形状因子
      • 关键术语: Shape Factor (形状因子) 是一个纯粹的几何量,它描述了**“从面片 i 均匀漫反射出去的所有能量中,有多大比例会直接到达面片 j”**。
      • 它取决于两个面片的面积、距离、相对朝向,以及它们之间是否有遮挡物。
      • 其计算公式如下: (你不需要手算这个积分,关键是理解它背后的几何意义)。
    3. 建立并求解线性系统: 基于所有面片间的形状因子,可以构建一个大型的线性方程组。
      • 是我们要求解的,面片 i 的最终辐射度(总的出射能量)。
      • 是面片 i 的自发光能量。
      • 是面片 i 的漫反射率。
      • 表示面片 i 从所有其他面片 j 接收到的能量总和。
    4. 得到结果: 求解这个方程组后,我们就得到了每个面片的最终光照强度,这个结果已经包含了所有间接光照。
  • 优点与局限:

    • 优点: 视图无关(view-independent)。一旦计算完成,你可以从任何角度观察场景,光照结果都是现成的。非常适合建筑可视化和静态场景的光照烘焙。
    • 局限:
      1. 仅限漫反射: 无法处理镜子、金属等光滑或镜面材质。
      2. 计算量巨大: 面片数量稍多,求解线性方程组的开销就会变得难以承受。
      3. 存储开销大: 需要存储 N x N 个形状因子(N为面片数量)。
  • 对实时渲染的意义: 虽然经典的辐射度算法已很少直接使用,但其**“预计算几何体之间光线传输关系”**的核心思想被许多现代实时GI技术所借鉴(我们将在11.5.3节看到相关技术)。


11.2.2 光线追踪 (Ray Tracing)

  • 核心观点: 光线追踪是一个极其通用的框架,通过模拟单个光子的传播路径来求解渲染方程。与辐射度不同,它可以处理任意类型的材质和光线交互。

  • 基本操作: Ray Casting (光线投射)

    • 从一个点沿一个方向发射光线,找到它与场景的第一个交点。这是所有光线追踪算法的基础。
  • 从经典光追到路径追踪:

    1. 经典光线追踪 (Whitted-Style Ray Tracing):

      • 流程: 从相机发射主光线。在交点处,向光源发射阴影光线 (Shadow Ray),并沿镜面反射和折射方向发射次级光线 (Secondary Rays)。这个过程递归进行。
      • 效果: 只能产生硬阴影纯镜面反射/折射。无法模拟漫反射间的能量传递(颜色溢出)或光滑表面的模糊反射。
    2. 路径追踪 (Path Tracing):

      • 这是真正意义上求解渲染方程的方法。
      • 核心思想: 蒙特卡洛积分 (Monte Carlo Integration)。渲染方程本质上是一个复杂的积分。蒙特卡洛方法告诉我们,可以用大量随机采样的平均值来近似这个积分的结果。
      • 流程:
        • 从相机发射一条光线。
        • 当光线击中物体表面时,根据该表面材质的BRDF随机选择一个出射方向,生成下一条光线。
        • 光线就这样在场景中随机“弹跳”,形成一条路径 (path)
        • 我们记录下整条路径对最终像素的能量贡献。
        • 对同一个像素,重复上述过程成百上千次,生成大量独立的随机路径。
        • 将所有路径的贡献值平均起来,就得到了该像素的最终颜色。
  • 路径追踪的挑战与对策:

    • 挑战: 高方差 (High Variance) 噪声 (Noise)
      • 因为是随机采样,如果每个像素的采样路径数量不足,那么相邻像素的计算结果可能会有很大差异,在视觉上就表现为麻点状的噪声。如上图11.6所示,8个采样点的图像噪点严重,而1024个采样点就好得多。
    • 对策: 重要性采样 (Importance Sampling)
      • 核心观点: 与其完全随机地散射光线,不如**“聪明地”**向那些贡献更大能量的方向(比如光源方向、BRDF波峰方向)发射更多的光线。
      • 这可以在不显著增加路径数量的情况下,大幅降低方差,从而更快地得到一张干净的图像。
  • 对实时渲染的意义:

    • 路径追踪是离线渲染的**“黄金标准 (Gold Standard)”**,是衡量其他渲染技术真实度的标杆。
    • 硬件加速光线追踪(如NVIDIA RTX, DXR)的出现,使得我们可以在实时应用中运行简化版的路径追踪算法,在每个像素发射少量光线来计算更真实的光照效果,这就是实时光线追踪 (Real-Time Ray Tracing, RTT) 的基础。

让我们深入了解环境光遮挡。这是最基本和最广泛使用的实时全局照明近似之一。它是一个在实现视觉愉悦效果的同时,牺牲物理精度来换取性能的完美例子。

11.3 环境光遮蔽 (Ambient Occlusion, AO)

  • 核心观点: 环境光遮蔽 (AO) 是一种近似的、简化的全局光照技术。它并不模拟光线的真实反弹,而是计算每个点**“暴露”在环境光下的程度**。其主要目的是在缺乏复杂光照时,通过在缝隙、角落和接触区域产生柔和的阴影,来增强模型的体积感和细节表现力。

  • 为什么需要AO? 想象一个阴天,光线从天空各个方向均匀射下。一个没有任何GI的渲染器会把所有物体渲染成一片“平坦”的颜色,毫无立体感。AO就是为了解决这个问题而生的,它能廉价地模拟出物体间的接触阴影自身遮挡

11.3.1 AO 理论基础

AO的理论推导过程,本身就是一次对渲染方程进行层层简化的绝佳示范。

  • 出发点: 我们从一个极其理想化的场景假设开始:

    1. 假设一 (材质): 场景中所有表面都是理想漫反射 (Lambertian)
    2. 假设二 (光照): 环境光是完全均匀的,即从天空半球的任何方向射来的光线亮度 都相同。
    3. 关键假设三 (遮挡): 如果某个方向被遮挡,那么从该方向射来的光强直接为零。这是一个非常粗暴的简化,因为它完全忽略了光线的反弹(相互反射)
  • 核心公式: 基于以上假设,我们得出了环境遮挡系数 的定义:

    • 关键术语:
      • (环境遮挡系数): 一个范围在 [0, 1] 之间的标量值。 表示该点完全暴露在环境中(如球体顶点), 表示该点被完全包裹(理论值)。值越小,该点就越“暗”。
      • (可见性函数): 这是个二进制函数。从点 p 沿方向 l 看去,如果能看到天空,则 ;如果被其他几何体挡住,则
    • 直观理解: 这个公式计算的是,在点p的表面法线所在的半球内,所有未被遮挡方向的余弦加权平均值。可以想象成在p点对天空的“可见度”百分比。
  • 衍生数据: Bent Normal (弯曲法线)

    • 核心观点: 除了遮挡度 ,我们还可以计算一个平均的、未被遮挡的方向,称为 Bent Normal
    • 用途: 在对环境贴图(CubeMap)进行采样时,使用 来代替原始的几何法线 ,可以获得更准确的间接镜面反射结果,因为它指向的是实际能接收到光线的方向。

11.3.2 可见性 (Visibility) vs. Obscurance

  • 核心观点: 纯粹的、基于无限远距离的“可见性”在封闭或半封闭空间中效果很差,因此我们引入了基于距离衰减Obscurance 作为一种更实用、更具艺术控制性的**“图形学技巧”**。

  • Visibility 的问题: 想象你在一个封闭的房间里。从任何一个墙面上的点向外发射光线,最终都必然会撞到另一面墙。按照严格的可见性定义, 将永远为0,导致整个房间一片漆黑。这在物理上“正确”,但在视觉上毫无用处。

  • Obscurance 的解决方案:

    • 关键术语:
      • Obscurance (遮蔽度): 用一个连续的、与距离相关的函数 来代替二进制的可见性函数
      • (最大影响距离): 设定一个最大距离。当光线击中一个物体时:
        • 如果距离为0,遮挡度为1 (最暗)。
        • 如果距离大于 ,我们视其为没有遮挡,遮挡度为0 (最亮)。
        • 距离在 0 到 之间,遮挡度平滑过渡。
    • 优势:
      1. 局部性: AO效果被限制在物体附近的狭小空间内,这正是我们通常想要的效果。
      2. 艺术可控: 艺术家可以通过调整 来控制AO的范围和强度。
      3. 性能: 限制了光线追踪的距离,可以显著提升计算速度。

11.3.3 补偿缺失的光:近似相互反射

  • 核心观点: 标准AO因为忽略了光线反弹,导致结果普遍偏暗。我们可以通过简单的数学模型来近似这种相互反射 (interreflection),从而“提亮”被遮挡的区域,使其更接近完整GI的效果。

  • 问题的根源: AO假设遮挡物是“黑洞”,不反射任何光线。但在现实中,墙角不仅接收到的直接天光少,还会接收到从两面墙壁相互反射过来的光。

  • 解决方案 (两种思路):

    1. 解析模型 (Analytical Approach - Stewart & Langer):

      • 核心思想: 做一个巧妙的假设——“从遮挡物反射过来的光,其亮度和颜色与我自身表面反射出去的光差不多”。这个假设打破了求解的递归。
      • 修正公式: 我们可以用一个简单的公式来“修正”原始的
        • 是表面的漫反射率 (Albedo)
        • 这个公式的效果是:表面反照率越高,对暗部提亮得就越多,这符合高反照率表面会产生更强烈的相互反射的物理直觉。
    2. 数据驱动模型 (Data-Driven Approach - Jimenez et al.):

      • 核心思想: 不去推导物理公式,而是“学习”它。
      • 流程:
        1. 离线使用高精度的路径追踪器,在各种场景中计算出带相互反射的“正确”遮挡值。
        2. 将这些海量数据作为一个“标准答案”。
        3. 拟合一个简单的多项式函数,让它能够根据输入的 和表面颜色,直接估算出接近“标准答案”的修正后遮蔽值
      • 这代表了一种更现代的思路:当物理模型过于复杂时,可以通过离线大数据+运行时简单拟合的方式来近似。

11.3.4 预计算环境光遮蔽 (Precomputed AO)

  • 核心观点: 对于场景中的静态物体,我们可以在游戏打包或关卡加载前,离线花费大量时间计算出高质量的AO,然后将结果**“烘焙” (Baking)** 到数据结构中,供运行时廉价使用。

  • 计算方法:

    • 蒙特卡洛光线追踪 (Monte Carlo Ray Tracing): 这是最常见也是最准确的方法。从物体表面的每个采样点(例如,纹理的每个像素)向其法线半球内发射大量随机光线,统计被遮挡的比例。
    • 优化: 重要性采样 (Importance Sampling): 与其在半球内均匀发射光线,不如**“偏向”**于朝法线方向发射更多光线。因为这些方向的余弦权重 更大,对最终结果的贡献也更大。这可以用更少的光线数量达到同等的质量,效率更高。
  • 存储方法:

    1. 光照贴图 (Lightmaps): 最常见的方式。将AO值存储在一张专门的2D纹理中。模型需要有第二套UV坐标来映射这张纹理。
    2. 顶点颜色 (Vertex Colors): 将AO值直接存储在网格的顶点数据中。优点是无需额外纹理和UV,但精度受限于顶点密度,无法表现精细的遮挡细节。
    3. 体积纹理 (Volume Textures): 将AO值存储在场景空间的一个3D网格中。
  • 处理动态物体与静态场景的交互:

    • 即使场景是静态的,角色等动态物体也应该被静态场景所遮蔽。
    • 环境光遮蔽体 (Ambient Occlusion Volumes): 在场景中预计算一个3D纹理(网格),存储空间中每个点的AO值。动态物体在移动时,可以实时采样这个体积纹理,获得由周围静态环境产生的遮蔽效果。
    • 环境光遮蔽场 (Ambient Occlusion Fields): 将一个静态物体对周围空间的遮蔽**“潜力”**烘焙到一个立方体贴图(Cubemap)中。动态物体可以查询这个场来计算自己受到的遮挡。
  • 游戏中的应用实例:

    • 《命运》(Destiny): 使用了高质量的预计算AO作为其动态日夜循环系统的间接光照基础。同一份烘焙好的AO数据可以在一天中的任何时间点复用,兼顾了质量与性能。
    • 《刺客信条》系列: 使用了一种称为世界AO (World AO) 的技术,通过从上向下渲染场景的深度图来快速计算大范围的遮蔽,并应用到所有物体上。

11.3.5 动态AO计算 (物体/世界空间)

  • 核心观点: 当物体是动态的,或者场景可以被破坏时,AO必须实时计算。这类方法直接在3D几何空间中进行计算,但通常需要对几何体进行简化和近似。

  • 主要方法:

    1. 基于符号距离场 (Signed Distance Field, SDF):
      • SDF 是一个3D网格,每个点存储到最近表面的距离(内部为负,外部为正)。
      • 近似计算: 沿着表面法线方向在SDF中采样几个点。根据采样的距离值来估算遮挡程度——距离越近,遮挡越强。
      • 锥形追踪 (Cone Tracing): 更高级的用法。从着色点向半球发射多个圆锥体(而非光线),通过在SDF中步进,根据SDF的距离值来判断并收缩圆锥,从而计算遮挡。
    2. 基于球体近似 + 球谐函数 (Spherical Harmonics, SH):
      • 思想: 将复杂的遮挡物近似为一组球体
      • 计算: 单个球体对一个点的遮挡可以被精确地表示为一组球谐函数 (SH) 系数。多个球体的遮挡可以通过对SH系数进行特定运算(近似为对数域的加法)来快速合并。
      • 特点: 速度快,但因为几何被简化为球体,所以只能产生柔和、模糊的遮蔽效果,无法表现锐利的细节。

11.3.6 屏幕空间方法 (Screen-Space Methods)

  • 核心观点: 这是目前最流行的实时动态AO技术。它完全抛弃了场景的3D几何信息,仅利用渲染后期的屏幕空间数据(主要是深度缓冲/Z-Buffer)来估算遮蔽。其性能开销只与屏幕分辨率有关,与场景复杂度无关。

  • 1. 屏幕空间环境光遮蔽 (SSAO - Crytek):

    • 算法流程:
      1. 对于屏幕上的每一个像素,获取其在世界空间中的位置P
      2. P点周围的球体内,随机生成一组采样点
      3. 将这些3D采样点投影回屏幕空间
      4. 比较每个投影点的深度值与该屏幕位置上深度缓冲中存储的真实场景深度
      5. 如果采样点的深度大于深度缓冲中的深度,说明它“藏”在了场景几何体的后面,被遮挡了。
      6. AO = 未被遮挡的采样点数 / 总采样点数
    • 优点: 概念简单,易于实现,速度快。
    • 缺点: 物理上不正确(忽略了法线和余弦项),容易产生噪点、光晕(halos)和条带(banding)等瑕疵。
  • 2. 基于视界的方法 (Horizon-Based AO, HBAO / GTAO):

    • 核心思想: 将深度缓冲看作一个从相机视角出发的高度场
    • 流程:
      1. 对于每个像素,在屏幕空间中向周围多个方向“步进”采样。
      2. 在每个方向上,找到能遮挡当前像素的**“地平线”**(即最高的那个邻近像素)。
      3. 通过所有方向上的地平线角度,积分计算出当前像素有多少比例的天空是可见的。
    • HBAO: 较早期的实现,做了一些简化,效果不错但物理精度不高。
    • GTAO (Ground-Truth AO): HBAO的改进版,致力于在数学上更严谨地匹配原始的AO积分公式(公式11.8),引入了余弦项,是目前公认的高质量SSAO方案之一。
  • 让SSAO变得实用的关键:时空滤波 (Spatio-Temporal Filtering)

    • 问题: 任何高质量的SSAO都需要大量采样点,但实时预算下每个像素可能只能负担几个甚至1个采样点,这会导致画面充满噪声
    • 解决方案:
      1. 空间滤波 (Spatial Filtering):
        • 使用抖动 (Jittering),让相邻像素使用不同的随机采样模式。
        • 对生成的带噪AO结果,使用一个智能的模糊——联合双边滤波 (Joint Bilateral Filter)。这种滤波器在模糊的同时,会参考深度和法线信息,避免跨越几何边缘进行模糊,从而保留细节。
      2. 时间滤波 (Temporal Filtering):
        • 核心: 在时间维度上累积采样。每一帧都使用一套新的随机采样模式。
        • 将前一帧的AO结果重投影 (reproject) 到当前帧的像素位置上。
        • 将当前帧计算出的(带噪的)AO结果与重投影过来的历史结果进行混合(通常是指数平均)
        • 这样,静止画面下的AO效果会随着时间(几帧内)迅速收敛到非常平滑和高质量的结果,极大地降低了单帧的计算开销。这是现代游戏引擎中SSAO的标配。

11.3.7 使用环境光遮蔽进行着色 (Shading with AO)

我们已经探索了多种方法来计算环境光遮挡因子。但是我们如何处理这个标量值呢?它如何适应我们的主要照明计算?

  • 核心观点: 环境光遮蔽 () 最正确的用法是作为间接漫反射光照 (Indirect Diffuse Lighting) 的一个衰减因子。它通过一个关键的近似,将复杂的可见性计算从光照积分中分离出来。

理论推导与关键近似

  1. 从完整的光照方程出发: 我们再次审视包含了可见性函数 的反射方程:

    这个积分很难直接求解,因为可见性函数 对于每个点 p 都是独一无二的。

  2. 针对漫反射的简化: 假设表面是理想漫反射 (Lambertian),我们可以将与方向无关的BRDF项 提出来。经过一系列数学变换(如书中所述),我们可以将方程重写为:

    这里的 是一个包含了可见性信息的、复杂的、归一化的滤波核。这个积分依然很难解。

  3. 做出关键近似 (The Key Approximation):

    • 核心思想: 我们用一个不包含可见性信息的、标准的余弦滤波核近似上面那个复杂的 核。
    • 换句话说,我们假装在计算光照积分时,所有方向都是可见的,就像在计算标准 Irradiance 一样。
    • 这个近似之所以“可行”,是因为我们已经将可见性信息**“因子分解”**到了积分外的 项中。
  4. 得到最终的实用公式: 经过这个近似,复杂的积分就变回了我们熟悉的 Irradiance (辐照度) 的定义。因此,最终的漫反射出射光 可以被极大地简化为:

    • 直观理解:

      最终的间接光照 = 表面颜色 × 接收到的总光照能量 × 可见度百分比

    这就是在实践中应用AO最常见的方式:计算场景的间接光照(例如,从光照探针或天空光采样),然后简单地将它乘以AO值。

AO 的使用准则 (Do's and Don'ts)

理解了上述近似后,AO的适用范围就变得非常清晰了:

  • 应该做 (DO):

    • ✔︎ 用AO来衰减低频的、柔和的间接光照。 例如:天空光、从Irradiance Map或Light Probe采样的环境光。对于这类平滑变化的光照,将可见性因子分离出来的近似效果很好。
  • 不应该做 (DON'T):

    • ❌ 不要用AO来代替直接光的阴影。 例如:太阳光、点光源。对于这种高频的、方向性极强的光源,可见性是“有或无”的二进制问题(即硬阴影)。用AO产生的柔和、无方向性的暗斑来模拟阴影,看起来会非常奇怪和不真实。直接光请务必使用Shadow Map等专门的阴影技术。
    • ❌ 避免将AO直接用于镜面反射。 对于镜面反射,BRDF与视角和光照方向都密切相关,不能简单地提出积分。使用单一的AO值去衰减复杂的镜面高光,会产生错误的结果。

一个简单的改进:使用弯曲法线 (Bent Normal)

  • 核心观点: 在对环境光(如天空盒、光照探针)进行采样时,使用弯曲法线 来代替几何法线 ,可以得到更准确的间接光照颜色。

  • 为什么有效?

    • 几何法线 只表示了表面的朝向。
    • 而弯曲法线 指向的是平均未被遮挡的方向
    • 去采样环境贴图,相当于“朝着能看得见天空的方向去采样”,自然能采样到更准确的入射光颜色,避免采样到被遮挡区域对应的(比如地面)颜色。这在一定程度上补偿了我们在光照积分中忽略可见性所带来的误差。

11.4 定向遮蔽 (Directional Occlusion)

  • 核心观点: 标准的环境光遮蔽 (AO) 只告诉我们一个点被遮挡了“多少”(一个标量 ),而定向遮蔽 (Directional Occlusion)则更进一步,告诉我们“从哪个方向”来的光被挡住了。这使得我们可以处理更复杂的光照环境,并产生更具方向感的柔和阴影。

  • 为什么需要定向信息?

    • 想象一个物体位于一个顶部是红色、侧面是蓝色的天空穹顶之下。一个被部分遮挡的点,如果只用AO,那么无论它能看到的是红色天空还是蓝色天空,它接收到的光都会被同样地调暗。
    • 如果我们有方向信息,就可以只对被遮挡方向(比如来自顶部的红色光)进行衰减,而保留可见方向(来自侧面的蓝色光)的贡献,从而得到物理上更准确、视觉上更丰富的结果。
  • 主要用途:

    • 大面积光源环境光照 (Environment Maps) 提供具有方向感的柔和阴影。
    • 作为传统阴影技术(如Shadow Maps)在远距离或细节层次(如凹凸贴图)上失效时的一种补充。

11.4.1 预计算定向遮蔽

和AO一样,对于静态场景,我们可以离线烘焙定向可见性信息。

  • 关键术语/表示方法:
    1. 视界映射 (Horizon Mapping): 最经典的方法。为每个点存储一组固定方向(如东、南、西、北等)上,能看到天空的最低角度(地平线)
    2. 环境光圈照明 (Ambient Aperture Lighting): 一种高度简化的表示法。将所有可见方向的复杂形状,近似为一个圆锥体。我们只需要存储这个圆锥的中心轴向张开角度即可。虽然不精确,但存储开销极小。
    3. 球面基函数 (Spherical Basis Functions): 最灵活和强大的方法。使用球谐函数 (Spherical Harmonics, SH) 或其他球面基底来表示整个半球的可见性函数 v(l)。阶数越高,能表示的可见性细节就越丰富。

11.4.2 定向遮蔽的动态计算

许多用于动态AO的技术,天然就可以扩展为提供定向信息。

  • 核心思想: 在计算AO的过程中,我们已经收集了方向信息,只是最后一步将它们平均成了一个标量。我们只需要保留这些中间的方向性数据即可。

  • 示例:

    • 基于SH的方法: 在计算时,保留SH系数的高阶(非零阶)部分,它们本身就编码了方向信息。
    • 锥形追踪 (Cone Tracing): 在为AO估算而追踪多个圆锥时,不将所有圆锥的遮挡结果平均,而是保留每个圆锥各自的遮挡值
    • 屏幕空间方法: 像GTAO这样的技术,在最终积分成一个AO值之前,已经计算出了各个方向上的视界角,这些原始数据就是我们需要的定向信息。也可以在屏幕空间中估算出环境光圈的圆锥参数。

11.4.3 使用定向遮蔽进行着色

这是本节最核心的部分:如何将我们得到的定向可见性函数 应用到最终的光照计算中。

  • 理论出发点: 我们的目标是求解这个带有可见性项的完整反射方程:

  • 分情况讨论:

    1. 用于点光源/方向光:

      • 积分退化为简单的乘法。
      • 着色 = 标准光照模型 × v(光照方向)
      • 也就是说,我们只需要查询光线方向 上的可见性值 ,然后乘以正常的光照结果即可。这可以作为一种廉价的阴影替代方案。
    2. 用于面光源 (Area Lights):

      • 问题转化为求解在光源立体角 范围内的积分:
      • 近似解法: 如果光源和可见性都可以被近似为圆锥,那么问题就变成了计算两个圆锥的相交部分的立体角。这个过程有解析解或高效的近似解。
    3. 用于环境光 (Environment Lighting):

      • 这是最复杂但也是最主要的应用场景。我们需要求解一个三重乘积积分 (Triple Product Integral),被积函数是三个函数的乘积:光照 L_i × 可见性 v × BRDF*cos
      • 核心技巧:降维打击
        • 直接求解三重积分非常昂贵。我们通过预先将其中两项相乘,将其简化为二重乘积积分
        • 思路A (预计算光照传输 - PRT): ∫ 光照 × (可见性 × cos项)
          • 预计算并存储 v(l) * (n·l) 的结果。这种方法被称为预计算光照传输 (Precomputed Radiance Transfer, PRT)
          • 缺点: 由于 cos 项依赖于法线 n,一旦预计算,就无法再响应法线贴图等细节变化。
        • 思路B (更常用): ∫ (光照 × cos项) × 可见性
          • 预计算 L_i(l) * (n·l),这其实就是辐照度环境贴图 (Irradiance Map)
          • 运行时,计算这个辐照度图和可见性函数的积分。
        • 球谐函数 (SH) 的威力: 如果二重乘积积分中的两个函数(如 (L_i × cos)v)都用SH表示,那么整个复杂的积分运算就简化为了两个SH系数向量的点积,计算效率极高!
    4. 用于光泽/镜面材质 (Glossy Materials):

      • 情况变得更复杂,因为BRDF本身也是方向相关的。
      • 核心近似技巧:
        1. 近似BRDF: 将复杂的BRDF波瓣 (lobe) 近似为一组简单的球面高斯 (Spherical Gaussian)
        2. 近似可见性: 假设在每个很窄的高斯波瓣范围内,可见性 是一个常数,可以直接提出积分。
        3. 预过滤环境图: 剩下的积分 ∫ 光照 × 球面高斯 可以被预先计算并存储在环境贴图的Mipmap层级中(更模糊的Mip层对应更宽的高斯波瓣)。
        4. 最终着色: 着色结果 ≈ Σ (高斯权重 × v(高斯中心方向) × 采样预过滤环境图)

11.5 漫反射全局光照 (Diffuse Global Illumination)

  • 核心观点: 这一节我们专注于模拟光线在场景中经过多次漫反射后到达人眼的效果。这是实现颜色溢出 (Color Bleeding)(例如,红地毯将白墙染上红色光晕)和整体环境氛围感的关键。

  • 光路表示法: 我们主要关心 L(D|S)*DE 这样的路径,即无论光线之前经历了什么,它被我们观察到的那一刻,是从一个漫反射表面射出的。


11.5.1 表面预照明 (Surface Prelighting) - 经典光照烘焙

  • 核心观点: 这是最传统、最广泛使用的全局光照技术,俗称**“烘焙光照” (Baking Lighting)。其核心思想是:离线使用高质量的渲染器(如路径追踪)计算好静态场景中所有静态光源**产生的完整光照(直接光+间接光),然后将结果存入一张特殊的纹理——光照贴图 (Lightmap) 中。

  • 关键概念:

    • 烘焙 (Baking): 一个昂贵的、在最终产品发布前的离线计算过程
    • 静态 vs 动态 (Static vs. Dynamic):
      • 静态物体 (Static Objects): 场景中固定不动的部分(如墙壁、地板)。它们在烘焙过程中既接收反弹间接光,是GI计算的贡献者接收者
      • 动态物体 (Dynamic Objects): 场景中会移动的部分(如角色、车辆)。它们不参与烘焙过程(即不产生间接光或阴影),但可以在运行时通过光照探针 (Light Probes) 等技术来采样接收周围的烘焙光照。
  • 局限性与“过时”的原因:

    • 这种最简单的方法烘焙的是辐照度 (Irradiance),即到达表面的总光能量。
    • 致命缺陷: Irradiance 是与特定的表面法线绑定的。这意味着,一旦烘焙完成,表面法线就固定了。因此,这种技术无法与法线贴图 (Normal Mapping) 兼容。如果你在运行时使用法线贴图去改变逐像素的法线,光照结果将是错误的,因为烘焙的光照是基于原始的、平滑的表面法线计算的。

11.5.2 定向表面预照明 (Directional Surface Prelighting) - 支持法线贴图的烘焙

  • 核心观点: 为了解决传统光照贴图不支持法线贴图的问题,我们不能只烘焙一个标量的Irradiance值,而是需要烘焙光照的方向性信息。这样,在运行时着色器就可以根据法线贴图提供的逐像素法线,动态地计算出正确的Irradi.ance。

  • 关键术语/表示方法 (如何存储方向光照):

    • 高质量方案:
      • 球谐函数 (Spherical Harmonics, SH): 最流行的高质量选择。它使用一组基函数来拟合整个球面(或半球)的光照分布。
        • 二阶SH (4个系数/通道): 效果尚可,但光照对比度较低,法线贴图细节不明显。
        • 三阶SH (9个系数/通道): 能保留更多光照细节,质量显著提升,但存储和计算开销也更大。
      • 球面高斯 (Spherical Gaussians): 在《教团:1886》中使用。用多个高斯波瓣来拟合入射光。能表示非常尖锐的光照,效果出众,但开销也最大。
    • 高性价比/游戏常用方案:
      • AHD (Ambient Hemisphere Distribution): 在《使命召唤》、《最后生还者》等游戏中广泛使用。用一组固定的方向(如6个)来表示半球光照,简单高效。
      • Crytek 表示法: 更加紧凑。只存储一个平均光照方向、一个平均光照颜色和一个方向性因子。内存占用极低。
      • 环境立方体/骰子 (Ambient Cubes/Dice): 在《半条命2》、《刺客信条》等游戏中应用。是SH的低成本替代品,避免了SH的振铃瑕疵。

11.5.3 预计算传输 (Precomputed Transfer, PRT)

  • 核心观点: PRT 是一种更高级的烘焙技术。它不直接烘焙光照结果,而是烘焙**“光线传输函数” (Transfer Function)**,即场景本身对光线的“响应方式”。这使得我们可以在保持实时GI效果的同时,动态地改变光源(如颜色、强度,甚至日夜循环)。

  • 核心思想 (显示器类比):

    1. 想象一个房间有红、绿、蓝三个显示器(光源)。
    2. 离线烘焙: 我们分别计算“只有红色显示器以单位亮度亮起时”的GI结果,并存下来。再分别计算绿色和蓝色的。这三份数据就是我们的传输函数
    3. 实时运行: 假设当前红色显示器亮度为0.5,绿色为0.8,蓝色为0.2。最终的GI结果就是一个简单的线性组合: 最终GI = 0.5 * (红色GI结果) + 0.8 * (绿色GI结果) + 0.2 * (蓝色GI结果)
  • PRT 的两种主要流派:

    1. 基于光源的PRT (Light-based PRT - Sloan et al.):

      • “光源”是远处的环境光,用球谐函数 (SH) 来表示。
      • 离线: 烘焙场景对每一个SH基函数的响应(比如烘焙9张光照贴图,对应三阶SH的9个基函数)。
      • 实时: 将当前的动态天空盒投影到SH,得到一组系数(如c_1c_9)。最终GI就是9张烘焙贴图根据这些系数的线性组合。
      • 问题: 如果要支持法线贴图,需要烘焙巨大的传输矩阵 (Transfer Matrix),数据量爆炸。通常需要配合PCA (主成分分析) 等压缩技术。
    2. 基于表面的PRT (Surface-to-Surface PRT - Enlighten):

      • 核心思想: 预计算表面面片 (patch) 之间的光能传输关系,类似于辐射度算法中的形状因子 (Form Factor)
      • 离线: 计算并存储一个巨大的矩阵,描述了从任意面片A发射的光有多少会到达面片B。
      • 实时:
        1. 计算所有面片接收到的直接光照
        2. 将这些受光面片视为新的“光源”,利用预计算好的传输矩阵,将光能**“传播”一步,得到第一次反弹**的间接光。
        3. (可选)可以将第一次反弹的结果作为新的光源,再传播一步,得到第二次反弹,如此迭代 (Progressive)
      • 这是著名中间件 Geomerics Enlighten 的核心原理。它允许动态的直接光照和局部光源,并实时更新它们产生的间接光反弹。

11.5.4 存储方法 (Storage Methods)

  • 核心观点: 无论我们烘焙的是最终光照还是光线传输函数,这些庞大的数据都必须以GPU友好的方式存储起来。最主流的方法有三种:光照贴图、顶点存储和体积存储(光照探针)。

  • 1. 光照贴图 (Lightmaps)

    • 定义: 存储预计算光照信息的2D纹理。这是最常用、最经典的方法。
    • 关键挑战: UVs
      • 唯一参数化 (Unique Parameterization): 与可以重复、平铺的反照率贴图不同,光照在物体表面每一点都是独特的。因此,模型的每个部分都必须在光照贴图上拥有一个独一无二、不重叠的UV空间。这个展开后的UV块被称为图表 (chart)壳 (shell)
      • 制作流程: 模型 → 切割成块 → 展开每个块 → 将所有图表打包到一张纹理上
    • 常见问题与解决方案:
      • 颜色溢出 (Color Bleeding): 在纹理采样时,由于双线性插值,一个chart边缘的像素可能会错误地采样到相邻chart的颜色。
        • 解决方案: 在打包chart时,在它们之间留出足够的**“排水沟” (gutter)** 或填充区域,确保插值范围不会越界。
      • 接缝 (Seams): 在UV被切开的地方,即使3D模型表面是连续的,光照贴图上的纹素也可能不连续,导致渲染时出现明显的光照接缝。
        • 解决方案: 使用更高级的参数化算法,保证UV展开后依然能对齐3D空间的像素网格,或者对烘焙后的贴图进行后处理,平滑接缝处的像素值。
      • Mipmaps: 光照贴图通常不使用Mipmaps,因为它们本身分辨率已经很低,而且生成Mipmap会加剧颜色溢出的问题。
  • 2. 顶点存储 (Vertex Storage)

    • 核心思想: 将光照信息(如SH系数)直接存储在模型的顶点数据中。
    • 为何很少使用:
      • 质量依赖网格密度: 光照细节受限于模型的布线,无法表现高频阴影。
      • 效率低下: 为了获得足够细节而增加顶点数,会大大增加内存和渲染开销。
      • 带宽问题: 从顶点着色器向像素着色器传递大量光照数据(例如9个SH系数)会产生“胖顶点”,这在现代GPU上效率不高。
  • 3. 体积存储 (Volumetric Storage) / 光照探针 (Light Probes)

    • 核心思想: 不将光照信息存储在物体表面,而是存储在空间中的一个网格里。
    • 巨大优势: 可以在空间中的任意位置查询光照,因此能非常自然地为动态物体提供高质量的间接光照,并保证静态和动态物体光照风格的统一。
    • 实现方式:
      • 规则网格 - 辐照度体积 (Irradiance Volumes):
        • 使用一个规则的3D纹理来存储光照。每个3D像素(体素)存储该空间点的定向光照信息(通常是二阶SH)。
        • 缺点: 内存开销与分辨率成立方关系,非常巨大。分辨率低时容易产生漏光 (Light Leaking),即光线穿透薄墙。
      • 非规则网格 - 光照探针 (Light Probes):
        • 在场景中的关键位置手动或自动放置一系列光照探针 (Light Probes),每个探针烘焙该点的光照信息。
        • 将这些离散的探针点连接成一个Delaunay四面体网格 (Delaunay tetrahedral mesh)
        • 查询: 运行时,先找到动态物体所在的四面体,然后根据其在四面体内的重心坐标 (barycentric coordinate),对四个顶点的探针数据进行插值,得到最终光照。
        • 优点: 探针可以根据需求灵活放置,比规则网格更高效。是现代游戏引擎(如Unity, Unreal)为主流的动态物体GI方案。

11.5.5 - 11.5.9 动态漫反射全局光照 (Dynamic Diffuse GI)

  • 核心观点: 当场景完全动态,无法进行任何预计算时,我们需要纯粹的实时GI解决方案。这些方法通常基于“两趟式”思想:第一趟收集光照信息,第二趟利用这些信息来计算间接光。

  • 1. 反射阴影贴图 (Reflective Shadow Maps, RSM)

    • 核心思想: 将直接光照的结果转化为大量的虚拟点光源 (Virtual Point Lights, VPLs) 来模拟一次光线反弹。
    • 流程:
      1. Pass 1 (光源视角): 渲染一张“超级”阴影贴图(RSM),除了深度,还存储被光照到的表面的世界坐标、法线、颜色等信息。
      2. Pass 2 (相机视角): 在为屏幕像素着色时,将RSM中的每一个像素都看作一个微小的VPL。随机从RSM中采样一部分VPLs,将它们的光照贡献累加起来,形成间接光。
    • 优点: 概念简单,可以产生不错的单次反弹效果。
    • 缺点: 没有间接光遮蔽,VPLs会“穿透”墙壁。需要采样海量VPLs才能避免闪烁,开销巨大。
    • 现代实践 (《神秘海域4》): 每帧只采样极少数VPLs,但通过时间滤波 (Temporal Filtering) 将多帧的结果累积起来,用时间换质量。
  • 2. 光照传播体积 (Light Propagation Volumes, LPV)

    • 核心思想: 将场景空间划分为一个规则的3D网格,然后模拟光能在网格的单元(cell)之间一格一格地传播
    • 流程:
      1. 注入 (Inject): 使用RSM,将直接光照信息“注入”到与几何体接触的网格单元中。
      2. 传播 (Propagate): 进行多次迭代。在每次迭代中,每个单元从其相邻的6个单元**“收集”**光照,并更新自身。光照就像墨水在水中一样扩散开来。
      3. 采样 (Sample): 物体从其所在的网格单元中采样最终的光照(通常是SH)。
    • 优点: 能模拟多次光线反弹。
    • 缺点: 漏光严重,光线很容易穿过薄墙。分辨率和传播速度难以平衡。
  • 3. 基于体素的方法 (Voxel-based Methods) - VXGI

    • 核心思想: 使用更精细的体素结构——稀疏体素八叉树 (Sparse Voxel Octree, SVO) 来同时表示场景的几何光照
    • 流程:
      1. 体素化 (Voxelize): 将当前帧的场景几何体实时转化为SVO。
      2. 注入 (Inject): 将直接光照注入到SVO的叶节点,并逐级向上(类似生成Mipmap)过滤光照信息。
      3. 收集 (Gather): 为每个屏幕像素,向场景中发射数个圆锥 (Cones)(而非光线),在SVO中进行锥形追踪 (Cone Tracing)。SVO的层级结构可以实现高效的、带有过滤的追踪查询。
    • 优点: 效果是这几种方法中最好的。由于追踪的是几何体素,天生就带有间接光遮蔽
    • 缺点: 体素化和锥形追踪的开销非常大,对性能要求极高。
  • 4. 屏幕空间方法 (Screen-Space Methods)

    • 核心思想: 像SSAO一样,尝试只用G-Buffer中的信息(深度、法线、颜色)来计算间接光。
    • 为何不流行: 屏幕能看到的信息极其有限。一个能产生强烈颜色溢出的巨大红色墙壁,只要移出屏幕,GI效果就会立刻消失,导致结果非常不稳定和不可预测。
    • 适用场景: 作为其他GI方案(如光照探针)的补充,用于增加小范围、近距离的接触反光细节。

我们继续深入全局光照的另一半——镜面全局光照。这部分内容专注于如何渲染那些依赖于视角、带有高光的反射效果,比如金属、玻璃和水面。这与我们之前讨论的漫反射GI在方法论上有很大不同。

11.6 镜面全局光照 (Specular Global Illumination)

  • 核心观点: 与宽广、模糊的漫反射不同,镜面反射 (Specular Reflection) 通常具有非常狭窄和高频的特征(即清晰的反射)。这意味着,我们需要一种能够精确编码高频细节的光照表示方法。幸运的是,这也意味着我们通常只需要关心反射方向上一个很小立体角内的入射光,而不是整个半球。

  • 漫反射GI方法的局限性:

    • 像SH、AHD这类低频的表示方法,虽然能产生“有颜色的高光”,但因为它们本质上是模糊的,无法渲染出清晰的反射。强行使用会导致高光变形、失真。
    • 即使是球形高斯,也需要非常多的波瓣才能模拟锐利的反射,这在性能上是不可接受的。

11.6.1 局部环境贴图 (Localized Environment Maps) - 反射探针

  • 核心观点: 这是目前实时渲染中最流行、最基础的镜面GI解决方案。其核心思想是在场景中的关键位置预先渲染和存储环境贴图 (Environment Maps),这些贴图被称为反射探针 (Reflection Probes)

  • 工作流程:

    1. 放置: 美术师在场景中手动放置反射探针。
    2. 烘焙: 在离线阶段,从每个探针的位置向周围渲染一张立方体贴图 (Cubemap),捕捉周围的环境。
    3. 采样: 运行时,一个有光泽的物体会找到离它最近的那个反射探针,并将其Cubemap作为环境光照来进行PBR计算。
  • 关键问题: 视差错误 (Parallax Error)

    • 问题: 标准环境贴图假设光照来自无限远处。当你移动时,反射的内容不会有任何变化,看起来就像“贴”在物体表面,缺乏立体感和空间感。

    • 解决方案: 视差校正 (Parallax Correction)

      • 核心思想: 我们不假设环境是无限远的,而是假设它被“固定”在一个有限大小的代理几何体 (Reflection Proxy) 上(通常是一个立方体或球体)。
      • 流程 (见下图):
        1. 从着色点 p 沿着反射方向 r 发射一条虚拟光线。
        2. 计算这条光线与反射代理的交点。
        3. 使用探针中心到这个交点的新方向 r' 去采样Cubemap。
      • 效果: 这就好像把无限远的环境贴图“拉近”并赋予了具体的形状和体积,当物体在代理几何体内部移动时,反射会产生正确的视差变化,真实感大大增强。
  • 优点与局限:

    • 优点: 易于实现,性能开销低,美术可控性强。
    • 局限:
      • 几何不匹配: 简单的代理体(如立方体)很少能完美匹配复杂的场景几何,会导致反射被拉伸或扭曲。
      • 漏光 (Light Leaking): 代理体无法表现场景的精细遮挡,可能导致一个封闭房间内的物体错误地反射出室外的天空。
      • 空间精度有限: 探针是离散放置的,当物体从一个探针的影响范围移动到另一个时,反射可能会发生跳变。

11.6.2 环境贴图的动态更新 (Dynamic Updates)

  • 核心观点: 在动态场景中(如日夜循环、可破坏环境),离线烘焙的反射探针会“过时”。因此,我们需要在**运行时动态地重新渲染(更新)**这些探针。

  • 性能挑战与策略:

    • 挑战: 实时渲染数百个Cubemap(每个需要渲染6个面)是不可想象的。
    • 策略:
      1. 时间切片 (Time Slicing): 不要在一帧内更新所有探针。每帧只更新固定数量的探针(甚至一个探针的一个面),将更新压力分散到多帧中。
      2. 优先级排序: 根据探针到相机的距离、上次更新时间等因素,优先更新那些对玩家最重要的探针。
      3. 快速预过滤: 离线使用的Cubemap Mipmap生成算法太慢。运行时需要使用基于重要性采样的快速卷积算法,用少量采样点来近似模糊效果。
      4. G-Buffer缓存: 如果场景大部分是静态的,可以离线烘焙探针的G-Buffer,运行时只重新计算光照,大大降低CPU开销。

11.6.3-11.6.4 其他高质量方法

  • 体素锥形追踪 (Voxel Cone Tracing - VXGI):

    • 与漫反射GI类似,但对于镜面反射,我们通常只需要沿着反射方向追踪一个很窄的圆锥即可。
    • 优点: 能提供比反射探针更精确的、逐像素的反射,并且自带遮挡。
    • 缺点: 性能开销巨大。对于接近纯镜面的反射,容易暴露底层体素的“方块感”。
  • 平面反射 (Planar Reflections):

    • 核心思想: 这是用于渲染完美平面(如镜子、平静水面)反射的**“黄金标准”**技术。
    • 流程:
      1. 将主相机的位置和朝向根据反射平面做一次镜像变换,得到一个“虚拟相机”。
      2. 从这个虚拟相机的位置,重新渲染一次场景到一张离屏贴图上。
      3. 在主相机视角下,将这张贴图作为纹理应用到反射平面上。
    • 优点: 效果完美,几何精确。
    • 缺点: 仅适用于单个平面,且相当于每帧要多渲染一次场景,开销很高。

11.6.5 屏幕空间反射 (Screen-Space Reflections, SSR)

  • 核心观点: 这是继反射探针之后,另一种极其重要的实时反射技术。它与SSAO师出同门,完全依赖屏幕空间的G-Buffer数据来实时追踪反射。

  • 核心算法 (光线步进 - Ray Marching):

    1. 对于屏幕上的一个像素,计算其反射方向 r
    2. 沿着 r 方向在世界空间中进行步进 (step)
    3. 每一步,将当前步进到的3D点投影回屏幕空间,并查询该位置的深度缓冲值。
    4. 如果当前点的深度大于深度缓冲中的深度,说明光线已经“穿入”到场景几何体之后,我们找到了一个交点
    5. 用交点处的屏幕颜色作为该像素的反射颜色。
  • 优化与演进:

    • Hi-Z Tracing: 使用分层的深度缓冲 (Hierarchical-Z) 来加速步进。在没有物体的空旷区域,可以在低分辨率的Mip层级上进行大步进;在靠近几何体的复杂区域,则在原始分辨率上进行精细步进。
    • 随机SSR (Stochastic SSR): 为了渲染粗糙/模糊的反射,而不是单一的镜面反射:
      1. 根据材质的粗糙度 (Roughness),在BRDF定义的波瓣内随机发射多条光线
      2. 由于性能限制,每像素每帧只能发射很少(甚至1条)光线,导致结果充满噪声
      3. 使用与SSAO完全相同的时空滤波 (Spatio-Temporal Filtering) 策略来消除噪声,用多帧信息累积出平滑的模糊反射效果。
  • SSR的致命缺陷与混合方案:

    • 缺陷: 所有信息都来自于屏幕
      • 物体的背面被遮挡的部分、以及屏幕外的任何东西,都不存在于G-Buffer中,因此绝对无法被SSR反射出来
    • 混合反射系统 (Hybrid Reflection System):
      • 现代游戏引擎的标准实践是将多种技术结合,形成一个鲁棒的、逐级回落 (fallback) 的系统:
        1. 首选SSR: 为近距离、屏幕内的物体提供高质量的逐像素反射。
        2. SSR失效时,回落到反射探针: 当SSR光线射出屏幕或找不到交点时,转而采样最近的反射探针,提供一个大致正确的环境反射。
        3. 探针也没有时,回落到全局天空盒: 作为最后的保底。
      • 这种混合方案结合了SSR的细节精度和反射探针的全局覆盖性,是当前实时镜面GI的最佳实践。

11.7 统一方法 (Unified Methods) - 实时路径追踪的曙光

  • 核心观点: 到目前为止,我们学习的所有实时GI技术(SSAO, Light Probes, SSR等)都是一个个独立的、带有各种妥协的“补丁”。它们虽然有效,但系统复杂,且在某些情况下会失效。图形学的终极目标是使用一个统一的、物理精确的算法——路径追踪 (Path Tracing) 来解决所有光照问题。在很长一段时间里,这被认为是“遥不可及的未来”,但现在,它正通过混合渲染的方式逐步成为现实。

混合渲染管线 (The Hybrid Rendering Pipeline)

  • 核心思想: 与其完全抛弃高效的光栅化硬件,不如**“扬长避短”**。我们继续使用光栅化来完成它最擅长的工作,同时用光线追踪来替代传统管线中最“丑陋”、最“hacky”的部分。

  • 分工合作:

    • ✔︎ 光栅化 (Rasterization) 负责:
      • 主可见性 (Primary Visibility): 高效地确定哪些物体在屏幕的哪个像素上,并生成G-Buffer(深度、法线、颜色等)。
    • ✔︎ 光线追踪 (Ray Tracing) 负责:
      • 精确的反射: 替代SSR和反射探针,解决屏幕外反射和视差错误问题。
      • 准确的阴影: 替代Shadow Map,解决锯齿、漏光和Peter-panning等问题。
      • 高质量的AO: 替代SSAO,解决屏幕空间信息的局限性。
      • 更复杂的GI: 模拟多次光线反弹。
  • 关键优势: 这种混合渲染管线 (Hybrid Rendering Pipeline) 结合了光栅化的速度和光线追踪的物理真实性,是当前乃至未来几年实时渲染发展的核心方向。

让实时光追成为现实的两大基石

纯粹的路径追踪之所以慢,是因为GPU的传统设计和海量的计算需求。两大技术的突破使其在实时领域成为可能:

  • 1. 硬件加速 (Hardware Acceleration):

    • 传统GPU的瓶颈: 线程发散 (Thread Divergence)
      • GPU通过锁步 (lock-step) 执行的线程组 (warp/wavefront) 来实现高效率。如果一个线程组内的线程执行了不同的代码路径(例如,两条光线击中了不同的物体),就会导致部分线程闲置,性能急剧下降。
      • 路径追踪是线程发散的噩梦,因为每条光线路径都是独一无二的。
    • 解决方案: 专用硬件 (Dedicated Hardware)
      • 现代GPU(如NVIDIA RTX系列的 RT Core)内置了专门用于加速光线与包围盒/三角形求交的硬件单元。
      • 这将光线追踪中最昂贵、最不适合并行计算的部分从通用计算单元中解放出来,使其效率提升了数个数量级。
  • 2. 降噪技术 (Denoising):

    • 问题: 即使有硬件加速,实时渲染的预算也只允许我们为每个像素发射极少数光线(通常是 1样本/像素 - 1 SPP)。这样的结果是一张充满噪点 (Noise)、完全不可用的图像。
    • 解决方案: 智能降噪器 (Denoiser)
      • 核心观点: 降噪器是让低采样率光追变得实用的**“魔法”**。
      • 它是一个后处理步骤,会利用G-Buffer中的信息(法线、深度、运动矢量)以及前几帧的历史数据(时间信息),对当前帧的噪点图进行智能模糊
      • 效果出色的降噪器(如NVIDIA的OptiX Denoiser, SVGF等)可以从1 SPP的输入,生成一张几乎无噪点、质量接近于数千SPP离线渲染结果的图像。

章节总结与补充阅读 (Chapter Summary & Further Reading)

至此,我们完成了对全局光照的探索之旅!

我们从最底层的物理原理渲染方程出发,了解了经典的离线算法辐射度路径追踪。随后,我们深入研究了实时渲染中为了追求性能而发明的各种聪明但充满妥协的近似方法:从简单的环境光遮蔽 (AO),到更精确的定向遮蔽,再到模拟光线反弹的漫反射GI(光照烘焙、PRT、动态VPL/LPV/VXGI)和镜面GI(反射探针、SSR)。

最终,我们看到了未来的方向:通过硬件加速降噪技术,这些零散的技术正被混合渲染管线中的实时光线追踪逐步统一,带领我们向着物理真实渲染的终极目标不断迈进。

为了更深入地学习,以下是本书推荐的一些宝贵资源:

  • 《Physically Based Rendering》 (PBRT): 被誉为图形学的“圣经”。如果你想深入理解所有离线、物理精确渲染算法的理论和实现细节,这本书是必读之选。
  • 《Ray Tracing in One Weekend》系列: 如果你想亲手从零开始写一个自己的路径追踪器,没有比这个系列更好的入门读物了。它非常实践,能让你快速建立对光线追踪的直观理解。
  • 《Advanced Global Illumination》: 深入探讨辐射度量学和渲染方程求解的学术著作。
  • 《Graphics Codex》: 一本包含大量图形学公式和算法的电子参考书,非常适合快速查阅。