体积与半透明渲染

引言:从表面到体积 (From Surfaces to Volumes)

欢迎来到体积渲染的世界!在此之前,我们大部分时间都在和物体的表面打交道,研究光如何在其表面反射(BRDF)。但真实世界充满了各种参与介质 (Participating Media)——雾、云、烟、水,甚至空气本身。这些介质的特点是,光线会在其内部发生复杂的相互作用。

本章的核心思想正如书中所说:“万物皆散射 (Everything is scattering)”。无论是坚硬的金属表面,还是缥缈的云朵,其视觉表现的本质都是光线与物质微粒的散射作用。本章将带你深入理解这一过程,并学会在实时应用中高效地模拟它。


14.1 光线散射理论 (Light Scattering Theory)

这是整个体积渲染领域的物理学基石。理解了这部分,后续所有的渲染技术都将变得有迹可循。

核心观点: 为了在计算机中模拟体积效果,我们必须首先建立一个数学模型,用以描述光线在穿过由无数微小粒子组成的介质时所经历的物理过程。我们将主要关注单次散射 (single scattering),这是一种在效果和性能之间取得良好平衡的简化模型,非常适合实时渲染。

14.1.1 参与介质材质 (Participating Media Material)

核心观点: 参与介质的“材质”并非由单一的颜色或纹理定义,而是由光线在介质中穿行时可能发生的四种基本事件,以及描述这些事件的关键物理参数所共同决定的。

想象一束光子射入一团烟雾中,它可能会遇到以下四种情况:

  1. 吸收 (Absorption): 光子被介质中的粒子“吃掉”,其能量转化为热能。这会削弱光线的强度并可能改变其颜色
  2. 外散射 (Out-scattering): 光子与粒子碰撞后,弹向了其他方向,离开了原来的路径。这同样会削弱光线沿原路径的强度
  3. 内散射 (In-scattering):其他方向来的光子,在介质中某点被散射后,恰好进入了我们观察的视线路径。这是我们能“看见”体积光、雾效等现象的根本原因,因为它为视线路径增加了亮度。
  4. 发射 (Emission): 介质自身发光,比如火焰或灼热的尘埃。这会直接向路径中增加光能

关键术语与公式:

为了量化这些事件,我们引入了几个核心系数:

  • 吸收系数 (Absorption Coefficient) : 描述了介质吸收光的能力有多强。值越大,光线被吸收得越快。
  • 散射系数 (Scattering Coefficient) : 描述了介质散射光的能力有多强。值越大,光线越容易被“弹开”。
  • 消光系数 (Extinction Coefficient) : 代表光线在介质中被削弱的总能力,是吸收和外散射的总和。这个概念非常重要,因为它统一了所有使光线减弱的因素。
  • 反照率 (Albedo) : 表示当光线与粒子发生交互时,被散射的概率有多大(相对于被吸收)。它决定了介质的“明亮”程度。
    • : 介质非常“亮”,几乎所有被交互的光都被散射,如云、雾、牛奶。
    • : 介质非常“暗”,大部分光都被吸收,如墨水、浓烟。

实践指导: 在引擎中,这些系数通常是vec3类型,分别对应RGB三个通道。通过调整不同颜色通道的,我们可以创造出各种颜色的体积效果。例如,红酒具有很高的红色通道吸收率,而散射率很低,因此呈现出半透明的红色。

14.1.2 透光率 (Transmittance)

核心观点: 透光率 () 是一个关键概念,它描述了光线在穿过一段距离的介质后,有多少比例的光能够“幸存”下来而没有被吸收或外散射。它是实现雾效和体积感的直接数学工具。

这个过程由著名的比尔-朗伯定律 (Beer-Lambert Law) 描述:

这里的 是自然对数的底,而 (tau) 是一个非常重要的无单位量:

  • 光学厚度 (Optical Depth) : 代表光线从点 的路径上,所遇到的粒子“总量”。它由消光系数 沿着路径的积分得到。 对于均匀介质( 为常数),公式可以简化为:

直观理解:

  • 光学厚度 越大(意味着介质越浓密或路径越长), 的值就越接近0,透光率越低,光线衰减越严重。
  • 如果介质是真空(),那么 ,光线100%通过,没有任何衰减。

视觉效果与应用:

透光率是实现多种关键视觉效果的基础:

  1. 雾和大气透视 (Fog & Atmospheric Perspective): 远处的物体看起来更暗、更模糊,就是因为物体表面反射的光在到达相机的漫长路径中,其透光率不断降低。
  2. 体积阴影 (Volumetric Shadows): 光源在照射到体积内的某一点之前,也需要穿过一段介质。这段路径上的透光率决定了该点能接收到多少初始光照,从而形成柔和的内阴影,即“体积自阴影”。
  3. 光线衰减: 任何穿过介质的光(无论是来自表面、还是来自内散射),在到达相机前都必须乘以相应的透光率。

总结一下:

到目前为止,我们已经建立了体积渲染的理论基础。我们知道,一个体积的“材质”由其吸收散射特性 () 定义,这两个特性共同决定了其消光能力 () 和反照率 ()。而光线穿过这个体积时会因消光而衰减,衰减的程度由透光率 () 描述,其核心是沿路径积分得到的光学厚度 ()

在上一部分,我们了解了定义体积材质的基本参数 () 以及光线穿过介质后的衰减规律(透光率 )。现在,我们将聚焦于体积渲染中“发光”的部分——内散射 (In-scattering),并深入探讨决定光线散射方向的关键因素——相位函数 (Phase Function)

14.1.3 散射事件 (Scattering Events)

核心观点: 内散射是体积能够被我们“看见”的根本原因。它计算的是在视线路径上的某一点,从各个光源方向散射进入我们眼睛的光线总量。这个计算过程本质上是一个光照模型,只不过作用于空间中的点,而非物体表面。

为了计算在空间中某点 的内散射光照 ,我们需要整合所有光源的贡献:

