Real-Time Rendering 4th 第十一章(二)
11.4 Directional Occlusion
即使仅使用环境遮挡可以极大地提高图像的视觉质量,但是它还是一个大大简化的模型。当处理甚至是大面积的光源,它对可见性的估计也很差,更不用说小的或守时的光源时。 它也无法正确处理光泽BRDF或更复杂的照明设置。考虑一个由遥远的圆顶灯照亮的表面,整个圆顶的颜色从红色变为绿色。根据颜色,这可能代表地面被天空发出的光线照亮,可能是在某个遥远的星球上。具体看下图。即使周围的遮挡会使点a和b的照明变暗,但它们仍将被天空的红色和绿色部分照亮。使用弯曲的法线有助于减轻这种影响,但也不是完美的。 我们之前介绍的简单模型不足以应对此类情况。 一种解决方案是以某种更具表现力的方式描述可见性
我们将着重于对整个球形或半球形可见性进行编码的方法,即描述哪些方向阻挡入射辐射的方法。尽管此信息可用于遮挡精准光源,但这不是其主要目的。 针对那些特定类型的灯光的方法(在第7章中进行了广泛讨论)能够获得更好的质量,因为它们只需要为光源的单个位置或方向编码可见性即可。此处描述的解决方案主要用于为大面积的灯光或环境照明提供遮挡,在这种情况下,生成的阴影较柔和,并且由于近似可见性而导致的瑕疵不明显。此外,在常规阴影技术不可行的情况下,例如,对于凹凸贴图细节的自阴影化以及阴影贴图没有足够分辨率的超大型场景的阴影化,这些方法也可以用于遮挡。
11.4.1 Precomputed Directional Occlusion
Max引入了水平映射( horizon mapping )的概念来描述高度场表面的自遮挡。在水平映射中,对于表面上的每个点,相对于水平的高度角(altitude angle)是由一组方位角方向(azimuth directions)决定的。既8个方向,北,东北,东,东南,南,西南,西,西北。
代替存储某些给定指南针方向的水平角度,整个未封闭的三维方向集可以建模为椭圆或圆形孔径。后一种技术称为环境光圈照明( ambient aperture lighting )(下图)。
这些技术的存储要求比水平映射低,但是当一组未遮挡的方向与椭圆或圆形不相似时,可能会导致阴影不正确。例如,一个平坦的平面,高尖峰从该平面以固定间隔突出,该平面应设置一个星形方向,该方向与该方案的映射不佳。
遮挡技术有很多变体。Wang等人使用球面有符号距离函数(spherical signed distance function)(SSDF)表示可见性。它编码被遮挡区域边界的有符号距离到球上。 第10.3节中讨论的任何球形或半球形基数也可以用于编码可见性。 就像环境遮挡一样,方向可见性信息可以存储在纹理,网格顶点或体积中。
11.4.2 Dynamic Computation of Directional Occlusion
用于生成环境遮挡的许多方法也可以用于生成方向可见性信息。Ren等人的球形谐波指数及其Sloan等人的屏幕空间变体以球形谐波矢量的形式生成可见性。如果使用多个SH波段,则这些方法本身会提供方向信息。 使用更多的频段可以更精确地编码可见性。
圆锥跟踪方法(例如Crassin等人和Wright的方法)为每个跟踪提供一个遮挡值。出于质量原因,甚至使用多条迹线进行环境光遮挡计算,因此可用信息已经定向。如果需要特定方向的可见性,我们可以追踪更少的圆锥体。
Iwanicki也使用圆锥跟踪,但他将其限制在一个方向。 结果被用来生成由动态角色投射到静态几何体上的柔和阴影,这些动态角色用一组球近似,类似于Ren等人和Sloan等人。 在该解决方案中,静态几何体的照明使用AHD编码存储(第10.3.3节)。周围和定向组件的可见性可以独立处理。对环境部分的遮挡进行了解析计算。跟踪单个圆锥并与球相交以计算方向分量的衰减因子。
许多屏幕空间方法也可以扩展为提供方向遮挡信息。Klehm等人使用z缓冲区数据来计算屏幕空间的弯曲圆锥体,实际上是圆形的孔径,非常类似于Oat和Sander离线预先计算的那些。在对像素邻域进行采样时,它们会将未遮挡的方向相加。所得向量的长度可用于估计可见性锥的顶角,其方向定义该锥的轴。Jimenez等人基于水平角估计锥轴方向,并从环境遮挡因子得出角度。
11.4.3 Shading with Directional Occlusion
编码定向遮挡的方法多种多样,我们无法为如何执行着色提供单一的方法。解决方案将取决于我们想要实现的什么样子的效果。
让我们再次考虑反射率方程,在一个将入射辐射分为远处照明Li和可见度v的版本中:
我们可以做的最简单的操作是使用可见度符号遮挡精准光源。由于大多数编码可见性的方法都比较简单,因此结果的质量通常不尽人意,但这将使我们能够在一个基本示例上进行推理。该方法也可以用于传统的阴影方法由于分辨率不足而失败的情况,并且结果的精确性远不如实现任何形式的遮挡重要。 这种情况的示例包括非常大的地形模型,或由凹凸贴图表示的较小表面细节。
按照第9.4节的讨论,在处理精准光源时,公式11.26变为
其中clight是从面对光的白色Lambertian表面反射的辐射,而lc是朝向光的方向。我们可以将上述等式解释为计算材质对未遮挡的光的响应,并将结果乘以可见性函数的值。 如果光的方向落在水平线以下(使用水平贴图时),在可见性圆锥体外部(使用环境光圈照明时)或在SSDF的负区域中,则可见性函数等于零,因此光的任何贡献不应该考虑在内。值得一提的是,即使将可见性定义为二进制函数,许多表示形式也可以返回整个范围的值,而不仅仅是零或一。这样的值表示部分遮挡。 由于振铃,球谐或 H -basis甚至可以重建负值。这些行为可能是不需要的,仅仅是编码的固有属性。
我们可以对区域照明进行类似的推理。 在这种情况下,Li在所有地方都等于零,但在光所包围的立体角内,Li等于该光源发出的辐射。我们将其称为Ll,并假设它在光源的立体角上是恒定的。 我们可以将整个球面Ω的积分替换为光的立体角Ωl的积分:
如果我们假设BRDF是恒定的,那么我们正在处理Lambertian曲面,那么它也可以从下面的积分推导出:
为了确定被遮挡光照,我们需要计算可见度函数的积分,再乘以在光所包围的立体角上的余弦项。在某些情况下可以通过分析来完成。Lambert推导了一个公式来计算球形多边形上余弦的积分。如果区域光是多边形的,并且可以将其裁剪为可见性表示形式,则只需要使用Lambert公式即可得出精确的结果(下图)。
例如,当我们选择水平角度作为可见性表示形式时,这是可能的。但是,如果由于某种原因我们决定采用其他编码方式(例如弯曲的圆锥体),则裁剪将产生圆形片段,因此我们将无法再使用Lambert公式。如果我们要使用非多边形区域光源,则同样适用。
另一种可能性是假设余弦项的值在整个积分域中是恒定的。如果区域光的大小较小,则此近似值非常精确。为简单起见,我们可以使用沿区域光的中心方向计算的余弦值。这给我们留下了可见度项在光的立体角上的积分。同样,我们如何进行选择取决于可见性表示形式和区域光的类型。如果我们使用球面光源和用弯曲圆锥体表示的可见性,则积分的值是可见性圆锥体与圆锥体被光线遮住的交点的立体角。可以通过分析来计算,如Oat和Sander所示。尽管精确的公式很复杂,但它们提供了一种近似值,在实际中效果很好。如果能见度是用球谐函数编码的,则积分也可以通过解析计算。
对于环境照明,我们不能限制积分范围,因为照明来自各个方向。我们需要找到一种根据公式11.26计算全积分的方法。
让我们首先考虑Lambertian BRDF:
该方程式中积分的类型称为三乘积积分(triple product integral)。如果各个函数以某些方式表示(例如,以球谐函数或小波表示),则可以进行分析计算。不幸的是,对于典型的实时应用而言,这太昂贵了,尽管已经证明这种解决方案可以在简单的设置中以交互式帧速率运行。
不过,我们的特定情况稍微简单一些,因为余弦是函数之一。 我们可以将公式11.30写成
或者
其中
都是球形函数,就像Li(l)和v(l)。 我们没有尝试计算三元积积分,而是先将余弦乘以Li(方程11.31)或vi(方程11.32)。这样做使被积物只有两个功能的乘积。 尽管这看起来像是一个数学技巧,但它极大地简化了计算。如果使用正交标准(例如球谐函数)表示这些因子,则可以简单计算出双乘积积分。 它是其系数向量的点积(第10.3.2节)。
我们仍然需要计算
但是因为它们涉及余弦,所以比完全普通的情况要简单。 如果我们用球谐函数表示函数,则余弦会投影到区域谐波(ZH),这是球谐函数的子集,其每个频带中只有一个系数为非零(第10.3.2节)。此投影的系数具有简单的解析公式。SH和ZH的乘积比SH和另一个SH的乘积的计算要更高效。
如果我们决定先将余弦乘以v(公式11.32),则可以离线进行,而只存储可见性。
如Sloan等人所述(第11.5.3节),这是一种预先计算的辐射传递( precomputed radiance transfer )形式。但是,以这种形式,我们不能对法线进行任何精细的修改,因为由法线控制的余弦项已经与可见性融合在一起。如果要对精细尺度的法线细节建模,可以先将余弦乘以Li(公式11.31)。 由于我们不预先知道法线方向,因此我们可以针对不同的法线预先计算此乘积,或者在运行时执行乘法。离线预先计算Li和余弦的乘积意味着限制照明的任何变化,并且允许照明在空间上变化将需要大量的内存。 另一方面,在运行时计算乘积在计算上是昂贵的。Iwanicki和Sloan描述了如何降低这一成本。乘积可以以较低的粒度(在顶点上)进行计算。 将结果与余弦项卷积,投影到更简单的表示形式(AHD)上,然后使用每像素法线进行插值和重构。这种方法使他们可以在性能要求很高的60 FPS游戏中使用该方法。
Klehm等人提出了一种解决方案,用于以环贴图射表示的照明和以视锥编码的可见性。他们使用不同大小的内核过滤环境贴图,这些内核代表了针对不同圆锥孔的可见性和光照的乘积的积分。 它们将增加圆锥角的结果存储在纹理的mip级别中。这是可能的,因为大锥角的预过滤结果在整个球面上平滑变化,并且不需要以高的粒度分辨率存储。在预过滤期间,他们假定可见性圆锥体的方向与法线对齐,这是一个近似值,但实际上给出了合理的结果。 他们提供了有关此近似值如何影响最终质量的分析。
如果我们要处理有光泽的BRDF和环境照明,情况将更加复杂。 我们不能再从积分下拉BRDF,因为它不是常数。为了解决这个问题,格林等人建议用一组球形高斯( spherical Gaussians )近似BRDF本身。这些是径向对称函数,可以仅用三个参数紧凑地表示:方向(或平均值)d,标准偏差µ和振幅w。 近似BRDF定义为球形高斯的总和:
其中G(d,µ,l)是球形高斯波瓣,沿d方向定向,具有锐度µ(见10.3.2节),并且在第k个波瓣的振幅中为wk。对于各向同性的BRDF,波瓣的形状仅取决于法线和视图方向之间的角度。 近似值可以存储在一维查找表中并进行插值。
通过这种近似,我们可以将公式11.26写成
Green等人还假设可见性函数在每个球面高斯的整个支持中是恒定的,这允许它们从积分下提取它。他们计算在波瓣中心方向上的可见性函数:
剩余的积分表示入射光与以给定方向和给定标准偏差定向的球形高斯卷积。这种卷积的结果可以预先计算并存储在环境贴图中,而较大µ的卷积则存储在较低的mip级别中。可见性是用低阶球谐函数编码的,但是也可以使用任何其他表示形式,因为它仅是点计算的。
Wang等人以类似的方式近似BRDF,但是以更精确的方式处理可见性。它们的表示使他们能够在可见性函数的支持下计算单个球形高斯积分。他们使用该值引入了一个新的球形高斯分布,其方向和标准偏差相同,但幅度不同。 他们在照明计算中使用了这一新功能。
对于某些应用,此方法可能太昂贵。它需要从预过滤的环境贴图中获取多个样本,并且纹理采样通常已经成为渲染过程中的瓶颈。 Jimenez等人和El Garawany提出了更简单的近似值。 为了计算遮挡因子,它们用单个圆锥体表示整个BRDF瓣,而忽略了其对视角的依赖性,只考虑了诸如材料粗糙度之类的参数(下图)。
它们将可视性近似为圆锥形,并计算可视性与BRDF圆锥体相交的立体角,这与环境光圈照明非常相似。即使大大简化,结果还是可以相信的。
11.5 Diffuse Global Illumination
下一部分将介绍各种方法,不仅可以实时模拟遮挡,还可以模拟全光线反射。它们可以粗略地划分为算法,这些算法假定,在到达眼睛之前,光会从漫反射或高光平面反射回来。相应的光路可以写成L(D | S)* DE或L(D | S)* SE,其中许多方法都对较早的反弹类型施加了一些约束。第一组中的解决方案假定传入的光在着色点上方的半球上平滑变化,或者完全忽略该变化。第二组算法假定入射方向的变化率很高。他们依赖这样的事实,即照明将仅在相对较小的立体角内进入。 由于这些巨大的限制,因此分别处理这两个组是有好处的。在本节中,我们将介绍漫反射全局照明的方法,在下一部分中将讨论高光反射,然后在最后一节中介绍有希望的统一方法。
11.5.1 Surface Prelighting
光能传递和路径跟踪均设计用于脱机使用。尽管已努力在实时设置中使用它们,但结果仍太不成熟,无法在生产中使用。 当前,最常见的做法是使用它们来预先计算与照明有关的信息。昂贵的离线过程需要提前运行,其结果将被存储起来,然后在显示过程中用于提供高质量的照明。如第11.3.4节所述,以这种方式对静态场景进行预计算称为烘焙。
这种做法带有一定的限制。如果我们提前进行光照计算,则无法在运行时更改场景设置。所有场景的几何形状,灯光和材质都需要保持不变。我们不能改变一天中的时间或在墙上打洞。在许多情况下,此限制是可以接受的折衷方案。 建筑可视化可以假定用户仅在虚拟环境中走动。 游戏也限制了玩家的动作。 在此类应用中,我们可以将几何分为静态( static )对象和动态( dynamic )对象。 静态对象用于预计算过程中,它们与照明完全交互。静止的墙壁投下阴影,静止的红色地毯反射红光。动态对象仅充当接收者。 它们不会阻挡光线,也不会产生间接照明效果。在这种情况下,通常将动态几何形状限制为相对较小,因此可以忽略其对其余照明的影响,也可以使用其他技术对其进行建模,而质量损失最小。动态几何可以例如使用屏幕空间方法来生成遮挡。 典型的动态对象集包括角色,装饰几何和车辆。
可以预先计算的最简单形式的照明信息是辐照度。对于平坦的Lambertian表面以及表面颜色,它可以充分描述材料对照明的反应。由于照明源的效果与其他光源无关,因此可以在预先计算的辐照度之上添加动态光(下图)。
1996年的Quake和1997年的Quake II是第一个利用预计算辐照度值的商业交互式应用程序。 Quake先预先计算静态光的直接贡献,主要是为了提高性能。Quake II还包含一个间接组件,使它成为第一款使用全局照明算法生成更逼真的照明的游戏。 它使用了基于光能传递的算法,因为该技术非常适合在 Lambertian环境中计算辐照度。同样,时间的内存限制将照明限制为相对较低的分辨率,这与光能传递解决方案中典型的模糊低频阴影很好地匹配。
通常将预先计算的辐照度值与存储在单独的一组纹理中的漫反射色或反照率贴图相乘。 尽管理论上可以预先计算出出射量(辐照度乘以漫反射的颜色)并存储在一组纹理中,但是在大多数情况下,许多实际考虑都排除了此选项。彩色贴图的频率通常很高,它们使用各种平铺方式,并且它们的各个部分经常在整个模型中重复使用,所有这些都会使内存使用保持合理。辐照度值通常是低得多的频率,不能轻易重复使用。 保持照明和表面颜色分开会消耗更少的内存。
除最严格的硬件平台外,如今很少使用预先计算的辐照度。因此按照定义,辐照度是针对给定法线方向计算的,因此我们无法使用法线映射来提供高频细节。 这也意味着只能针对平坦表面预先计算辐照度。 如果需要在动态几何体上使用烘焙的照明,则需要其他方法来存储它。这些局限性促使人们寻找一种方法来存储带有方向分量的预先计算的照明。
11.5.2 Directional Surface Prelighting
要将预照明与Lambertian曲面上的法线贴图一起使用,我们想要一种表示辐照度如何随曲面法线变化的方法。为了为动态几何体提供间接照明,我们还需要为每个可能的表面方向提供其值。幸运的是,我们已经有了表示这些功能的工具。在10.3节中,我们介绍了根据法线方向确定照明的各种方法。 这些包括针对功能域为半球形且球体下半部分的值无关紧要的特殊解决方案,不透明表面的情况也是如此。
最通用的方法是存储完整的球形辐照度信息,例如通过使用球形谐波。 该方案最初是由Good和Taylor在加速光子映射的背景下提出的,并由Shopf等人在实时设置中使用。在这两种情况下,定向辐射都存储在纹理中。 如果使用九个球谐系数(三阶SH),则质量非常好,但是存储和带宽成本很高。 仅使用四个系数(二阶SH)的成本较低,但会丢失许多细微之处,照明的对比度较低,法线贴图的清晰度较差。
Chen使用Halo 3方法的一种变体,该方法旨在以更低的成本获得三阶SH的质量。他从球形信号中提取最主要的光,并将其分别存储为颜色和方向。 使用二阶SH对余数进行编码。这样可以将系数的数量从27个减少到18个,而质量损失很小。Hu描述了如何进一步压缩这些数据。 Chen和Tatarchuk提供了有关生产中使用的基于GPU的烘培管线的更多信息。
Habel等人的H-basis是另一种替代解决方案。 由于它仅编码半球形信号,因此,用较少的系数可以提供与球形谐波相同的精度。只需六个系数就可以得到与三阶SH相当的质量。由于仅针对半球定义了基础,因此我们需要在表面上具有一些局部坐标系以使其正确定向。通常,将由uv参数化产生的切线架构用于此目的。如果将H-basis分量存储在纹理中,则其分辨率应足够高以适应底层切线空间的变化。如果切线空间明显不同的多个三角形覆盖同一纹素,则重构的信号将不精确。
球形谐波和H-basis的一个问题是它们会出现振铃(第10.6.1节)。尽管预过滤可以减轻这种影响,但它也可以使照明变得平滑,这可能并不总是被希望的。另外,就存储和计算而言,即使是较便宜的变体仍然具有相对较高的成本。在限制性更强的情况下(例如在低端平台上或为虚拟现实进行渲染时),此花费可能是禁止的。
花费也是简单替换方案仍然受欢迎的原因。《半条命2》使用自定义的半球基(第10.3.3节),该基础存储了三个颜色值,每个样本总共有9个系数。尽管环境/高光/方向( ambient/highlight/direction)(AHD)基础(第10.3.3节)虽然简单易行,但它也是一个受欢迎的选择。 它已被用于《使命召唤》系列和《 The Last of Us 》等游戏中。 参见下图。
Crytek在游戏Far Cry中使用了一个变体。Crytek表示方法由切线空间中的平均光线方向,平均光线颜色和标量方向性因子组成。最后一个值用于混合使用相同颜色的环境分量和方向分量。这样可以将每个样本的存储量减少到六个系数:三个用于颜色,两个用于方向,1个用于方向性因子。Unity引擎在其模式之一中也使用类似的方法。
这种类型的表示是非线性的,这意味着从技术上讲,在像素之间或顶点之间线性内插单个分量在数学上是不正确的。 如果主导光的方向快速变化,例如在阴影边界上,则可能在着色中出现视觉伪像。尽管存在这些错误,但结果看起来还是令人愉悦的。由于周围环境和定向照明区域之间的对比度很高,因此法线贴图的效果会更加突出,这通常是理想的。此外,在计算BRDF的高光响应时,可以使用方向性分量,以提供一种低成本替代环境的低光泽度材质贴图。
在频谱的另一端是为高视觉质量而设计的方法。Neubelt和Pettineo在游戏The Order:1886(下图)中使用纹理图存储了球形高斯系数。它们存储入射辐射,而不是辐照度,它被投影到切线架构中定义的一组高斯波瓣(第10.3.2节)。 根据特定场景中照明的复杂性,它们使用五到九个瓣。为了产生漫反射效果,球形高斯由沿表面法线方向的余弦瓣卷积。通过使高斯与高光BRDF瓣卷积,该表示也足够精确以提供低光泽的高光效果。Pettineo详细介绍了整个系统。他还为能够烘焙和渲染不同照明表示形式的应用程序提供源代码。
如果我们需要有关任意方向照明的信息,而不仅仅是在表面上方的半球内(例如,为动态几何图形提供间接照明),则可以使用对完整球形信号进行编码的方法。 球谐函数在这里很合适。当内存问题较少时,三阶SH(每个颜色通道有9个系数)是受欢迎的选择。否则,将使用二阶(每个颜色通道四个系数,这些系数与RGBA纹理中的组件数量匹配,因此单个贴图可以存储一个颜色通道的系数)。 球形高斯也可以在完全球形的环境中工作,因为波瓣可以分布在整个球体或法线周围的半球中。 但是,由于球形技术需要波瓣覆盖的立体角是原来的两倍,因此我们可能需要使用更多的波瓣来保持相同的质量。
如果我们想避免振铃,但又不能使用大量的波瓣,那么环境立方(第10.3.1节)是一个可行的选择。它由六个沿主轴定位的cos^2瓣组成。 余弦波瓣仅覆盖一个半球,因为它们具有局部支撑( local support ),这意味着它们仅在其球域的子集上具有非零值。因此,在重建过程中仅需要六个存储值中的三个可见瓣。这限制了照明计算的带宽成本。 重建的质量类似于二阶球谐函数。
Ambient dice(也见第10.3.1节)可用于比环境立方体更高的质量。此方案使用沿二十面体的顶点定向的十二个波瓣,它们是cos^2和cos^4裂片的线性组合。在重建过程中使用了十二个存储值中的六个。 其质量可与三阶球形谐波媲美。 这些以及其他类似的表示形式(例如,由三个cos^2瓣和一个余弦瓣组成的基,扭曲以覆盖整个球体)已在许多商业上成功的游戏中使用,例如Half-Life 2,Call of Duty系列, 孤岛惊魂3(Far Cry 3),汤姆克兰西(Tom Clancy)的The Division和刺客信条(Assassin's Creed 4:Black Flag)等。
11.5.3 Precomputed Transfer
尽管预计算的照明看起来很漂亮,但它本身也是静态的。几何形状或照明的任何更改都可能使整个解决方案无效。就像在现实世界中一样,打开窗帘(场景中几何体的局部变化)可能会使整个房间充满光线(照明的全局变化)。在寻找允许某些类型的更改的解决方案上已经花费了很多研究工作。
如果我们假设场景的几何形状不会改变,仅改变照明,那么我们可以预先计算光与模型的交互方式。可以在某种程度上预先分析对象间的影响,例如相互反射或地下散射,并存储结果,而无需对实际辐射值进行操作。将传入的光照转换为整个场景的辐射分布的描述的函数称为转换函数(transfer function)。对此进行预先计算的解决方案称为预计算转换( precomputed transfer )或预计算辐射转换( precomputed radiance transfer )(PRT)方法。
与将光源完全脱机烘烤相比,这些技术确实具有明显的运行时成本。在屏幕上显示场景时,我们需要计算特定照明设置的辐射值。为此,将实际的直接光量“注入”到系统中,然后应用转换函数将其传播到整个场景中。 一些方法假定这种直接照明来自环境贴图。 其他方案允许照明设置是任意的并以灵活的方式进行更改。
Sloan等人将预计算辐射转移的概念引入图形中。他们用球谐函数来描述它,但是该方法不必使用SH。基本思想很简单。如果我们使用一些(最好是少量)“构件”灯来描述直接照明,则可以预先计算其中的每一个如何照亮场景。想象一下一个房间,里面有三台计算机显示器,并假设每个显示器只能显示一种颜色,但是强度会有所不同。考虑每个屏幕的最大亮度等于一个标准化的“单位”亮度。我们可以独立地预先计算每个显示器对房间的影响。可以使用第11.2节介绍的方法完成此过程。因为光传输是线性的,所以用所有三个显示器照亮场景的结果将等于直接或间接来自每个显示器的光的总和。 每个显示器的照明不会影响其他解决方案,因此,如果我们将其中一个屏幕设置为一半的亮度,这样做只会改变其自身对总照明的贡献。
这使我们能够快速计算整个房间内的全反射光。我们采用每个预计算的光源解决方案,将其乘以屏幕的实际亮度,然后对结果求和。我们可以打开和关闭显示器,使它们变亮或变暗,甚至改变它们的颜色,而要获得最终照明,所需要做的就是这些乘数和加法运算(下图)。
我们可以写成
其中L(p)是在点p的最终辐射,Li(p)是来自屏幕i的预计算的单位贡献,而wi是其当前亮度。 该方程式在数学上定义了一个向量空间( vector space ),其中Li是该空间的基础向量。线性照明组合可以创建任何可能的照明。
Sloan等人的原始PRT论文使用了相同的推理,但在无限远的照明环境中使用了球谐函数表示。他们存储的不是场景对显示器屏幕的响应,他们存储它如何响应周围的光,其分布由球面谐波基函数定义。通过对一定数量的SH波段执行此操作,它们可以渲染由任意照明环境( lighting environment)照亮的场景。他们将这种照明投射到球谐上,将每个结果系数乘以其各自的归一化“单位”贡献,然后将它们加在一起,就像我们对显示器所做的那样。
请注意,用于将光“注入”场景的基础选择与用于表达最终照明的表示形式无关。例如,我们可以描述如何使用球谐函数照亮场景,但可以选择另一个基础方法来存储在任何给定点到达多少辐射。假设我们使用环境立方体进行存储。 我们会计算出从顶部到达多少辐射,从侧面到达多少辐射。这些方向的每个方向的传递都将单独存储,而不是作为表示总传递的单个标量值存储。
Sloan等人的PRT论文分析了两种情况。第一种是当接收基仅是表面的标量辐照度值时。 为此,接收器必须是具有预定法线的完全漫反射的表面,这意味着它不能将法线贴图用于精细比例的细节。转换函数采用输入照明的SH投影与预先计算的转换向量( transfer vector )之间的点积形式,该点积在整个场景中会发生空间变化。
如果我们需要渲染非Lambertian材质,或允许使用法线贴图,则可以使用第二种变化形式。在这种情况下,周围照明的SH投影将转换为给定点的入射辐射的SH投影。因为此操作为我们提供了整个球体(或半球,如果我们要处理静态不透明物体)的完整辐射度分布,则我们可以将其与任何BRDF适当地卷积。传递函数将SH向量映射到其他SH向量,并具有矩阵乘法的形式。无论在计算上还是在存储器方面,这种乘法运算都是昂贵的。 如果我们对源和接收器都使用三阶SH,则需要为场景中的每个点存储9×9矩阵,并且这些数据仅用于单色转化。如果需要颜色,则需要三个这样的矩阵。
一年后,Sloan等人解决了这个问题。与其直接存储转移向量或矩阵,不如使用主成分分析( principal component analysis )(PCA)技术分析它们的整个集合。可以将转换系数视为多维空间中的点(例如,在9×9矩阵的情况下为81维),但是它们的集合在该空间中分布不均匀。它们形成维数较低的簇。这种聚类就像沿着一条线分布的三维点,实际上,全部位于三维空间的一维子空间中一样。PCA可以有效地检测这种统计关系。一旦发现了子空间,就可以使用更少数量的坐标来表示点,因为我们可以将维度中的位置存储在减少的维度中。使用线类比,而不是使用三个坐标存储点的完整位置,我们只需存储其沿线的距离即可。 Sloan等人使用此方法将转换矩阵的维数从625维(25×25转换矩阵)减少到256维。 尽管对于典型的实时应用来说,这仍然太高了,但是许多后来的光传输算法都采用PCA作为压缩数据的一种方式。
这种降维本质上是有损的。在极少数情况下,数据形成一个完美的子空间,但大多数情况下是近似的,因此将数据投影到其上会导致一些损伤。为了提高质量,Sloan等人将转换矩阵集划分为多个簇,并分别对每个簇执行PCA。 该过程还包括一个优化步骤,可确保在群集边界上不存在不连续性。还提出了允许对象有限变形的扩展,称为局部可变形预计算辐射传递( local deformable precomputed radiance transfer )(LDPRT)。
PRT已在多种游戏中以各种形式使用。它在游戏玩法集中于一天中的时间和天气条件会动态变化的户外区域的游戏中特别受欢迎。孤岛惊魂3和孤岛惊魂4使用PRT,其中源基为二阶SH,接收基为定制的四方向基。 刺客信条4:黑旗使用一种基函数作为来源(太阳色),但会预先计算一天中不同时间的传输量。 可以将这种表示解释为具有在时间维度而非方向上定义的源基函数。 接收基的依据与《孤岛惊魂》的区域相同。
SIGGRAPH 2005有关预计算辐射率传输的课程很好地概述了该领域的研究。Lehtinen提供了一个数学框架,可用于分析各种算法之间的差异并开发新算法。
原始的PRT方法假定周围光线无限远。尽管此模型可以很好地模拟室外场景的照明,但对于室内环境而言却过于严格。但是,正如我们前面提到的,该概念与照明的原始来源完全无关。Kristensen等人描述了一种方法,其中PRT是针对散布在整个场景中的一组灯光计算的。这对应于具有大量的“源”基函数。接下来,将灯光组合成簇,然后将接收几何体划分为多个区域,每个区域受不同的灯光子集影响。该过程导致传输数据的显着压缩。在运行时,通过对来自预先计算的集合中最接近的灯光的数据进行插值,可以近似估算任意放置的灯光所产生的照明。Gilabert和Stefanov使用此方法在游戏《孤岛惊魂3》中生成间接照明。此方法的基本形式只能处理点光源。 尽管可以扩展以支持其他类型,但成本随每个灯的自由度数量呈指数增长。
至此为止讨论的PRT技术会预先计算一些元素的传输,然后将其用于建模灯光。另一类流行的方法是预先计算平面之间的传递。 在这种类型的系统中,实际的照明源变得无关紧要。 可以使用任何光源,因为这些方法的输入是来自一组表面的出射辐射(如果该方法采用仅漫反射表面,则为其他相关量,例如辐照度)。 这些直接照明计算可以使用阴影(第7章),辐照环境贴图(第10.6节)或本章前面讨论的环境和方向遮挡方法。 通过将任何表面的出射辐射设置为所需值,并将其变成面光源,也可以使表面变得微不足道。
根据这些原则运行的最流行的系统是Geomerics的Enlighten(下图)。尽管该算法的确切细节尚未完全公开披露,但大量的演讲和演示都准确地描述了该系统的原理。
场景假定为Lambertian,但仅用于光传输的目的。使用Heckbert的表示法,处理的路径集为LD *(D | S)E,因为眼睛之前的最后一个曲面不仅仅是漫反射的。该系统定义了一组“源”元素和另一组“接收”元素。源元素存在于表面上,并共享它们的某些属性,例如漫反射颜色和法线。预处理步骤计算光如何在源元素和接收器之间传输。该信息的确切形式取决于源元素是什么以及在接收器处收集照明的基。以最简单的形式,源元素可以是点,然后我们想在接收位置生成辐照度。在这种情况下,传输系数只是源和接收方之间的相互可见性。在运行时,所有源元素的输出辐射都提供给系统。 根据这些信息,我们可以使用预先计算的可见性和有关源和接收器的位置和方向的已知信息,对反射率方程(方程11.1)进行数值积分。
以此方式,执行一次光反射。由于大多数间接照明来自第一次反射,因此仅执行一次反射就足以提供合理的照明。但是,我们可以使用此光并再次运行传播步骤以生成第二次反射。这通常是在几帧的过程中完成的,其中一帧的输出用作下一帧的输入。
将点用作源元素将导致大量连接。为了提高性能,代表法线和颜色相似区域的点的簇也可以用作源集。在这种情况下,传输系数与辐射度算法(11.2.1节)中看到的形状系数相同。请注意,尽管有相似之处,但该算法与经典的辐射度不同,因为它一次只计算一个反弹光,并且不涉及求解线性方程组。它借鉴了渐进辐射( progressive radiosity )的思想。在此系统中,单个 patch可以通过迭代过程确定从其他patch接收多少能量。将辐射转移到接收位置的过程称为收集( gathering )。
接收元素处的辐射可以以不同的形式收集。 到接收元素的传输可以使用我们之前描述的任何定向基。在这种情况下,单个系数成为向量的值,维数等于接收基中的函数的数量。使用定向表示执行收集时,结果与11.5.2节中描述的脱机解决方案相同,因此可以与法线贴图一起使用或提供低光泽的高光反射。
在许多变体中都使用相同的一般思想。为了节省内存,Sugden和Iwanicki使用SH传输系数,对其进行量化,然后将它们间接存储为调色板中条目的索引。Jendersie等人建立了源patch的层次结构,并在当子级对向的立体角太小时,在该树中存储对较高元素的引用。Stefanov引入了一个中间步骤,首先将表面元素的辐射传播到场景的体素化表示体系中,然后将其用作传输的源。
从某种意义上说,理想的表面分割成源patch取决于接收器的位置。对于遥远的元素,将它们视为单独的实体会产生不必要的存储成本,但近距离查看时应将其单独对待。源patch的层次结构在某种程度上缓解了此问题,但并未完全解决。可用于特定接收器组合的某些patch可能相距足够远,足以防止此类合并。Silvennoinen和Lehtinen提出了解决该问题的新方法。他们的方法不是明确的创建源patch,而是为每个接收位置生成不同的源patch集。将对象渲染到散布在场景周围的稀疏环境贴图集合。每个贴图都被投影到球谐函数,而这个低频版本被“虚拟”投影回环境。接收点记录他们可以看到多少投影,并且此过程分别针对每个发送者的SH基功能完成。 这样做会根据来自环境探测器和接收器点的可见性信息为每个接收器创建一组不同的源元素。
由于源基是从投影到SH的环境贴图生成的,因此自然会组合更远的曲面。 为了选择要使用的探针,接收器使用了一种有利于附近探针的启发式方法,这使接收器以相似的比例“看到”环境。 为了限制必须存储的数据量,使用群集PCA压缩传输信息。
Lehtinen等人描述了另一种形式的预计算传输。在这种方法中,源元素和接收元素都不存在于网格上,而是体积上,可以在三维空间中的任何位置进行查询。这种形式便于在静态和动态几何之间提供照明一致性,但是该方法在计算上相当昂贵。
Loos等人在具有不同配置的侧壁的模块化单位单元内进行预计算传输。然后,将多个此类单元进行缝合和扭曲以近似场景的几何形状。辐射首先传播到充当界面的单元边界,然后再使用预先计算的模型传播到相邻的单元。 该方法足够快,即使在移动平台上也能有效运行,但是对于要求更高的应用程序,其质量可能并不足够。
11.5.4 Storage Methods
无论我们是要使用完整的预先计算的照明还是要计算传输信息并允许对照明进行一些更改,都必须以某种形式存储结果数据。 必须使用GPU友好格式。
光照贴图是存储预计算光照的最常用方法之一。 这些是存储预先计算的信息的纹理。尽管有时使用诸如辐照度贴图( irradiance map )之类的术语来表示存储的特定类型的数据,但是使用术语光照贴图(light map)来共同描述所有这些数据。在运行时,将使用GPU的内置纹理机制。值通常是双线性过滤的,对于某些表示形式,可能并不完全正确。例如,当使用AHD表示时,滤波后的D(方向)分量在插值后将不再是单位长度,因此需要重新归一化。 使用插值法还意味着,如果我们直接在采样点上计算A(环境)和H(突出显示),它们将不是确切的。也就是说,即使表示形式是非线性的,结果通常看起来也可以接受。
在大多数情况下,光照贴图不使用mipmapping,这通常是不需要的,因为与典型的反照率贴图或法线贴图相比,光照贴图的分辨率较小。即使在高质量的应用中,单个光照贴图纹素也可以覆盖至少大约20×20厘米(通常更大)的区域。 使用这种大小的纹理像素,几乎将不再需要额外的mip级别。
为了将光照存储在纹理中,对象需要提供唯一的参数化( unique parameterization )。将漫反射颜色纹理映射到模型上时,通常可以使网格的不同部分使用纹理的相同区域,尤其是在模型使用常规重复图案进行纹理化的情况下。重用光照贴图是最困难的。光照对于网格上的每个点都是唯一的,因此每个三角形都需要在光照图上占据其自己的唯一区域。创建参数化的过程始于将网格划分为较小的块。这可以使用某些启发式方法自动完成,也可以在创作工具中手动完成。通常,使用已经存在的其他纹理映射切分。接下来,分别对每个块进行参数化,以确保其各个部分在纹理空间中不重叠。纹理空间中的最终元素称为图表( charts )或外壳( shells )。最后,所有图表都打包到一个通用纹理中(下图)。
必须注意确保不仅图表不重叠,而且它们的过滤范围也必须分开。所有纹理像素都可以被访问,当渲染给定图表时(双线性过滤访问四个相邻纹理像素)应标记为已使用,因此没有其他图表与它们重叠。否则,图表之间可能会发生渗色,而其中一个图表上的灯光可能会在另一图表上可见。虽然对于光映射系统来说,提供用户控制的“gutter”表示光映射图表之间的间距是相当常见的,但这种分离是不必要的。可以使用一组特殊的规则通过在光照贴图空间中对其进行光栅化来自动确定图表的正确过滤范围。参考下图。 如果以此方式光栅化的shell不重叠,我们可以保证不会发生渗漏。
避免混合是mipmapping很少用于光照贴图的另一个原因。图表过滤足迹需要在所有mip级别上保持分开,这将导致shells之间的间距过大。
将图表最佳地打包到纹理中是一个完全NP问题,这意味着没有已知的算法可以生成具有多项式复杂度的理想解决方案。由于实时应用程序可能在单个纹理中包含成千上万个图表,因此所有现实世界的解决方案都使用微调的启发式方法和经过仔细优化的代码来快速生成打包。如果以后对光照贴图进行块压缩(第6.2.6节),则为了提高压缩质量,可能会向打包程序添加其他约束,以确保单个块仅包含相似的值。
光照贴图的一个常见问题是接缝( seams )(下图)。
由于将网格划分为图表,并且每个网格都是独立设置参数的,因此无法确保沿拆分边缘的照明在两侧完全相同。这表现为视觉上的不连续。如果手动拆分网格,则可以通过将网格拆分到不直接可见的区域来避免此问题。但是,这样做很费力,并且在自动生成参数化时无法应用。Iwanicki在最终的光照贴图上执行后处理,该过程会沿分割边缘修改纹理像素,以最大程度地减小两侧插值之间的差异。Liu和Ferguson等人通过等式约束沿边缘执行插值匹配,并求解最能保持平滑度的纹素值。另一种方法是在创建参数化和打包图表时考虑此约束。 Ray等人展示了如何使用保留网格的参数化( grid-preserving parameterization )来创建不受接缝瑕疵影响的光照贴图。
预先计算的照明也可以存储在网格的顶点处。缺点是照明的质量取决于网格的细分程度。 由于此决定通常是在创作的早期阶段做出的,因此很难确保网格上有足够的顶点以在所有预期的照明情况下看起来都不错。另外,曲面细分可能很昂贵。如果网格细密地细分,则照明信号将被过采样。如果使用存储光照的定向方法,则整个表示需要通过GPU在顶点之间插值,并传递到像素着色器阶段来执行照明计算。在顶点着色器和像素着色器之间传递如此多的参数非常少见,并且会产生无法优化现代GPU的工作负载,从而导致效率低下和性能降低。由于所有这些原因,很少使用在顶点上存储预先计算的光照。
即使在曲面上需要有关入射辐射的信息(第14章中讨论的体积渲染除外),我们也可以按体积进行预先计算和存储。 这样做,可以在空间中的任意点查询照明,从而为预计算阶段场景中不存在的对象提供照明。 但是请注意,这些对象将无法正确反射或遮挡照明。
Greger等人提出了体积辐照度( irradiance volume ),它代表了五维(三个空间和两个方向)的辐照度函数,并具有一个稀疏的辐照环境贴图空间采样。即,空间中存在三维网格,并且在每个网格点处都有一个辐照环境贴图。动态对象根据最接近的贴图对辐照度值进行插值。Greger等人使用两级自适应网格进行空间采样,但是也可以使用其他体积数据结构,例如八叉树。
在原始辐照度体积中,Greger等人以较小的纹理将每个采样点的辐照度存储起来,但是无法在GPU上有效过滤此表示方法。如今,体积照明数据通常存储在三维纹理中,因此可以使用GPU的加速过滤对体积进行采样。采样点处辐照度函数的最常见表示形式包括:
• 二阶和三阶的球谐(SH)更为常见,因为单个颜色通道所需的四个系数可以方便地打包为具有典型纹理格式的四个通道。
• 球形高斯 (Spherical Gaussians)
• 环境立方体 或 环境 dice。
即使在技术上能够表示球形辐照度,AHD编码也会产生分散注意力的瑕疵。如果使用SH,则球谐梯度可以进一步提高质量。 以上所有表示已成功用于许多游戏中。
Evans描述了LittleBigPlanet中用于 辐射体积 的技巧。代替完整的辐照度图表示,平均辐照度存储在每个点上。根据辐照场的梯度,即场变化最快的方向,计算出近似的方向性因子。代替精准地计算梯度,梯度和表面法线n之间的点积是通过获取两个辐照场样本来计算的,一个在表面点p,另一个在沿n方向稍微偏移的点,然后从另一个中减去一个。这种近似表示的动机是动态计算LittleBigPlanet中的辐照量。
辐照度体积也可以用于为静态表面提供照明。这样做的优点是不必为光照贴图提供单独的参数设置。该技术也不会产生接缝。静态和动态对象都可以使用相同的表示形式,从而使两种类型的几何图形之间的照明保持一致。体积表示法可方便地用于延迟着色(第20.1节),其中所有照明都可以在一次pass中执行。主要缺点是内存消耗。光照贴图使用的内存量与分辨率的平方成正比。 对于常规的体积结构,它随立方体一起增长。因此,将较低的分辨率用于网格体积表示。适应性,分层形式的照明体积具有更好的特性,但是与光照贴图相比,它们仍然存储更多的数据。它们也比具有规则间距的网格要慢,因为额外的间接调用会在着色器代码中创建负载依赖关系,这可能导致停顿并降低执行速度。
在体积结构中存储表面照明有些棘手。有时具有不同照明特性的多个表面可以占据同一体素,因此不清楚应该存储哪些数据。从此类体素采样时,照明经常不正确。这种情况尤其经常发生在明亮的室外和黑暗的室内之间的墙壁附近,并导致外面的黑暗patches或里面的明亮patches。对此的解决方法是使体素大小足够小,以至于永远不会跨越此类边界,但是由于所需的数据量,通常这是不切实际的。解决该问题的最常见方法是沿法线移动采样位置一定量,或者调整插值期间使用的三线性混合权重。这通常是不完善的,可能需要手动调整几何形状以掩盖问题。Hooker在辐照体积上添加了额外的剪切平面,从而将它们的影响限制在凸形多边形的内部。Kontkanen和Laine讨论了各种减少混合的策略。
保持照明的体积结构不必是规则的。一种受欢迎的选择是将其存储在不规则的点云中,然后将其连接以形成Delaunay四面体化(下图)。
这种方法由Cupisz推广。要查找照明,我们首先找到采样位置所在的四面体。这是一个迭代的过程,可能会有些昂贵。我们遍历网格,在相邻单元之间移动。查找点相对于当前四面体角的重心坐标用于选择下一步要访问的邻居(下图)。因为典型的场景可能包含数千个存储照明的位置,所以此过程可能很耗时。为了加快速度,我们可以在上一帧中记录用于查找的四面体(如果可能),或者使用简单的立体数据结构为场景中的任意点提供良好的“起始四面体”。
找到合适的四面体后,使用已经可用的重心坐标对存储在其四角的照明进行插值。GPU不会加速此操作,但是它只需要四个值即可进行插值,而不是网格上三线性插值所需的八个值。
可以手动或自动放置照明预先计算和存储的位置。当它们探测(或采样)照明信号时,它们通常被称为光照探头( lighting probes )或照明探头( light probes )。该术语不应与“light probe”(第10.4.2节)混淆,后者是环境地图中记录的远处照明。
从四面体网格采样的照明质量高度依赖于该网格的结构,而不仅取决于 probe 的整体密度。如果它们分布不均匀,则生成的网格可以包含生成视觉瑕疵的细长的四面体。如果用手放置探针,可以轻松地纠正问题,但这仍然是手动过程。 四面体的结构与场景几何的结构无关,因此,如果处理不当,灯光将会在整个墙壁上插值,就像辐照体积一样,并生成混色瑕疵。在手动放置探头的情况下,可能要求用户插入其他探头以阻止这种情况的发生。使用自动放置探针时,可以将某种形式的可见性信息添加到探针或四面体中,以将其影响限制在仅相关区域。
通常,对静态和动态几何体使用不同的照明存储方法。例如,静态网格物体可以使用光照贴图,而动态对象可以从体积结构中获取光照信息。 尽管很流行,但该方案会在不同类型的几何外观之间造成不一致。 其中一些差异可以通过正则化来消除,其中照明信息在表示之间是平均的。
烘烤光照时,仅在真正有效的地方计算它们的值时需要注意。网格常常是不完美的。某些顶点可以放置在几何体内部,或者网格的某些部分可以自相交。如果我们在这些有缺陷的位置计算入射辐射,结果将是不正确的。他们将导致不想要的变暗或者混合不正确的照明无阴影。Kontkanen,Laine,Iwanicki和Sloan讨论了可用于丢弃无效样本的不同启发式方法。
环境和方向遮挡信号共享漫反射照明的许多空间特征。如第11.3.4节所述,上述所有方法也可以用于存储它们。
11.5.5 Dynamic Diffuse Global Illumination
即使预计算的照明可以产生令人印象深刻的效果,但其主要优点也是主要缺点--需要预先计算。这样的离线过程可能很漫长。在典型的游戏关卡中,灯光烘烤要花费多个小时并不罕见。由于照明计算需要很长时间,因此通常会迫使艺术家同时在多个level上工作,以避免在等待烘焙完成时停止工作。反过来,这通常会导致用于渲染的资源过多,并使烘焙花费更长的时间。该循环会严重影响生产率并导致挫败感。 在某些情况下,甚至无法预先计算照明,因为几何图形会在运行时更改或由用户在某种程度上创建。
已经开发了几种方法来模拟动态环境中的全局照明。它们不需要任何预处理,或者准备阶段足够快以至于每帧都可以执行。
在全动态环境中模拟全局照明的最早方法之一是基于“即时辐射度(Instant Radiosity)”。尽管名称如此,该方法与辐射度算法几乎没有共同之处。在其中,光线从光源向外投射。对于光线照射的每个位置,都会放置一个光,表示该表面元素的间接照明。这些光源称为虚拟点光源( virtual point lights )(VPL)。 利用这个想法,Tabellion和Lamorlette开发了一种在《怪物史莱克2》的制作过程中使用的方法,该方法执行场景表面的直接光照pass并将结果存储在纹理中。然后,在渲染过程中,该方法跟踪光线并使用缓存的光照来创建一反射间接照明。 Tabellion和Lamorlette表明,在许多情况下,一次反射足以产生令人信服的结果。这虽然是一种离线方法,但它启发了Dachsbacher和Stamminger并提出的一种称为反射阴影贴图( reflflective shadow maps )(RSM)的方法。
与常规阴影贴图(第7.4节)相似,反射阴影贴图是从光的角度渲染的。除了深度之外,它们还存储有关可见表面的其他信息,例如反射率,法线和直接照明(磁通量)。在执行最终着色时,将RSM的纹素视为点光源,以提供间接照明的单次反射。因为典型的RSM包含成千上万个像素,所以使用重要性驱动的启发式算法,这样只需要选择其中的一个子集。Dachsbacher和Stamminger随后展示了如何通过逆转过程来优化该方法。与其从每个着色点的RSM中选择相关纹理,不如根据整个RSM创建一定数量的灯光并在屏幕空间中对其进行分割(第13.9节)。
该方法的主要缺点是它不能为间接照明提供遮挡。虽然这是一个很大的近似值,但结果似乎是合理的,并且对于许多应用程序都是可以接受的。
为了获得高质量的结果并在灯光移动期间保持临时稳定性,需要创建大量的间接照明。 如果创建的间接照明太少,它们将在重新生成RSM时迅速改变其位置,并导致闪烁的瑕疵。另一方面,从性能的角度来看,具有太多的间接照明是具有挑战性的。Xu描述了该方法如何在“神秘海域4”游戏中实现。为了不影响性能,他每个像素使用少量(16)的光,但在几个帧上循环使用他们不同的集合,并在时间上过滤结果(下图)。
已经提出了不同的方法来解决间接遮挡的缺点。Laine等人将双抛物线阴影贴图用于间接光照,但将它们逐步添加到场景中,因此在任何单帧中,仅渲染了少数阴影贴图。 Ritschel等人使用简化的,基于点的场景表示方式来渲染大量不完美的阴影贴图。 这种贴图很小,直接使用时会包含很多缺陷,但是在简单过滤之后,可以提供足够的保真度,从而为间接照明提供适当的遮挡效果。
一些游戏使用了与这些解决方案有关的方法。 dust 514呈现一个自上而下的世界视图,需要时最多具有四个独立的图层。这些生成的纹理用于执行间接照明的收集,非常类似于Tabellion和Lamorlette的方法。 在Kite演示中,使用类似的方法从地形提供间接照明,在虚幻引擎中展示。
11.5.6 Light Propagation Volumes
辐射传递理论是对电磁辐射如何通过介质传播进行建模的一般方法。 它说明了散射,自发射和吸收。尽管实时图形努力显示所有这些效果,但除了最简单的情况以外,用于这些模拟方法的数量级太过昂贵,无法直接应用于渲染。 但是,已证明该领域中使用的某些技术在实时图形中很有用。
Kaplanyan提出的光传播体积( Light propagation volumes )(LPV)从辐射传递中的离散纵坐标方法( discrete ordinate methods )中汲取了灵感。用他的方法,将场景离散为三维单元的规则网格。每个单元将保持流经它的辐射的方向分布。 他对这些数据使用二阶球谐函数。第一步,将光注入包含直接照亮表面的单元。可以访问反射阴影图以找到这些像元,但是也可以使用任何其他方法。注入的光是从照亮表面反射的辐射。这样,它围绕着法线形成了一个背向表面的分布,并从材质的颜色中获取了颜色。接下来,照明被传播。每个单元分析其邻居的辐射场。然后,它修改自己的分布,以考虑从所有方向到达的辐射。在单个步骤中,辐射仅在单个单元格的距离上传播。 需要多次迭代才能进一步分发它(下图)。
该方法的重要优点是,它为每个单元生成一个完整的辐射场。这意味着我们也可以使用任意BRDF进行着色,即使使用二阶球谐函数时光泽BRDF的反射质量将相当的低。Kaplanyan显示了同时具有漫反射和反射表面的示例。
为了允许光在更大的距离上传播,并增加体积所覆盖的区域,同时保持合理的内存使用,Kaplanyan和Dachsbacher开发了该方法的级联( cascaded )变体。他们不使用具有统一大小的单元格的单个体积,而是使用一组这样的单元格,它们的单元格越来越大,彼此嵌套。照明被注入所有级别并独立传播。在查找过程中,它们选择了给定位置可用的最详细级别。
原始实现未考虑间接照明的任何遮挡。经过修改的方法使用了反射阴影贴图的深度信息以及相机位置的深度缓冲区,以将有关光阻挡者的信息添加到体积中。该信息不完整,但是在预处理过程中也可以将场景体素化,因此可以使用更精确的表示。
该方法存在其他体积方法的问题,其中最大的是混合。不幸的是,提高网格分辨率以解决该问题会导致其他问题。当使用较小的单元大小时,需要更多的迭代才能在相同的世界空间距离上传播光,这使该方法的成本大大增加。在网格分辨率和性能之间找到平衡并非易事。该方法还存在抗锯齿问题。网格的有限分辨率与辐射的粗略方向表示相结合,会导致信号在相邻单元之间移动时质量下降。在多次迭代之后,空间瑕疵(例如对角条纹)可能会出现在解决方案中。这些问题中的一些可以通过在传播pass之后执行空间过滤来消除。
11.5.7 Voxel-Based Methods
由Crassin引入的体素圆锥跟踪全局照明( voxel cone tracing global illumination )(VXGI)也基于体素化的场景表示。几何体本身以稀疏体素八叉树( sparse voxel octree )的形式存储,如第13.10节所述。关键概念是这种结构提供了场景的类似于mipmap的表示形式,因此可以快速测试一个体积空间的遮挡。体素还包含关于它们所代表的几何形状反射的光量的信息。它以定向形式存储,因为辐射在六个主要方向上被反射。 使用反射阴影贴图,直接照明首先被注入到八叉树的最低级别。 然后将其向上传播到层次结构中。
八叉树用于计算入射辐射。理想情况下,我们将跟踪射线以获取来自特定方向的辐射的计算值。但是,这样做需要许多光线,因此,将这些光线的整个束近似用沿其平均方向跟踪的圆锥近似,只返回一个值。精确测试圆锥体是否与八叉树相交并不是一件容易的事,因此这个操作可以近似为一系列的通过沿圆锥体轴对树进行查找。每次查找都会读取树的级别,该级别的节点大小与给定点处圆锥体的横截面相对应。查找提供了在圆锥体原点方向上反射的已过滤辐射率,以及几何所占查找踪迹的百分比。该信息用于以类似于alpha混合的方式,衰减来自后续点的照明。跟踪整个圆锥的遮挡。在每个步骤中,它都会减少,以解决当前样本被几何图形占用的百分比。 累积辐射率时,首先将其乘以组合的遮挡因子(下图)。
此策略无法检测到由于多个部分遮挡而导致的完全遮挡,但是结果仍然令人相信。
为了计算漫反射照明,将跟踪多个圆锥体。生成和cast的数量是性能和精度之间的折衷。跟踪更多的圆锥体可以提供更高质量的结果,但要花费更多的时间。假定余弦项在整个圆锥上是恒定的,因此可以将该项从反射方程积分中分解出来。这样做使漫反射照明的计算像计算圆锥轨迹返回的值的加权和一样简单。
如Mittring所述,该方法是在Unreal Engine的原型版本中实现的。他给出了开发人员需要进行的一些优化,以使其能够在完整渲染管道中运行。 这些改进包括以较低的分辨率执行迹线并在空间上分布视锥。 进行此过程是为了使每个像素仅跟踪一个圆锥体。 通过对屏幕空间中的结果进行过滤,可以获得漫反射的全部辐射。
使用稀疏八叉树存储光照的主要问题是查找成本高。查找包含给定位置的叶节点对应于一系列内存查找,并与确定要遍历的子树的简单逻辑交错。典型的内存读取可能需要数百个周期。 GPU试图通过并行执行多组着色器线程(warps or wavefronts)来隐藏此延迟(第3章)。在任何给定时间即使只有一组执行ALU操作的线程,当它需要等待内存读取时,另一组也会代替它。可以同时激活的warps的数量由不同因素决定,但所有因素都与单个组使用的资源量有关(第23.3节)。在遍历分层数据结构时,大部分时间都花在等待从内存中取出下一个节点。但是,在此等待期间将执行的其他warps也很可能也会执行内存读取。由于与内存访问次数相比,ALU的工作量很少,并且由于运行中的warps总数有限,因此所有组都在等待内存而没有执行实际工作的情况很常见。
具有大量的停滞warp会导致性能不理想,尝试减轻这些低效率的方法现在已经开发出了。McLaren用一组级联的三维纹理代替八叉树,就像级联的光传播体积一样(第11.5.6节)。它们具有相同的尺寸,但覆盖范围逐渐扩大。这样,读取数据只需要一个常规的纹理查找就可以完成——不需要依赖的读取。纹理中存储的数据与稀疏体素八叉树中的数据相同。它们包含六个方向的反照率,占用率和反射光信息。由于级联的位置随相机的移动而变化,因此对象会不断地进出高分辨率区域。 由于内存限制,不可能一直保持这些体素化版本,因此它们在需要时根据需要进行体素化。McLaren还描述了许多优化措施,使该技术适用于30 FPS游戏《明天的孩子》(下图)。
11.5.8 Screen-Space Methods
就像屏幕空间环境光遮挡一样(第11.3.6节),仅使用存储在屏幕位置的表面值可以模拟某些漫反射的全局照明效果。 这些方法没有SSAO流行,主要是因为有限的可用数据量导致的瑕疵更加明显。诸如混色之类的效果是强直射光照亮了颜色相当恒定的大区域的结果。这样的表面通常不可能完全适合视图。 这种情况使得反射光的数量在很大程度上取决于当前取景,并且会随着相机的移动而波动。 出于这个原因,屏幕空间方法只用于在一个精细的尺度上增加一些其他的解决方案,超出了主要算法所能达到的分辨率。游戏Quantum Break中使用了这种类型的系统。 辐照量用于模拟大规模全局照明效果,并且屏幕空间解决方案可在有限距离内提供反射光。
11.5.9 Other Methods
Bunnell的计算环境光遮挡的方法(第11.3.5节)还允许动态计算全局照明效果。通过存储有关每个圆盘的反射辐射率的信息来增强场景的基于点的表示(第11.3.5节)。在收集步骤中,不仅可以收集遮挡,还可以在每个收集位置构造一个完整的入射辐射函数。就像环境光遮挡一样,必须执行后续步骤以消除来自被遮挡的圆盘的光线。