这个公式看起来复杂,但我们可以把它拆解成三个我们熟悉的部分,就像在做表面着色一样:

  1. - 相位函数 (Phase Function):

    • 作用: 类似于表面着色的BRDF,它决定了光线从光源方向 散射到观察方向 的能量分布。简单来说,就是**“光会朝哪个方向散射?”**。我们将在下一节详细讲解。
  2. - 光源自身属性:

    • 作用: 这是光源的颜色、强度以及随距离的衰减(如平方反比定律)。这部分与我们处理普通点光源或聚光灯时完全相同。
  3. - 可见性/阴影函数 (Visibility/Shadow Function):

    • 作用: 这是最关键也最特殊的部分。它判断从光源到点 的路径上,光线被阻挡了多少。在体积渲染中,遮挡来自两个方面:
    • 不透明物体阴影 (Opaque Shadow): 由场景中的普通物体(如角色、建筑)产生,通常使用Shadow Mapping等传统技术计算。
    • 体积阴影 (Volumetric Shadow): 这是体积自身产生的阴影。光线在到达点 之前,会穿过一段介质,并因消光而衰减。这个衰减量就是从光源到点 透光率 。这正是产生“体积感”和“丁达尔效应”的关键,如图中的兔子模型,有体积自阴影后,内部结构和厚度感立刻显现。

实现的核心技术:光线步进 (Ray Marching)

为了计算视线路径上的总光照(积分方程14.2)和每个点的体积阴影,我们必须对路径进行采样。光线步进就是实现这一目标的常用方法:我们将一条光线(无论是从相机出发的视线,还是从采样点到光源的阴影射线)分割成许多小步,在每一步的采样点上评估介质属性和光照,最后将所有步的结果累加起来,近似得到最终的积分结果。

  • 性能警示: 朴素的光线步进实现(在每个视线采样点,都再次向光源进行完整的步进)计算成本极高 (),因此在实时渲染中需要大量优化。

直观理解:散射颜色 vs. 透射颜色

介质最终呈现的颜色是内散射光颜色透射光颜色之间竞争的结果。

  • 短路径(介质稀薄): 内散射占主导。散射系数 越高的颜色通道,散射的光越多。例如,大气层的 在蓝色通道最高,所以我们看到的天空是蓝色的
  • 长路径(介质浓厚): 透光率 占主导。由于透光率是指数衰减 (),它比线性累加的内散射下降得快得多。消光系数 越低的颜色通道,能“幸存”得越远。大气层的 在红色通道最低,因此阳光穿过极厚的大气层后(日出日落),剩下的主要是红光,我们看到的太阳和晚霞是红色的

14.1.4 相位函数 (Phase Function)

核心观点: 相位函数 是一个数学模型,用以描述光线在与介质中的粒子碰撞后,其能量在不同方向上的概率分布。它决定了体积光照的“形状”和方向性,例如光晕的大小、是向前散射还是向后散射。

这个函数的输入是入射光方向和出射光方向的夹角 。为了保证能量守恒,它在所有方向(一个球面)上的积分必须为1。

根据介质中粒子尺寸相对于光波长的不同,散射行为可分为三类:

1. 瑞利散射 (Rayleigh Scattering)

  • 适用场景: 粒子尺寸远小于光波长 (),典型代表是空气分子
  • 核心特性:
    • 强烈的波长依赖性: 散射强度与波长的四次方成反比 ()。这意味着蓝光(波长短)比红光(波长长)更容易被散射。这是天空呈现蓝色的根本物理原因。
    • 对称散射: 向前和向后散射的能量几乎相同,侧向最弱。
  • 公式:

2. 米氏散射 (Mie Scattering)

  • 适用场景: 粒子尺寸与光波长大致相当 (),如雾、霾、尘埃、云中水滴
  • 核心特性:
    • 与波长无关: 散射对所有颜色的光基本一视同仁,所以雾和云通常是白色或灰色的。
    • 强烈的前向散射: 大部分光线会在碰撞后继续沿着原来的方向前进,形成一个明亮的前向散射波瓣。这就是为什么在有雾的天气里直视车灯会感到刺眼,以及太阳在云层后会形成明亮的光晕或“银边”。
  • 常用模型:Henyey-Greenstein (HG) 相位函数
    • 这是一个灵活且计算高效的近似模型,在图形学中被广泛用于模拟米氏散射。
    • 公式:
    • 控制参数 :
      • : 前向散射 (forward scattering),g 越接近1,前向散射越强越集中。
      • : 后向散射 (backward scattering)。
      • : 各向同性散射 (isotropic scattering),光向所有方向均匀散射,其相位函数为最简单的
  • 性能优化:Schlick 近似
    • 这是一个比HG函数更简单的近似,避免了复杂的幂运算,计算速度更快,效果非常接近,是实时渲染中的一个绝佳选择。

3. 几何散射 (Geometric Scattering)

  • 适用场景: 粒子尺寸远大于光波长 (),如雨滴、冰晶
  • 核心特性: 此时光的行为更接近于宏观几何光学,会在粒子内外发生复杂的折射和反射。这能产生非常复杂的散射现象,例如彩虹。在实时渲染中,通常会使用更简化的模型或预计算查找表来模拟。

14.2 特殊的体渲染 (Specialized Volumetric Rendering)

核心观点: 在追求完全物理真实的通用体渲染方案之外,存在一类针对特定场景、高度优化的渲染技术。这些方法通常被看作是巧妙的“视觉戏法”,它们在计算开销和视觉效果之间取得了极佳的平衡,非常适合用于渲染大规模的雾效简单的体积光

14.2.1 大规模雾 (Large-Scale Fog)

核心观点: 大规模雾是一种经典的、基于深度的视觉效果,它通过模拟大气对光线的衰减来增强场景的氛围感、深度感,并且可以作为一种有效的性能优化手段

雾效的三个主要作用:

  1. 营造氛围: 增加场景的真实感和戏剧性,烘托出特定的情绪。
  2. 增强深度暗示: 帮助玩家判断物体的远近,理解广阔场景的空间布局。
  3. 遮挡剔除: 远处的物体会被浓雾完全遮挡,此时引擎可以安全地跳过对这些物体的渲染,提升帧率。

基本原理:颜色混合

雾效的本质是一个简单的颜色混合(lerp)过程。最终像素的颜色 是由物体原始颜色 和雾的颜色 混合而成:

这里的关键是雾效因子 ,它代表了物体的可见度(或者说,是光的透光率)。 表示完全清晰, 表示完全被雾遮挡。

如何计算雾效因子 (f)

计算 的方法主要有两种,代表了从简单直观到物理近似的演进:

  1. 线性雾 (Linear Fog):

    • 原理: 雾的浓度随与摄像机的线性深度 线性增加。通过设定一个起始距离 和一个结束距离 来控制。
    • 公式:
    • 优点: 控制简单直观,参数易于调节。
    • 缺点: 不符合物理规律。
  2. 指数雾 (Exponential Fog):

    • 原理: 这是一种更物理正确的方法,直接应用了我们之前学到的比尔-朗伯定律 (Beer-Lambert Law)
    • 公式:
    • 参数 是一个用户定义的雾密度(density)参数。
    • 优点: 效果更自然,符合真实世界中光线衰减的规律。
    • 实现注意: 现代渲染管线中,深度缓冲中的值是非线性的。在像素着色器中应用雾效时,必须先将非线性的深度值重构回线性的视图空间深度 ,才能正确计算雾效。

实用雾效变体

  • 高度雾 (Height Fog): 将雾模拟成一个有特定高度和厚度的“雾层”(Slab),非常适合制作山谷间的晨雾或贴地面的薄雾。计算时,需要求解视线在这层雾中穿过的距离。
  • 局部雾 (Local Fog): 为了在特定区域(如洞穴、墓地)创建雾效,可以使用简单的几何体(如球体、立方体)作为雾的容器。渲染时,计算视线在该几何体内部穿行的距离,并只在这段距离上应用雾效。
  • 水下效果 (Underwater Effects): 水体本质上就是一种参与介质。因此,水下的模糊和颜色衰减效果可以被完美地建模为一种特殊的、颜色和密度固定的体积雾。

14.2.2 简单的体积光 (Simple Volumetric Light)

核心观点: 完整的体积光照(尤其是“耶稣光”/“上帝光”)模拟成本高昂。因此,在实时渲染中,我们常常使用一系列高效的近似方法(“作弊手段”)来模拟这种效果。

常用技术概览

  1. 纹理面片法 (Splatting/Billboards):

    • 原理: 在光路上放置一系列面向摄像机的半透明面片(粒子),面片上贴有光束的纹理。
    • 优点: 实现简单。
    • 缺点: 在摄像机穿过或靠近时容易露馅;大量半透明面片的叠加会造成严重的Overdraw,消耗大量像素填充率和显存带宽。
  2. 解析解法 (Analytic Solutions):

    • 原理:介质均匀、无遮挡等理想化假设下,光线的单次散射积分可以被数学方法解出一个封闭形式的解(解析解),无需进行昂贵的光线步进。
    • 优点: 计算速度极快,可以写成一个非常简短的着色器函数。
    • 缺点: 假设条件太苛刻,无法处理复杂的介质和阴影遮挡。
  3. 泛光/辉光法 (Bloom/Glow):

    • 原理: 一种屏幕空间的后处理技术。通过模糊场景中的高亮区域,然后将其叠加回原图,模拟光线“溢出”的效果。
    • 优点: 性能开销小,能有效增强画面的“电影感”。
    • 缺点: 并非真实的体积散射,更像是模拟镜头光晕,无法产生有方向性的光束。
  4. 屏幕空间光束/耶稣光 (Screen-Space Light Shafts / Crepuscular Rays):

    • 原理: 这是目前最流行和高效的“假”体积光技术,同样是一种后处理效果。
    • 实现步骤:
      1. 遮挡源识别: 将光源(如太阳)和场景中会遮挡光线的物体(仅保留能产生光束的像素)渲染到一个低分辨率的纹理中。
      2. 径向模糊 (Radial Blur): 以光源在屏幕上的位置为中心,对上一步得到的纹理进行多次定向模糊。模糊的方向是从中心向外发散,从而“拉”出光束。
      3. 混合: 将模糊后的光束纹理,以**加法混合(Additive Blending)**的方式叠回到原始的场景画面上。
    • 优点: 效果令人信服,性能开销可控,是现代游戏中实现动态“耶稣光”的主流方法。
    • 缺点: 纯屏幕空间技术,当光源在屏幕外时无法产生光束。

14.3 通用的体渲染 (General Volumetric Rendering)

核心观点: 通用体渲染的目标是,放弃上一节中的各种“特例”和“戏法”,转而采用一种更基于物理、更统一的框架来模拟光与介质的相互作用。这种方法能够处理空间中任意分布的、非均匀(异质)的参与介质,并能正确地与动态光源、阴影以及场景中的其他透明或不透明物体进行交互。

14.3.1 体积数据可视化 (Volume Data Visualization)

核心观点: 在深入游戏渲染之前,我们先从一个相关领域——科学与医学可视化——中学习基础技术。这个领域的核心任务是将离散的三维标量场数据(体素),如CT或MRI扫描结果,转化为直观的图像。

虽然目标不同,但其核心渲染技术——如何从一堆数据点中“看”到一个立体的、半透明的物体——对游戏渲染极具启发意义。

核心技术1:视点对齐切片 (View-Aligned Slicing)

  • 原理: 想象一下把一个西瓜切成无数片非常薄的薄片。视点对齐切片就是这个思路。我们沿着垂直于摄像机视线的方向,生成一系列等间距的半透明平面(切片)。
  • 渲染流程: 从后往前渲染这些切片,每个切片对它所在位置的体积数据进行采样,获得颜色和透明度,然后将结果混合(blend)到之前的画面上。当切片足够多时,它们在视觉上就融合成了一个连续的体积。

核心技术2:传递函数 (Transfer Function)

  • 问题: 体素数据本身通常只是一个单一的数值(如密度)。我们如何决定骨骼是白色不透明的,而软组织是粉色半透明的?
  • 解决方案: 传递函数就是一个“染色”和“定义透明度”的工具,它本质上是一个查找表(LUT)
    • 一维传递函数 (1D Transfer Function):
      • 映射关系: 密度值 -> (颜色, 透明度)
      • 局限性: 无法很好地区分密度相近但材质不同的边界。例如,如果空气和某个组织的密度值很接近,它们可能会被赋予相似的颜色。
    • 二维传递函数 (2D Transfer Function):
      • 映射关系: (密度值, 梯度大小) -> (颜色, 透明度)
      • 巨大优势: 梯度(Gradient)代表了数据变化的剧烈程度。在不同材质的边界处,密度值会发生突变,因此梯度值会很大。利用这个特性,我们可以精确地为不同材质的边界和内部区域赋予不同的外观,效果远超一维函数。

高级技术:半角切片 (Half-Angle Slicing)

  • 原理: 一种更高级的切片技术,它不完全对齐视点,而是将切片朝向设置在视线方向和光线方向的中间
  • 优点: 这种巧妙的设置使得在从后往前累积颜色的同时,可以更方便地计算光照和体积阴影,能够模拟出更高质量的次表面散射效果。

14.3.2 参与介质渲染 (Participating Media Rendering)

这是本节的重中之重,直接关系到游戏引擎中的动态雾、烟、云和体积光的实现。

核心观点: 现代游戏引擎普遍采用一种基于视锥体的体素化 (Frustum-Based Voxelization)方案,也常被称为Froxel体渲染。其核心思想是将摄像机的视锥体离散化成一个三维网格(体素/Froxel),然后在这个低分辨率的网格上计算复杂的体积光照,最后再将结果应用到高分辨率的全屏画面上。

这个流程可以分解为以下几个关键步骤:

  1. 步骤一:材质体素化 (Voxelize Material)

    • 目标: 在我们划分好的低分辨率视锥体网格中,填入每个体素(Froxel)的物理属性。
    • 操作: 创建一个3D纹理(可以看作一个三维的G-Buffer),为每个Froxel存储其吸收系数 、散射系数 和相位函数参数 。这些信息可以来自场景中艺术家放置的雾效盒子、粒子系统或者全局设定。
  2. 步骤二:光照注入 (Inject Lighting)

    • 目标: 计算每个Froxel因为内散射而“发出的光”。
    • 操作: 遍历所有光源(太阳、点光源等),对每一个被光照亮的Froxel,根据其材质属性、相位函数以及来自光源的阴影(包括普通阴影贴图和体积阴影),计算出该Froxel的内散射光照
  3. 步骤三:散射积分与累积 (Integrate & Accumulate)

    • 目标: 模拟光线从远到近穿过整个视锥体网格,并累积光照、计算衰减。
    • 操作: 从视锥体最远的切片(slice)开始,逐层向摄像机前进。对于每一层的Froxel,它的最终光照 = 前一层传递过来的光照 + 本层自身的内散射光照。同时,计算并累积透光率
    • 优化: 这个累积过程有一个更精确的解析解,可以避免一些数值误差: 其中, 是从前一层()传递过来的光照和透光率。
  4. 步骤四:应用到主场景 (Composite)

    • 目标: 将我们计算出的低分辨率体积光效应用到全分辨率的场景中。
    • 操作: 在渲染不透明物体之后,根据每个像素的世界坐标,到这个最终的体积光3D纹理中进行采样,获取该点的累积散射光 总透光率 。最终的像素颜色为: L_{\text{final}} = T_r \cdot L_{\text{opaque_surface}} + L_{\text{scat}}

关键组成部分:体积阴影 (Volumetric Shadowing)

  • 重要性: 如果没有体积阴影,浓雾或烟雾会显得平坦、明亮,缺乏层次和真实感。体积阴影是提供深度和体积感的关键视觉线索。
  • 统一方案: 为了让参与介质(如烟雾、粒子)能对自己、对其他介质、以及对场景物体投射柔和的阴影,可以采用一个统一的解决方案:
    1. 将所有能产生遮挡的参与介质(粒子、雾盒子等)的消光系数 体素化到一个或多个围绕摄像机的级联3D纹理中(称为消光体积 Extinction Volume)。
    2. 步骤二(光照注入)中,当计算每个Froxel的光照时,从光源出发到该Froxel的路径需要在这个消光体积中进行光线步进,以计算其透光率,从而得到正确的体积阴影。

总结: 基于Froxel的通用体渲染方法是一个强大而统一的框架。它虽然在低分辨率网格上进行计算,但通过时间抗锯齿(TAA)等后处理技术可以有效隐藏瑕疵,最终以可控的性能开销,实现了与场景无缝融合的高质量动态体积效果。

14.4 天空渲染 (Sky Rendering)

核心观点: 在现代实时应用中,天空不再是一个简单的贴图(Skybox),而是一个动态的、基于物理的参与介质。精确地渲染大气和云,对于营造真实感、暗示一天中的时间变化以及增强大规模场景的深度感至关重要。

14.4.1 天空和空气透视 (Sky and Aerial Perspective)

核心观点: 天空的视觉外观主要由太阳光与大气中两种不同尺寸的粒子相互作用决定。我们的渲染模型必须同时捕捉这两种散射现象。

天空渲染的物理基础

  1. 瑞利散射 (Rayleigh Scattering):

    • 成因: 太阳光与尺寸远小于光波长的空气分子发生散射。
    • 特性: 散射强度与波长四次方成反比 (),即蓝光比红光更容易被散射
    • 视觉效果: 构成了天空的基本蓝色;在日出日落时,阳光穿过更厚的大气层,大部分蓝光被散射掉,只有红光能到达人眼,形成红色的天空。
  2. 米氏散射 (Mie Scattering):

    • 成因: 太阳光与尺寸约等于光波长的悬浮颗粒(如水汽、尘埃、污染物)发生散射。
    • 特性: 散射与波长无关,具有强烈的前向散射特性。
    • 视觉效果: 在太阳周围形成一个明亮的白色光晕(Halo);当大气浑浊度(Turbidity)高时,会产生灰蒙蒙的薄雾效果。

渲染技术演进与现代方案

过去的实时天空渲染方法,如简单的解析模型(Analytic Models),虽然速度快,但通常局限于地面视角,且缺乏艺术创作的灵活性。现代引擎普遍采用一种更强大、更灵活的方案:

核心技术:预计算大气散射 (Precomputed Atmospheric Scattering)

  • 原理: 大气散射的物理过程涉及复杂的路径积分,实时逐像素计算是不现实的。因此,我们将这个积分过程离线预计算,并将结果存储在查找表 (Look-Up Tables, LUTs) 中。在运行时,着色器只需根据当前参数进行几次纹理采样,即可重建出高质量的大气效果。
  • 参数化: 这个LUT通常是三维或四维的,其坐标轴(参数)包括:
    1. 观察点高度 (Altitude)
    2. 观察方向与天顶夹角 (View Zenith Angle)
    3. 太阳方向与天顶夹角 (Sun Zenith Angle)
    4. (可选)观察方向与太阳方向的相对方位角
  • 巨大优势:
    • 任意视点: 支持从地面到外太空的任何视角,无缝切换。
    • 动态与灵活: 艺术家可以调整底层物理参数(如大气密度、颜色、粒子浓度)来创造出外星星球的天空或特定的艺术风格,并实时更新LUT。
    • 性能高效: 将昂贵的积分计算转移到预计算阶段,运行时开销极低。
    • 集成多重散射: 预计算方法可以迭代地计算更高阶的散射,使天空光照更饱满、更真实。

14.4.2 云 (Clouds)

核心观点: 动态体积云是现代开放世界游戏的标配。其实时渲染的核心在于,使用程序化噪声来构建云的复杂形态,并通过光线步进 (Ray Marching) 在这个虚拟的介质中进行高效的光照和阴影计算。

云的物理特性

云是由水滴或冰晶组成,其物理特性表现为高反照率(几乎是纯白色散射,)和复杂的前向散射相位函数。这意味着光线很难直接穿透厚云,且会在其内部发生大量的多重散射,这正是云看起来明亮、蓬松、洁白的关键原因。

现代云渲染流程 (基于光线步进)

  1. 云的塑形 - 程序化噪声 (Procedural Noise):

    • 我们不需要手动建模云,而是通过数学函数在空间中生成云的密度。Perlin噪声Worley噪声的组合被证明能非常有效地模拟出从蓬松的积云到棉花状的各种云朵形态和细节。这些噪声可以组合成一个3D纹理或在着色器中实时计算。
  2. 云的光照与阴影 (Lighting and Shadowing):

    • 主光照: 从摄像机出发,沿视线方向进行光线步进,在路径上的每个采样点,对噪声场进行采样以获得云的密度。然后,计算从太阳到该采样点的光线贡献(考虑单次散射和相位函数)。
    • 体积阴影: 为了计算一个采样点是否在阴影中,需要从该点向太阳方向进行二次光线步进,累积路径上的云密度来计算透光率。这是一个巨大的性能开销。
    • 阴影优化: 为避免二次光线步进,可以预先将整个云层的透光率从太阳视角“烘焙”到一个映射中(如Transmittance Function Map)。
  3. 性能优化 - 低分辨率渲染与时间累积:

    • 核心思路: 全分辨率光线步进非常昂贵。我们可以在一个低得多的分辨率(如1/4或1/8屏幕分辨率)下进行云的渲染,然后通过时间重投影 (Temporal Reprojection) 技术,将前几帧的结果与当前帧结合起来,并利用TAA等抗锯齿方法,最终重建出一幅清晰、稳定且细节丰富的图像。

外观细节与视觉一致性

  1. 多重散射近似 (Multiple Scattering Approximation):

    • 问题: 只考虑单次散射的云会显得很暗,像烟雾,无法体现其明亮洁白的外观。
    • 实时方案: 采用一种多级/八度 (multi-octave) 的近似方法。它通过多次(例如3-4次)迭代计算单次散射,每次迭代都略微修改散射和消光系数(让光能穿透得更深),并将结果累加。这是一种在物理正确性和艺术可控性之间取得极佳平衡的技巧。
  2. 相位函数近似 (Phase Function Approximation):

    • 云的真实相位函数非常复杂。在实时渲染中,常用两个Henyey-Greenstein函数的混合来模拟,一个模拟尖锐的前向散射波瓣(产生“银边效应”),另一个模拟更宽的散射,为艺术家提供了足够的控制力。
  3. 云与大气的相互作用 (Cloud-Atmosphere Interaction):

    • 视觉统一的关键:
      • 大气影响云: 云本身也处于大气之中,因此云的颜色需要叠加上空气透视的效果。远处的云应该比近处的云更蓝、更模糊。
      • 云影响大气: 大片的云会遮挡太阳,因此云下方的天空光和空气透视应该变暗,营造出阴天的效果。

通过整合这些技术,现代游戏引擎能够渲染出从晴空万里到乌云压境的各种动态天气,并与一天的时间变化无缝衔接,极大地提升了虚拟世界的沉浸感。


我们来攻克第14章中关于固体半透明表面的部分。这部分内容与之前的体积雾、云渲染不同,它更专注于玻璃、水、水晶这类有明确界面的材质,其核心在于模拟光线如何穿过(Transmit)弯曲(Refract)并最终在其他表面上聚焦(Caustics)


14.5 半透明表面 (Translucent Surfaces)

核心观点: 本节我们讨论的“半透明”材质,特指那些像玻璃、水和宝石一样,具有高吸收系数和低散射系数的物体。光线可以在其内部穿行,但不会像在雾或牛奶中那样被剧烈地散射开。我们将重点关注如何处理它们的透光折射以及由此产生的焦散效果。

关键术语辨析

在开始之前,清晰地区分以下概念至关重要:

  • Transparency (透明): 光线可以穿过,不发生明显散射。我们能清晰地看到物体背后的景象(如窗户玻璃)。
  • Translucency (半透明): 光线可以穿过,但会发生明显的内部散射。我们无法清晰地看透物体(如毛玻璃、玉石)。
  • Coverage / Opacity (覆盖率/不透明度): 描述一个物体在宏观上“遮挡”了多少背景,通常由 alpha 值表示。它更像是一个“蒙版”或“纱窗”的概念。
  • Transmittance (透光率): 描述光线在微观上穿过材质后,有多少比例的能量“幸存”了下来,它是一个受材质颜色和厚度影响的物理量。

14.5.1 覆盖率和透光率 (Coverage and Transmittance)

核心观点: 在渲染中,我们必须区分基于覆盖率的混合(Alpha Blending)基于透光率的物理过滤。前者是简单的“遮挡”,后者是物理上的“滤色”。

混合公式的演进

  1. 纯覆盖率混合 (Alpha Blending):

    • 最终色 = α * 物体色 + (1-α) * 背景色
    • 这模拟的是像铁丝网或薄纱这样的物体。
  2. 纯透光率混合 (Transmissive Blending):

    • 最终色 = 物体表面反射色 + 透光率 * 背景色
    • 这模拟的是纯净的有色玻璃,背景光被玻璃“过滤”了一层颜色。注意,这里的透光率 是一个RGB向量。
  3. 统一混合模型:

    • 将两者结合,可以模拟带有覆盖率的半透明材质(例如一个布满孔洞的彩色塑料板)。

计算透光率

透光率的计算依然遵循比尔-朗伯定律

  • 是材质的消光系数,决定了滤色的强度和颜色。
  • 是光线在介质内部穿过的距离

给美术同学的实用技巧: 直接调整物理参数 非常不直观。我们可以提供更友好的参数:让美术师指定一个目标颜色 和一个标准厚度 ,然后通过以下公式反推出物理正确的

如何计算穿透距离

  • 薄壳物体 (Thin-shelled): 对于窗玻璃这样的薄片,距离 可以近似为 厚度 t / (n·v),即考虑了视角倾斜带来的路径增长。
  • 实体物体 (Solid):
    • 简单凸面体: 先渲染背面,将其深度写入纹理;再渲染正面,通过当前深度与纹理中的背面深度之差计算出距离
    • 复杂凹面体: 物体可能有多层表面。需要使用深度剥离 (Depth Peeling) 或类似的OIT (Order-Independent Transparency) 技术,逐层计算穿透距离并正确混合。

14.5.2 折射 (Refraction)

核心观点: 折射是光线穿过不同介质界面时发生的路径弯曲现象。在实时渲染中,我们通常使用屏幕空间技术来高效地模拟这种视觉扭曲效果。

核心技术:屏幕空间折射 (Screen-Space Refraction)

这是现代游戏中实现折射效果的主流方法,因为它避免了传统环境贴图法的静态和高成本问题。

  • 渲染流程:
    1. 场景绘制: 将不包含折射物体的完整场景渲染到一张纹理中(Scene Color Texture)。
    2. 折射体绘制: 渲染折射物体(如玻璃杯)。在其像素着色器中: a. 计算标准的屏幕坐标(UV)。 b. 根据该像素的法线、视角等信息,计算一个扰动偏移量。 c. 用 标准UV + 扰动偏移量 作为新的采样坐标,去采样第一步的场景纹理。
    3. 将采样到的“扭曲后”的背景色与玻璃自身的反射、透光等结合,得到最终颜色。
  • 局限性: 纯屏幕空间技术,无法折射出屏幕外或被物体自身遮挡的景象。

模拟粗糙表面的折射 (Frosted Glass)

对于毛玻璃、磨砂玻璃等粗糙表面,光线会向多个方向散射,导致背景模糊。

  • 优雅的解决方案:基于粗糙度采样Mipmap (Roughness-based Mipmap Sampling)
    • 原理: 场景颜色纹理通常会生成一系列从高到低分辨率的Mipmap层级。越高的层级(分辨率越低)图像越模糊。
    • 实现: 在渲染粗糙折射表面时,直接将材质的**粗糙度(Roughness)**值映射到一个合适的Mipmap层级。表面越粗糙,就从越模糊的Mipmap层采样背景,完美地、高效地模拟出磨砂效果。

14.5.3 焦散和阴影 (Caustics and Shadows)

核心观点: 焦散是光线被曲面反射或折射后,在另一表面上汇聚形成的高亮图案。由于其物理过程复杂,实时渲染通常采用各种高效的**近似方法(“作弊手段”)**来模拟。

焦散 (Caustics) 的实时模拟

  1. 动画纹理 / 光照贴图 (Animated Textures / Light Maps):

    • 原理: 最经典、最常用的游戏技术。预先制作一张或多张循环播放的焦散图案纹理,在运行时像投影一样将其叠加到水底、墙壁等表面上。
    • 优点: 性能开销极低,效果可控。
    • 缺点: 非物理模拟,与水面真实动态不完全匹配。
  2. 图像空间光子溅射 (Image-Space Photon Splatting):

    • 原理: 一种更高级的动态方法。可以看作是简化的实时光子映射。
      1. 从光源视角,计算光线穿过折射体后的新位置和方向(“虚拟光子”)。
      2. 将这些“光子”作为发光的点或小面片(Splat),“溅射”回主场景中,形成高亮区域。
    • 优点: 能够根据物体和光源的动态变化生成正确的焦散图案。
    • 缺点: 实现复杂,性能开销相对较高。
  3. 焦散阴影 (Caustic Shadows):

    • 焦散不仅有亮斑,也有因光线被折射走而形成的暗区。一个简单的近似方法是:根据透明表面的法线方向来调整其透射的阴影。例如,法线弯曲剧烈的地方,光线偏折更严重,其投射的阴影可以被适度加深。

我们来剖析实时渲染中一个极具挑战性也极富表现力的主题——次表面散射 (Subsurface Scattering, SSS)。这正是让皮肤、玉石、蜡烛等材质摆脱“塑料感”,呈现出柔软、通透质感的关键技术。

14.6 次表面散射 (Subsurface Scattering)

核心观点: 次表面散射(SSS)描述了光线进入材质内部,经过多次散射后,从不同于入射点的位置射出的现象。这种光能在空间上的“渗透与模糊”,使得简单的BRDF模型失效,必须采用特殊的渲染技术来模拟。

理解SSS的关键:

  • 光线进入点 ≠ 光线射出点: 这是SSS与标准漫反射最根本的区别。光照在表面的一个点,但其影响会像墨水滴在宣纸上一样扩散开来。
  • 单次散射 vs. 多次散射: 光线在介质内可能只反弹一次就射出,也可能反弹成千上万次。对于皮肤这类材质,多次散射占据主导地位,它构成了那种柔和、模糊的视觉外观。因此,大多数实时SSS技术都在想办法近似模拟多次散射的扩散效应

我们将按照从简单到复杂、从“技巧”到“物理近似”的顺序,梳理各种实时SSS技术。


第一类:简单的着色模型近似 (Simple Shading Model Approximations)

这类方法不真正模拟光的扩散,而是通过修改标准的着色方程来“伪造”出SSS的柔和感。

14.6.1 环绕光照 (Wrap Lighting)

  • 核心观点: 这是最简单、最廉价的SSS近似。它通过修改兰伯特光照模型,让光线能够“环绕”到物体的背光面,从而软化明暗过渡线
  • 实现: 将标准的max(0, n·l)光照计算,放宽到一个更大的范围,例如 (n·l + wrap) / (1 + wrap),其中wrap是[0, 1]范围的控制参数。
  • 增强: 可以为这个“环绕”过来的光添加一个颜色偏移(例如皮肤使用红色),模拟光在穿透过程中被吸收了特定波长的颜色。

14.6.2 法线模糊 (Normal Blurring)

  • 核心观点: 一个非常巧妙的思路。既然多次散射的效果类似于模糊,我们不直接模糊光照,而是模糊用于计算漫反射光照的法线
  • 实现:
    1. 镜面反射 (Specular): 使用原始的、高精度的法线贴图,因为它发生在物体最表层,不受SSS影响。
    2. 漫反射 (Diffuse): 使用一个模糊后的法线贴图(甚至是未扰动的顶点法线)。
  • 优点: 几乎是零额外性能开销,效果却很显著。
  • 进阶版: 由于不同波长的光在皮肤中扩散的距离不同(红光最远),可以为RGB三个通道使用不同模糊程度的法线贴图,以模拟出更精确的颜色溢出效果。

第二类:预计算与空间扩散法 (Pre-integration and Spatial Diffusion Methods)

这类方法开始真正地模拟光的空间扩散过程,效果更真实,但开销也更大。

14.6.3 预积分皮肤着色 (Pre-integrated Skin Shading)

  • 核心观点: 将环绕光照和法线模糊的思想结合,并将光照贡献预先计算到一个**2D查找表(LUT)**中。
  • 实现: 运行时,根据**光照向量(n·l)表面曲率(curvature)**这两个参数去查询LUT,直接得到最终的散射颜色。曲率越大的地方(如鼻尖、下巴),光线渗透和散射的效果会更明显。

14.6.4 纹理空间扩散 (Texture-Space Diffusion)

  • 核心观点: 一种高画质的SSS渲染管线。其核心思想是在UV纹理空间中对光照进行模糊
  • 渲染流程:
    1. 光照渲染: 将物体的漫反射光照(Irradiance)渲染到一张展开的UV贴图上(Lightmap)。
    2. 模糊处理: 对这张光照贴图进行多次高斯模糊。关键在于,不同颜色通道使用不同半径的模糊核(例如,皮肤的红色通道模糊半径最大,绿色次之,蓝色最小)。
    3. 最终合成: 再次渲染物体,但这次不计算光照,而是直接从模糊后的光照贴图中采样漫反射颜色,再在其上叠加镜面高光。
  • 优缺点: 效果非常逼真,但流程复杂,需要为物体进行两次绘制,且依赖于良好的UV展开。

14.6.5 屏幕空间扩散 (Screen-Space Diffusion)

  • 核心观点: 这是当前实时渲染领域最主流、最灵活的SSS解决方案。它将模糊操作从纹理空间转移到了更通用的屏幕空间
  • 渲染流程:
    1. 常规渲染: 正常渲染场景,并将需要SSS效果的物体用模板缓冲(Stencil Buffer)标记出来。
    2. 屏幕空间模糊: 对渲染结果(仅标记区域)进行多趟模糊处理。
  • 实现关键 (区别于普通模糊): 这是一个“聪明的”模糊,必须考虑三维信息:
    • 双边滤波 (Bilateral Filtering): 必须检查像素的深度,避免将前景物体的光照错误地模糊到背景上。
    • 深度缩放: 模糊半径需要根据像素的深度进行缩放,以保证在世界空间中模糊范围的一致性。
    • 法线考量: 高质量的实现还会考虑法线,避免光线在曲面上不自然地“爬行”。
  • 优点: 无需额外UV和二次绘制,一套后处理可以处理屏幕上所有SSS材质,非常高效和通用。

第三类:大尺度透射近似 (Large-Scale Transmission Approximations)

这类技术主要模拟光线穿透整个物体(如手、耳朵、玉石)的效果,关注的是透射而非局部模糊。

14.6.6 深度贴图技术 (Depth Map Techniques)

  • 核心观点: 巧妙地复用光源的阴影贴图(Shadow Map)来快速估算光线穿过物体的厚度
  • 实现:
    1. 在为物体背面着色时,查询光源的阴影贴图,得到光线射入点(物体正面)的深度。
    2. 通过正面深度和当前背面深度,可以计算出光线穿过物体的路径长度
    3. 使用比尔-朗伯定律 来计算透光率,模拟光线的吸收。
  • 半透明阴影映射 (Translucent Shadow Mapping): 是该技术的扩展,在深度图中额外存储法线、光照等信息,以模拟更复杂的多次散射。
  • 游戏开发中的“Ad-Hoc”技巧:
    • 对于树叶、纸片等薄物体,可以预先烘焙一张厚度图 (Thickness Map)(常用反转法线的AO图来近似)。
    • 渲染时,背面光照的强度直接受这张厚度图的调制,再乘以一个模拟相位函数的项,可以用极低的成本实现看似合理的透光效果。

本章的最后一部分,将探讨实时渲染中两个极具挑战性的前沿领域:毛发(Hair & Fur)的模拟,以及对未来渲染范式的展望——统一渲染方法。

14.7 毛发和皮毛 (Hair and Fur)

核心观点: 实时毛发渲染是一个涉及几何表示、透明度处理、复杂光照模型、体积阴影和多重散射五大难题的综合性领域。现代实时技术通过分层解决这些问题,在性能和真实感之间取得了惊人的平衡。

毛发的物理结构:光照模型的基础

理解毛发的物理结构,是理解其独特光照现象的关键。一根毛发纤维主要由三层构成:

  1. 角质层 (Cuticle): 最外层,由倾斜的鳞片构成。它产生了毛发的主要高光(镜面反射)
  2. 皮层 (Cortex): 中间层,包含黑色素,决定了毛发的颜色。光线穿过皮层时会被染色。
  3. 髓质 (Medulla): 最内层。在人类细发中可忽略,但在动物粗硬的皮毛中,它对光线散射有显著影响。

14.7.1 几何表示与透明度处理

在着色之前,我们首先要解决“画什么”和“怎么画”的问题。

  1. 几何表示:发片 (Hair Cards / Ribbons)

    • 原理: 这是游戏中最主流的毛发几何方案。我们不渲染数百万根单独的发丝,而是创建数千个半透明的片状或带状模型(Hair Cards),并在其上贴上带有alpha通道的头发纹理。这些发片由美术师或物理模拟沿着引导曲线生成。
    • 优点: 性能开销可控,能有效覆盖大面积区域。
  2. 透明度处理:排序的噩梦

    • 问题: 大量半透明发片叠加在一起,会产生严重的排序问题,导致渲染出错。
    • 解决方案演进:
      • Alpha Blending: 最基础,但依赖于从后到前的严格排序,对于动态复杂的发型几乎不可能。
      • Alpha Testing: 不依赖排序,但会产生严重的锯齿(硬边缘),尤其是在远处。
      • Alpha to Coverage (MSAA特性): 可以软化Alpha Test的边缘,但增加了MSAA的开销。
      • 顺序无关透明度 (Order-Independent Transparency, OIT): 这是现代高质量毛发的终极解决方案。通过在GPU上使用特殊的数据结构(如Per-Pixel Linked Lists或K-Buffer)来存储每个像素前的多个片元,然后在着色器中进行手动排序和混合。AMD的TressFX就是基于此技术。

14.7.2 毛发光照模型 (Hair Shading)

核心观点: 毛发的光照极其复杂,不能用标准的BRDF来描述。我们使用一种更通用的BSDF (双向散射分布函数),其核心是模拟光线与毛发纤维交互后产生的几种独特的光路。

Marschner模型:奠基性的物理模型 这是毛发渲染领域的里程碑。它首次精确地识别并建模了三种主要的视觉贡献:

  1. R (Reflection): 光线直接从角质层表面反射。形成我们看到的主高光,通常是白色的。
  2. TT (Transmit-Transmit): 光线穿透毛发纤维,从另一侧射出。这构成了背光透光效果,让头发在光源后方时边缘发亮。
  3. TRT (Transmit-Reflect-Transmit): 光线穿透纤维,在内部发生一次反射,再穿透射出。这次内部反射让光线被皮层的黑色素染色,从而形成了带有头发颜色的次高光

这三个分量,特别是RTRT形成的两个分离且颜色不同的高光,是构成毛发真实质感的关键!

实时毛发渲染的关键挑战与方案

  1. BSDF的实时近似:

    • 完整的Marschner模型计算量巨大。实时方案(如Unreal Engine中的Karis模型)通过使用更简化的数学表达式来近似R、TT、TRT这三个视觉分量,在保持视觉特征的同时大大提升了性能。
  2. 体积阴影 (Volumetric Shadowing):

    • 问题: 普通阴影贴图会让一头浓密的头发投下漆黑一块的阴影,毫无层次感。
    • 解决方案: 必须模拟光线在发丝间的衰减。一种有效的方法是使用深度不透明度贴图 (Deep Opacity Maps),它不仅记录了最近的表面,还记录了光线路径上累积的“毛发密度”,从而可以计算出更柔和、更具层次感的阴影。
  3. 多重散射 (Multiple Scattering):

    • 问题: 光线会在不同发丝之间反复弹射,这个过程对于浅色头发(如金发)的明亮外观至关重要。若忽略,金发会看起来像干草。
    • 解决方案: 这是一个前沿难题。目前主流的实时方案是一种称为双重散射 (Dual-Scattering) 的近似模型。它通过一个全局项和一个局部项,模拟光线在整个发束中的透射和在邻近发丝间的散射,以可接受的性能开销,极大地提升了浅色头发的真实感。

14.7.3 皮毛渲染技术 (Fur Rendering)

核心观点: 皮毛通常更短、更浓密。除了使用上述的发丝渲染技术外,还有一些针对性的经典技巧。

  • 壳与鳍 (Shells and Fins):
    • 原理: 一种非常经典的“障眼法”。
      • 壳 (Shells): 将动物模型复制多次,每一层都沿法线方向稍微放大一点点,并在其上应用带有alpha的毛尖纹理。多层“壳”叠加起来就形成了毛茸茸的体积感。
      • 鳍 (Fins): 在模型的轮廓边上,挤出一些垂直于视线的面片(鳍),贴上毛发纹理。这专门用于解决“壳”技术在轮廓处的穿帮问题。
  • 几何着色器挤出 (Geometry Shader Extrusion):
    • 一种更现代的方法,利用GPU的几何着色器,直接在模型表面上“长出”成千上万的程序化发丝几何体。

14.8 统一渲染方法 (Unified Rendering Methods)

核心观点与未来展望:万物皆散射 (Everything is scattering)”。无论是坚硬的实体表面、半透明的体积、还是复杂的毛发,其视觉表现的本质都是光与微观结构的散射作用。未来的渲染管线可能会朝着一个统一的、基于体积散射的表示方法发展。

  • 从微表面到微晶片 (From Microfacets to Microflakes):
    • 我们目前的PBR表面材质基于微表面理论(将粗糙表面建模为无数微小的镜面)。
    • 未来的统一模型可能会基于微晶片理论(将一个体积建模为其中充满了无数有方向的微小薄片)。
  • 对称GGX (Symmetrical GGX, SGGX):
    • 这是一个很有前景的数学模型,它将描述表面粗糙度的GGX分布扩展到了体积域,能够统一描述光线在体积内的透射和散射。
  • 最大的优势:自然的LOD (Natural Level of Detail):
    • 在统一的体积表示下,物体的LOD不再需要切换不同的网格模型(会产生突兀的POP-UP现象)。取而代之的是,对体积数据进行平滑的滤波。想象一下,远处的森林不再是“纸片树”和“模型树”的切换,而是平滑地从精细的树木细节过渡到一团具有正确颜色和遮挡属性的绿色体积。这将是渲染技术的一个巨大飞跃。

本章总结

这是实时渲染中内容最丰富、最具挑战性的章节之一。我们从光线与介质作用的物理基础出发,系统性地学习了如何渲染体积雾和云半透明表面、具有次表面散射的柔和材质,以及极为复杂的毛发。这些技术是构建现代高质量、高沉浸感虚拟世界的关键。更重要的是,我们展望了“万物皆散射”的统一渲染未来。