局部光照
- 面光源
- 光泽材质
- 一般光源形状
- 环境光照
- 球面函数和半球函数
- 简单表格形式
- 球面基底
- 球面径向基函数
- 球面高斯函数
- 球谐函数
- 其他球面表示
- 半球基底
- AHD 基底
- 辐射法向映射/《半条命2 》基底
- 半球谐波 / H-Basis
在第9章中,我们讨论了基于物理的材质的相关理论,以及如何使用精确光源来计算它们。有了这些前置内容,我们就可以通过模拟光线与表面之间的相互作用,来进行着色计算,以便计算这个着色点在给定方向上,向虚拟相机发出了多少radiance。这个光谱radiance是场景参考的像素颜色,它最终会被转换为图像中给定像素的显示参考颜色。
实际上,我们需要考虑的交互作用从来都不是发生在某一个点上的。在章节9中,我们已经看到,为了正确计算着色效果,我们必须要对整个像素足迹(pixel footprint,即屏幕像素区域在表面上的投影面积)上的表面BRDF进行积分。这个积分的过程也可以被认为是一种抗锯齿方法。着色函数一般都是一个连续函数,并在一定区域范围内进行积分,我们并不会使用一个无上限的采样频率来对着色函数进行采样,相反我们会对其进行预积分。
到目前为止,我们只描述了点光源和方向光的效果,在这种光照条件下,表面只能接收来自少数离散方向上的光线,这种光照条件是不完整的。但是实际上,表面可以接收来自任意入射方向的光线。户外场景也不仅仅只是由太阳光(方向光)照亮的,如果只由太阳光照亮的话,那么所有处于阴影区域或者背对太阳的表面将会是纯黑的。因为太阳光会在大气层中发生散射,因此天空同样也是一个十分重要的光源。从月球的照片就可以看出天光的重要性,由于月球没有大气层,因此不存在天光,如图10.1所示。
图10.1:在月球上拍摄的图像,由于缺乏散射太阳光的大气层,因此月球上并没有天光。这张图片展示了一个场景只被直接光源照亮时的样子,请注意在背对太阳的表面处,这些表面具有漆黑的阴影,同时没有任何表面细节。这张照片展示的是在阿波罗15号执行任务期间,宇航员Astronaut James B. Irwin站在月球漫游车旁边,图片前景区域的阴影来自于登月舱。这张照片由宇航员David R. Scott拍摄,他是此次任务的指挥官。
在阴天,黄昏或者黎明时分,室外的光照基本都来自于天光。即使是在晴朗的日子里,从地球上看向太阳,太阳也具有一定的面积,其所占据的视野区域是一个圆锥体,因此太阳并不是一个无穷小的光源。奇怪的是,虽然太阳和月球的尺寸差异巨大,太阳半径要比月球半径大两个数量级,但是从地球上看,它们基本具有相似的大小,二者直径所占据的视野角度大约都为半度。
在现实中,光源从来都不是精确的,但是在某些情况下,使用无穷小的实体来作为廉价近似,或者作为完整模型中的一部分是十分有用的。为了构建一个更加真实的光照模型,我们需要在表面着色点的半球范围内,对来自入射方向的BRDF进行积分。在实时渲染中,我们更喜欢通过找到方程的封闭形式解或者近似值,来求解渲染方程所必须的积分。我们通常都会避免对多个样本(光线)的结果进行平均(蒙特卡洛方法),因为这种方法往往会很慢,如图10.2所示。
图10.2:左图中展示的是我们在第9章中所看到的,对表面区域和定点光源进行积分。右图中展示的则是本章节的目标,我们将对着色方程和数学表达进行扩展,从而将光源表面上的积分考虑在内。
本章节将对这些解决方案进行探索和讨论,尤其是我们想通过计算各种非精确光源的BRDF,来对之前所介绍的着色模型进行一些扩展。通常来说,为了找到一种廉价的解决方案(或者是任意的解决方案),我们需要对光源或者BRDF进行近似,有时候也会对二者同时进行近似。在一个感知框架中来评估最终的着色结果是十分重要的,这要求我们了解最终图像中哪些视觉元素更加重要,从而来为这些元素分配更多的精力和计算资源。
在本章节的最开始部分,我们将对面光源的公式进行解析积分。面光源将会成为场景中的主要光源,它负责大部分的直接光照强度,因此在计算面光源效果的时候,我们需要保留之前所有选择的材质属性。我们还会计算面光源的阴影,因为漏光会导致明显的视觉瑕疵。然后我们会对更加一般的光照环境的表示方法进行研究,这些光照环境由入射半球上的任意分布组成。在这些情况下,我们通常会使用一些更加近似的解决方案。环境光照通常用于表示大型、复杂但是不太强烈的光源,例如:包括来自天空和云的散射光;场景中大型物体反射的间接光(indirect light);以及一些很暗的面光源的直接光照。这样的近似光源对于正确的图像白平衡十分重要,不然画面会显得太暗。即使我们在这里考虑了间接光照对场景照明的影响,但是我们仍然没有进入全局光照的领域(第11章),全局光照还依赖于场景中其他表面的显式知识和信息。
面光源
在第9章中,我们描述了理想的无穷小光源:精确光源和方向光。图10.3展示了一个表面着色点上的入射半球,以及无穷小光源和非零面光源(area light source)之间的差异。其中左侧光源使用了章节9中讨论的定义,它从单一方向 l c \mathbf{l}_{c} lc照射到表面上,其亮度由颜色 c l i g h t \mathbf{c}_{light} clight进行表示,这个颜色代表了从一个正对光源的白色Lambertian表面,所反射出的radiance。点光源或者方向光在方向 v \mathbf{v} v上,对出射radiance L o ( v ) L_{o}(\mathbf{v}) Lo(v)的贡献为 π f ( l c , v ) c light ( n ⋅ l c ) + \pi f\left(\mathbf{l}_{c}, \mathbf{v}\right) \mathbf{c}_{\text {light }}\left(\mathbf{n} \cdot \mathbf{l}_{c}\right)^{+} πf(lc,v)clight (n⋅lc)+,其中符号 x + x^{+} x+代表了将负数限制到0。相对地,面光源的亮度由其radiance L l L_{l} Ll来进行表示,并且面光源与表面着色点位置之间会形成一个立体角,记为 ω l ω_l ωl,此时这个面光源在方向 v \mathbf{v} v上,对出射radiance的贡献是 f ( l , v ) L l ( n ⋅ l ) + f(\mathbf{l}, \mathbf{v}) L_{l}(\mathbf{n} \cdot \mathbf{l})^{+} f(l,v)Ll(n⋅l)+在立体角 ω l ω_l ωl上的积分。
图10.3:被光源照亮的表面,光源的入射方向位于由表面法线 n \mathbf{n} n所定义的半球范围内。左图中的光源是无穷小的;右图中的光源则被建模为一个面光源。
对无穷小光源的基本近似可以表示为如下形式:
L o ( v ) = ∫ l ∈ ω l f ( l , v ) L l ( n ⋅ l ) + d l ≈ π f ( l c , v ) c l i g h t ( n ⋅ l c ) + (10.1) L_{o}(\mathbf{v})=\int_{\mathbf{l} \in \omega_{l}} f(\mathbf{l}, \mathbf{v}) L_{l}(\mathbf{n} \cdot \mathbf{l})^{+} d \mathbf{l} \approx \pi f\left(\mathbf{l}_{c}, \mathbf{v}\right) \mathbf{c}_{\mathrm{light}}\left(\mathbf{n} \cdot \mathbf{l}_{c}\right)^{+} \tag{10.1} Lo(v)=∫l∈ωlf(l,v)Ll(n⋅l)+dl≈πf(lc,v)clight(n⋅lc)+(10.1)
而面光源对表面着色点的照明贡献量,与radiance( L l L_{l} Ll)和从该位置所看到的光源尺寸( ω l ω_l ωl)有关。正如我们在章节9中所看到的,点光源和方向光是一种抽象近似,它在现实中并不存在,因为它们的可见立体角为0,这意味着在单位面积上的radiance无穷大。理解这种由近似所引入的视觉误差,将有助于知道何时能够使用这种近似方法,以及在不能使用这种近似方法的时候,我们可以采取什么方法来进行替代。这些近似误差主要取决于两个因素:第一个是光源的尺寸有多大,即从着色点看向光源,该光源会覆盖多大的立体角;第二个则是表面的光泽程度。
图10.4展示了一个表面上的高光大小和高光形状,是如何受到表面材质的粗糙度和光源大小的影响的。对于一个很小的光源,它相对于相机视野只占据了一个很小的立体角,因此产生的误差也很小。相对于光泽表面来说,粗糙表面更加能够显示出光源尺寸对高光的影响。一般来说,面向表面点的面光源,其发光情况与表面BRDF的镜面波瓣都是球面函数。如果考虑哪些方向集合对这两个函数的贡献最显著,我们可以得到两个立体角。误差的决定因素与面光源发射角和BRDF镜面高光立体角的相对大小成正比。
图10.4:球体使用了GGX BRDF来进行渲染,从左到右,球体材质的表面粗糙度递增。最右侧图像和最左侧图像是一样的,只是将其垂直翻转了过来。请注意,在低粗糙度的材质上,由大圆盘灯引起的高光和着色效果,与较小光源在高粗糙度材质上所引起的高光效果,在视觉上面十分相似。
最后请注意观察,面光源的高光效果,可以通过使用精确光源并增加表面材质的粗糙度来进行近似。这个观察结果对于推导面光源积分的低成本近似十分有用,这也解释了为什么在实践中,许多实时渲染系统只使用精确光源就能够产生合理的结果:因为艺术家可以通过手动调整材质,来对误差进行一些补偿(compensate)。但是这样做肯定是有坏处的,因为它将材质属性与特定的光照设置耦合在了一起,当场景中的光照条件发生改变的时候,以这种方式生成的光影和画面看起来就不太正确了。
对于Lambertian表面这种特殊情况,直接使用点光源来表示面光源是很精确的。对于这样的表面,其出射的radiance与irradiance成正比:
L o ( v ) = ρ s s π E (10.2) L_{o}(\mathbf{v})=\frac{\rho_{\mathrm{ss}}}{\pi} E \tag{10.2} Lo(v)=πρssE(10.2)
方程中的 ρ s s \rho_{\mathrm{ss}} ρss是表面的次表面反照率(subsurface albedo),或者叫做漫反射颜色(diffuse color)。有了这个关系,我们可以对方程10.1进行等价变换,从而计算irradiance,这样要简单得多:
E = ∫ l ∈ ω l L l ( n ⋅ l ) + d l ≈ π c light ( n ⋅ l c ) + (10.3) E=\int_{\mathbf{l} \in \omega_{l}} L_{l}(\mathbf{n} \cdot \mathbf{l})^{+} d \mathbf{l} \approx \pi \mathbf{c}_{\text {light }}\left(\mathbf{n} \cdot \mathbf{l}_{c}\right)^{+} \tag{10.3} E=∫l∈ωlLl(n⋅l)+dl≈πclight (n⋅lc)+(10.3)
向量irradiance(vector irradiance)的概念对于当面光源存在时,理解irradiance的行为十分有用。向量irradiance的概念由Gershun 提出,他将其称之为光源向量(light vector),Arvo 将这个概念进一步推广。利用向量irradiance,可以将任意大小和任意形状的面光源,精确地转换为点光源或者方向光。
想象一个分布为 L i L_i Li的radiance进入到了空间中的点 p \mathbf{p} p,如图10.5所示。现在我们假设 L i L_i Li与光线的波长无关,因此可以将其表示为一个标量。对于每个以入射方向 l \mathbf{l} l为中心的、无限小的立体角 d l d\mathbf{l} dl,我们都构建一个与入射方向 l \mathbf{l} l平行的向量,其长度等于从该方向入射的radiance(标量)与 d l d\mathbf{l} dl的乘积。再对所有构建的向量进行求和(积分),最终可以得到向量irradiance e \mathbf{e} e,这个过程的数学形式如下:
e ( p ) = ∫ l ∈ Θ L i ( p , l ) l d l (10.4) \mathbf{e}(\mathbf{p})=\int_{\mathbf{l} \in \Theta} L_{i}(\mathbf{p}, \mathbf{l}) \mathbf{l} d \mathbf{l} \tag{10.4} e(p)=∫l∈ΘLi(p,l)ldl(10.4)
其中的 Θ \Theta Θ表示在整个球面方向上进行积分。
图10.5:向量irradiance的计算过程。左图:点 p \mathbf{p} p被各种具有形状、大小、radiance分布的光源所包围,其中黄色的明亮程度代表了光源发射出的radiance数量。以点 p \mathbf{p} p为起点的橙色箭头代表了向量,它指向任何存在入射radiance的方向,每个向量的长度,等于来自该方向上的radiance乘以箭头所覆盖的无限小的立体角。原则上应当存在无穷多个箭头。右图:向量irradiance(橙色大箭头)是左图中所有橙色向量的总和。向量irradiance可以用来计算任意平面在点 p \mathbf{p} p处的净irradiance。
向量irradiance e \mathbf{e} e可以通过与任意平面的表面法线进行点乘运算,从而获得点 p \mathbf{p} p处的净irradiance,其数学表达如下:
E ( p , n ) − E ( p , − n ) = n ⋅ e ( p ) (10.5) E(\mathbf{p}, \mathbf{n})-E(\mathbf{p},-\mathbf{n})=\mathbf{n} \cdot \mathbf{e}(\mathbf{p}) \tag{10.5} E(p,n)−E(p,−n)=n⋅e(p)(10.5)
其中 n \mathbf{n} n是平面的表面法线。通过平面的净irradiance,是指流经平面“正面”(表面法线 n \mathbf{n} n所指向的方向)和流经平面“背面”的irradiance之差。虽然说净irradiance本身对于着色计算来说没有什么用处,但是如果说没有任何radiance被发射通过平面的“背面”的话(换句话说,对于所分析的光线分布,光线方向 l \mathbf{l} l和表面法线 n \mathbf{n} n之间的夹角都不会超过 9 0 ∘ 90^{\circ} 90∘,所有的入射光线都来自于着色点的正半球方向),即 E ( p , − n ) = 0 E(\mathbf{p},-\mathbf{n})=0 E(p,−n)=0,那么此时有:
E ( p , n ) = n ⋅ e ( p ) (10.6) E(\mathbf{p},\mathbf{n}) = \mathbf{n \cdot e (p)} \tag{10.6} E(p,n)=n⋅e(p)(10.6)
单个面光源的向量irradiance可以实用方程10.6中的方法,来照亮具有任意法线 n \mathbf{n} n的Lambertian表面,只要这个面光源整体位于表面的正面方向即可。也就是说面光源上任意一点与着色点之间的连线,和表面法线之间的夹角都不超过 9 0 ∘ 90^{\circ} 90∘,如图10.6所示。
图10.6:单个面光源的向量irradiance。左图中的箭头代表用于计算向量irradiance的单个向量。右图中的橙色大箭头代表的就是向量irradiance e \mathbf{e} e;红色虚线代表了光源的范围;红色向量(每个红色向量都垂直于一条红色虚线)定义了表面法线的极限范围,位于这个范围外的表面法线,将会与面光源的部分区域呈大于 9 0 ∘ 90^{\circ} 90∘的夹角,这样的法线无法使用 e \mathbf{e} e来正确计算它们的irradiance。
如果入射radiance L i L_i Li与波长无关的假设不成立的话,那么在一般情况下,我们就不能再定义单个向量irradiance e \mathbf{e} e了。然而,彩色光通常在所有点上都具有相同的相对光谱分布,这意味着我们可以将 L i L_i Li分解为颜色 c ′ \mathbf{c}^{\prime} c′,以及与波长无关的radiance分布 L i ′ L_i^{\prime} Li′。在这种情况下,我们可以计算 L i ′ L_i^{\prime} Li′的向量irradiance e \mathbf{e} e,并对方程10.6进行一些扩展,将 n ⋅ e \mathbf{n} \cdot \mathbf{e} n⋅e乘上颜色 c ′ \mathbf{c}^{\prime} c′。这样做的结果与计算方向光irradiance的方程相同,只是做了以下替换:
l c = e ( p ) ∥ e ( p ) ∥ , c light = c ′ ∥ e ( p ) ∥ π . (10.7) \begin{aligned} \mathbf{l}_{c} & =\frac{\mathbf{e}(\mathbf{p})}{\|\mathbf{e}(\mathbf{p})\|}, \\ \mathbf{c}_{\text {light }} & =\mathbf{c}^{\prime} \frac{\|\mathbf{e}(\mathbf{p})\|}{\pi} .\end{aligned} \tag{10.7} lcclight =∥e(p)∥e(p),=c′π∥e(p)∥.(10.7)
到此为止,我们已经可以将任意形状和任意大小的面光源转换为方向光,同时不会引入任何误差。
对于一些简单情况,用于求取向量irradiance的方程10.4可以求出解析解。例如:想象现在有一个以 p l \mathbf{p}_l pl为中心、半径为 r l r_l rl的球形光源。球面上的每一点都会向各个方向发出具有恒定radiance L l L_l Ll的光线。对于这种光源,将方程10.4和方程10.7联立,可以获得如下结果:
l c = p l − p ∥ p l − p ∥ , c light = r l 2 ∥ p l − p ∥ 2 L l . (10.8) \begin{aligned} \mathbf{l}_{c} & =\frac{\mathbf{p}_{l}-\mathbf{p}}{\left\|\mathbf{p}_{l}-\mathbf{p}\right\|}, \\ \mathbf{c}_{\text {light }} & =\frac{r_{l}^{2}}{\left\|\mathbf{p}_{l}-\mathbf{p}\right\|^{2}} L_{l} .\end{aligned} \tag{10.8} lcclight =∥pl−p∥pl−p,=∥pl−p∥2rl2Ll.(10.8)
上述方程,与具有 c light 0 = L l , r 0 = r l \mathbf{c}_{\text {light }_{0}}=L_{l}, r_{0}=r_{l} clight 0=Ll,r0=rl和标准距离平方反比衰减函数的泛光灯完全相同。可以对这个衰减函数进行一些修正,使得光线从球体表面才开始发生衰减,并在光源的最大影响距离处衰减到0。
在没有来自“背面”irradiance的情况下,上述所描述的一切都是正确的。另一种思考方式是,面光源的任何部分都不能“位于地平线以下”,或者是被表面遮挡。我们可以将这个说法推广,对于表面而言,面光源和点光源之间的所有差异,都是由于遮挡差异所造成的。对于光线没有被遮挡的任意着色点,点光源的irradiance服从余弦衰减定律。Snyder推导出了一个考虑遮挡情况的球形光源的解析表达式,这个表达相当复杂。然而,由于这个表达式只和两个量有关( r / r l r/r_l r/rl,表面法线 n \mathbf{n} n和 l c \mathbf{l}_c lc之间的夹角 θ i θ_i θi),因此可以对其进行预计算,并存储在一个二维纹理中。Snyder还给出了两个适用于实时渲染的函数近似。
在图10.4中我们可以看到,对于较为粗糙的表面,面光源的光照效应其实不太明显。基于这一观察结果,我们可以使用一种不太物理正确,但是仍然有效的方法,来对Lambertian表面上的面光源效果进行模拟,这种方法叫做环绕光照(wrap lighting)。在这种方法中,首先会对 n ⋅ l \mathbf{n} \cdot \mathbf{l} n⋅l的结果进行一些简单的修改,然后再将其限制到0。Forsyth 给出了环绕光照的一种形式:
E = π c light ( ( n ⋅ l ) + k w r a p 1 + k w r a p ) + (10.9) E=\pi \mathbf{c}_{\text {light }}\left(\frac{(\mathbf{n} \cdot \mathbf{l})+k_{\mathrm{wrap}}}{1+k_{\mathrm{wrap}}}\right)^{+} \tag{10.9} E=πclight (1+kwrap(n⋅l)+kwrap)+(10.9)
其中 k w r a p k_{wrap} kwrap的取值范围为 [ 0 , 1 ] [0,1] [0,1],对于点光源而言, k w r a p = 0 k_{wrap}=0 kwrap=0;对于覆盖整个半球范围的面光源而言, k w r a p = 1 k_{wrap}=1 kwrap=1。Valve采用了另一种形式的环绕光照,来模仿大尺寸的面光源效果:
E = π c light ( ( n ⋅ l ) + 1 2 ) 2 (10.10) E=\pi \mathbf{c}_{\text {light }}\left(\frac{(\mathbf{n} \cdot \mathbf{l})+1}{2}\right)^{2} \tag{10.10} E=πclight (2(n⋅l)+1)2(10.10)
一般来说,如果我们要计算面光源的话,我们还应当对阴影计算进行一定的修改,如果我们不这样做,一些面光源的视觉效果可能会被强烈的阴影所抵消。正如我们在第7章中所讨论的,柔和的软阴影可能是面光源最明显的视觉效果。
光泽材质
面光源对非Lambertian表面的影响要更为复杂。Snyder推导出了一个球形光源的解,但是这个解仅适用于原始的反射向量Phong材质模型,并且极其复杂,在实际应用中需要对其进行近似。
面光源在光泽(glossy)表面上的主要视觉效果是高光,如图10.4所示。这个高光的大小和形状类似于产生该效果的面光源,高光的边缘则会根据该表面的粗糙度,被一定程度的模糊。基于这一观察结果,研究者提出了几个针对该效应的经验近似值,这些近似方法在实践中是相当令人信服的。例如:我们可以对高光计算的结果进行修改,将其加上一个截止阈值,从而生成一个大而平坦的高光区域。这可以有效地产生一个球面光源镜面反射的视错觉,如图10.7所示。
图10.7:面光源在光滑物体上强烈反射所产生的高光,高光的形状与面光源的形状相类似。左图中,通过限制Blinn-Phong着色器的高光阈值,来对这种视觉现象进行近似。右图中,使用未修改的Blinn-Phong着色器对物体进行渲染,以便进行比较。
在实时渲染中,大多数对面光源光照效果的实用近似,都是基于了这样的一个想法:为每个着色点都寻找一个等效的精确光源,从而模拟非无穷小光源的效果。这种方法经常被用于实时渲染中,以解决各种各样的问题。这与我们在第9章中,在表面像素足迹所覆盖的区域内,对BRDF进行积分的原理相同。这种方式所产生的近似值,其计算成本通常会很低,因为我们只需要修改着色方程的输入即可,不会引入任何其他额外的复杂性。由于背后的数学运算并没有发生改变,因此我们通常可以保证,在某些条件下,我们可以恢复对原始着色结果的计算,并保留其所有的属性。由于大多数渲染系统的着色代码都是基于精确光源的,因此用它们来实现面光源只会引入局部的代码变化。
第一个被开发出来的近似方法是Mittring在虚幻引擎的“Elemental demo”中所使用的粗糙度修正(roughness modification)。这个想法首先会找到一个圆锥体,其中包含了入射到表面半球范围内的大部分光源irradiance。然后我们在镜面波瓣的附近放置一个类似的圆锥体,它会包含“大部分”的BRDF,如图10.8所示。这两个圆锥体是半球上函数的替代品,它们各自包含了一组方向,在这组方向上,这两个函数的输出值都会大于给定的任意阈值。这样做之后,我们可以寻找一个新的BRDF波瓣,来近似光源和材质BRDF之间的卷积,这个新的BRDF波瓣具有不同的粗糙度,它同样有一个对应的圆锥体,这个圆锥体的立体角等于光源波瓣立体角和材质波瓣立体角的和。
图10.8:GGX BRDF和一个圆锥体,这个圆锥体包含了一组方向,其中镜面波瓣会在这组方向上反射大部分光源的入射radiance。
Karis 将Mittring所提出原理应用在了GGX/Trowbridge-Gereitz BRDF(章节9)和一个球面光源中,并对GGX的粗糙度参数 α g α_g αg进行了简单的修改:
α g ′ = ( α g + r l 2 ∥ p l − p ∥ ) ∓ \alpha_{g}^{\prime}=\left(\alpha_{g}+\frac{r_{l}}{2\left\|\mathbf{p}_{l}-\mathbf{p}\right\|}\right)^{\mp} αg′=(αg+2∥pl−p∥rl)∓
注意这里使用了章节1中介绍的符号 x ∓ x^{\mp} x∓,它表示将输入值限制到0-1之间。对于具有一定光泽的表面而言,这种近似方法的效果相当好,而且计算成本很低;但是对于闪亮的、几乎像镜子一样的材质来说就会失效。这种失效的原因是因为镜面波瓣总是光滑的,它无法模拟由面光源在表面上因尖锐反射所产生的锐利高光。此外,大多数微表面BRDF模型的波瓣并不是那么“紧凑”(即反射分布的扩散角度较大),同时会表现出一个较宽的衰减(高光拖尾),这使得粗糙度重映射的方法不太有效,如图10.9所示。
图10.9:球形光照。从左至右分别是:使用数值积分方法计算出来参考结果、粗糙度修正技术、代表性点技术。
除了改变材质的粗糙度之外,还有另一个思路:根据被着色的表面点来改变的光线方向,从而来表示面光源的照明效果。这种方法被称为代表性点技术(most representative point),它通过对光线向量进行修改,使其在面光源表面方向上,能够对着色表面产生最大的能量贡献,如图10.9最右侧所示。Picott 使用了光源表面上与反射光线夹角最小的点。Karis 对Picott的公式进行了改进,他将这个形成最小角度的点,近似为面光源到反射光线最近的点,从而进一步提高效率。他还提出了一个廉价的公式来对光线强度进行缩放,从而尽可能保持整体发射的能量,如图10.10所示。大多数代表性点的解都是很容易推导的,并且这种方法适用于各种几何形状的光源,因此对它们背后的理论进行一些了解是很重要的。这些方法的核心思路,类似于蒙特卡洛积分中重要性采样的思想,蒙特卡洛积分是指,我们通过在积分域上对样本结果进行平均,从而对定积分的值进行数值计算。为了更高效地做到这一点(使用较少的样本),我们可以尝试优先考虑那些对总体平均值具有较大贡献的样本。
图10.10:球的Karis代表性点近似。首先,计算反射光线上最接近球体中心 l \mathbf{l} l的点: p c r = ( l ⋅ r ) r − 1 \mathbf{p}_{\mathrm{cr}}=(\mathbf{l} \cdot \mathbf{r}) \mathbf{r}-1 pcr=(l⋅r)r−1。然后再计算球面上距离点 p c r \mathbf{p}_{\mathrm{cr}} pcr最近的点: p c s = l + p c r ⋅ min ( 1 , radius ∥ p c r ∥ ) \mathbf{p}_{\mathrm{cs}}=\mathbf{l}+\mathbf{p}_{\mathrm{cr}} \cdot \min \left(1, \frac{\text { radius }}{\left\|\mathbf{p}_{\mathrm{cr}}\right\|}\right) pcs=l+pcr⋅min(1,∥pcr∥ radius )
定积分的中值定理可以更加严格地证明其有效性的,它允许我们用函数的单次求值来代替该函数的积分,其数学表达如下:
∫ D f ( x ) d x = f ( c ) ∫ D 1 (10.11) \int_{D} f(x) d x=f(c) \int_{D} 1 \tag{10.11} ∫Df(x)dx=f(c)∫D1(10.11)
如果 f ( x ) f(x) f(x)在区域 D D D上是连续的,则 ∫ D 1 \int_{D} 1 ∫D1代表了该区域的面积,点 c ∈ D c\in D c∈D位于区域 D D D中函数最小值与最大值之间的连线上。对于光照,我们考虑的是BRDF与光源irradiance的乘积,这个乘积在被光照覆盖的半球面上的积分。通常我们会认为光源是均匀照射的,因此我们只需要考虑光线随距离的衰减即可,并且大多数近似方法还会假设区域 D D D在着色点位置上是完全可见的。即使有了上述这些假设,确定点 c c c和归一化系数 ∫ D 1 \int_{D} 1 ∫D1的计算成本仍然可能会很高,因此我们需要对其进行进一步的近似。
代表性点的解也可以通过它们对高光形状的影响来限定。在部分的表面着色点上,代表性点可能不会发生改变,因为反射向量位于面光源所覆盖的方向锥之外,对于这些区域,我们可以使用一个点光源来进行高效照明,因为高光的形状只取决于镜面波瓣的底层形状。而对于那些反射向量指向面光源的表面着色点,其代表性点将会不断变化,以便能够指向能量贡献最大的方向。这样做有效地扩展了镜面波瓣的峰值,使其“变宽”,其效果类似于图10.7左侧的硬阈值。
这个较宽的、恒定的高亮峰值,也是近似值中剩余的误差来源之一。在较为粗糙的表面上,面光源反射看起来要比真实值(ground-truth,即通过蒙特卡罗积分获得)更加“尖锐”,这是一种与粗糙修正技术过度模糊相反的视觉瑕疵。为了解决这个问题,Iwanicki和Pesce 将BRDF波瓣、软阈值、代表性点参数与缩放因子,拟合到通过数值积分计算而来的球形区域光照结果中,从而得到了近似结果。这些拟合的函数生成了一个参数表,这个参数表通过材质粗糙度、球形光源的半径、光源中心与表面法线之间的夹角、观察向量来进行索引。由于在着色器中直接使用这种多维查找表的开销很大,因此他们还提供了封闭形式的近似。最近,de Carpentier 推导出了一种改进的方程,这个方程对于基于微表面的BRDF,可以更好地保留掠射角度下球形面光源所生成的高光形状。该方法的原理是找到一个使得 n ⋅ h \mathbf{n} \cdot \mathbf{h} n⋅h最大化的代表性点,而不是原始方程中的 n ⋅ r \mathbf{n} \cdot \mathbf{r} n⋅r(这是通过Phong BRDF推导出的),这里的 n ⋅ h \mathbf{n} \cdot \mathbf{h} n⋅h是表面法线和半向量(光线方向-观察方向)之间的点积。
一般光源形状
到目前为止,我们介绍了几种方法,它们可以从均匀辐射的球形光源和任意的光泽BRDF中计算着色效果。其中的大多数都采用了各种近似策略,从而能够获得可以快速实时计算的数学方程,但是与ground-truth的方法相比,它们都具有不同程度的误差。然而,即使我们的计算能力足够强,能够推导出完全精确的解决方案,我们仍然会犯一个很大的错误,这个错误来源于我们在光照模型中的假设。因为现实世界的光源通常并不是球形的,而且它们向外辐射的能量也并不是完美均匀的,如图10.11所示。但是球形光源在实践中仍然非常有用,因为它们提供了一种最简单的方法,来打破精确光源所引入的光照和表面粗糙度之间的错误关联。然而,只有在光源相对较小的情况下,球形光源才能对现实中的大多数光源进行良好的近似。
图10.11:常用面光源的形状。从左到右依次:球形、矩形(卡牌光源)、管状(线光源)、管状的聚焦发射光源(辐射能量在半球上的分布不均匀,集中在光源的法线方向上)。请注意它们所生成的、不同形状的高光。
基于物理的实时渲染,其目标是生成令人信服的、可信的图像,因此我们只能通过将自己限制在一个理想化的场景中来实现这个目标。这就是在计算机图形学中反复出现的trade-off(权衡),通常我们可以选择为简化假设的简单问题生成精确的解,或者是为更加一般化的问题推导出一个近似的解决方案,从而更好的对现实进行模拟。即选择简单问题的精确解,还是选择复杂问题的近似解。
图10.12:一个管状光源。使用了代表性点方法来计算图像中的光照效果。
管状光源(也叫做胶囊体光源)是对球形光源的最简单扩展之一,它可以用来表示现实世界中的荧光灯管,如图10.12所示。对于Lambertian BRDF,Picott 给出了一个封闭形式的光照积分方程,它相当于在线性光源分段(light segment)的极值处,使用适当的衰减函数来评估两个点光源的照明效果,其数学形式如下:
∫ p 0 p 1 ( n ⋅ x ∥ x ∥ ) 1 ∥ x ∥ 2 d x = n ⋅ p 0 ∥ p 0 ∥ 2 + n ⋅ p 1 ∥ p 1 ∥ 2 ∥ p 0 ∥ ∥ p 1 ∥ + ( p 0 ⋅ p 1 ) (10.12) \int_{\mathbf{p}_{0}}^{\mathbf{p}_{1}}\left(\mathbf{n} \cdot \frac{\mathbf{x}}{\|\mathbf{x}\|}\right) \frac{1}{\|\mathbf{x}\|^{2}} d \mathbf{x}=\frac{\frac{\mathbf{n} \cdot \mathbf{p}_{0}}{\left\|\mathbf{p}_{0}\right\|^{2}}+\frac{\mathbf{n} \cdot \mathbf{p}_{1}}{\left\|\mathbf{p}_{1}\right\|^{2}}}{\left\|\mathbf{p}_{0}\right\|\left\|\mathbf{p}_{1}\right\|+\left(\mathbf{p}_{0} \cdot \mathbf{p}_{1}\right)} \tag{10.12} ∫p0p1(n⋅∥x∥x)∥x∥21dx=∥p0∥∥p1∥+(p0⋅p1)∥p0∥2n⋅p0+∥p1∥2n⋅p1(10.12)
其中 p 0 \mathbf{p}_{0} p0和 p 1 \mathbf{p}_{1} p1是线性光源的两个端点, n \mathbf{n} n是表面法线。Picott还推导了一个Phong镜面BRDF积分的代表性点解,来将其作为位于光源分段位置上点光源照明的近似,将这个代表性点与表面着色点相连接,可以与反射向量形成最小的夹角。这个代表性点的解可以动态地将线性光源转换为一个点光源,因此我们可以使用任意球形光源的近似,通过“叠加”的方式来构建一个胶囊光源。
在球形光源的情况下,Karis 在Picott原始解决方案的基础上,提出了一个更加高效(但是不太准确)的变体,该方法使用了与反射向量距离最短的光源表面点(而不是最小的夹角),并提出了一个缩放公式,试图恢复光照中的能量守恒。
许多其他光源形状的代表性点近似也可以很容易地获得,例如圆环光源和Bezier光源,但是通常我们并不希望着色器的分支过多。一个良好的光源形状,应当能够表示许多现实世界中的光源。其中最具表现力的一类形状是平面光源(planar area light),它位于一个平面上,被给定的几何形状所约束,例如:矩形光源(在这种情况下,它们也称为卡片光源),圆盘光源或者更加普遍的多边形光源。这些平面光源可以用于发出光线的面板(例如广告牌和电视屏幕),可以代替常用的摄影光源(例如柔光箱和反光板),可以用于模拟复杂照明装置的光圈,又或者是用于表示场景中墙壁和其他较大表面所反射出的光线。
最早的卡片光源(和圆盘光源)的实用近似,是由Drobot 推导出来的,它也是一个代表性点的解决方案,但是它特别值得注意,因为将这种方法扩展到平面上的二维区域十分复杂,而且对于求解的整体方法来说也是如此。Drobot 从中值定理出发,他认为一个良好的光源计算候选点,应该位于光照积分的全局最大值附近。
对于一个Lambert BRDF而言,这个积分是:
L l ∫ l ∈ ω l ( n ⋅ l ) + 1 r 1 2 d l (10.13) L_{l} \int_{\mathbf{l} \in \omega_{l}}(\mathbf{n} \cdot \mathbf{l})^{+} \frac{1}{r_{1}^{2}} d \mathbf{l} \tag{10.13} Ll∫l∈ωl(n⋅l)+r121dl(10.13)
其中 L l L_l Ll是光源发出的恒定radiance; ω l ω_l ωl是光源几何形状所对应的立体角; r 1 r_1 r1是沿光照方向 l \mathbf{l} l,从着色点到光源平面的射线长度; ( n ⋅ l ) + (\mathbf{n} \cdot \mathbf{l})^{+} (n⋅l)+是Lambertian点积的限制结果。从着色点出发,沿法线方向发射一条射线,将这条射线与光源平面的交点记为 p ′ \mathbf{p}^{\prime} p′;光源边界上距离点 p ′ \mathbf{p}^{\prime} p′最近的点记作 p c \mathbf{p}_c pc,将点 p c \mathbf{p}_c pc与着色点相连接,在这个方向上可以获得 ( n ⋅ l ) + (\mathbf{n} \cdot \mathbf{l})^{+} (n⋅l)+的最大值。类似的,我们将光源平面上距离着色点最近的点记为 p ′ ′ \mathbf{p}^{\prime \prime} p′′,点 p r \mathbf{p}_r pr是光源边界上距离点 p ′ ′ \mathbf{p}^{\prime \prime} p′′最近的点,在点 p ′ ′ \mathbf{p}^{\prime \prime} p′′处,我们可以获得 1 / r 1 2 1 / r_{1}^{2} 1/r12的最大值,如图10.13所示。这个被积函数的全局最大值位于点 p r \mathbf{p}_r pr和点 p c \mathbf{p}_c pc之间的某处,即: p max = t m p c + ( 1 − t m ) p r \mathbf{p}_{\max }=t_{m} \mathbf{p}_{c}+\left(1-t_{m}\right) \mathbf{p}_{r} pmax=tmpc+(1−tm)pr,其中 t m ∈ [ 0 , 1 ] t_m \in [0,1] tm∈[0,1]。Drobot使用数值积分方法来找到不同配置下的最佳代表性点,然后再找到一个平均表现最好的参数 t m t_{m} tm。
图10.13:Drobot的矩形面光源。上图展示了代表性点近似的几何构造过程。
在Drobot的最终解决方案中,对漫反射光照和镜面光照的进行了进一步的近似,所有这些都是通过与数值上的ground-truth解决方案进行对比来实现的。他还为纹理卡片光源(textured card light)推导出了一种算法,这种光源在矩形区域上的光线发射是不均匀的,具体的发光强度由一个纹理进行控制。这个过程是使用一个三维查找表来实现的,这个表中包含了自发光纹理在不同半径的圆形区域上的预积分。Mittring 采用了类似的方法来进行光泽反射,它将反射光线与一个纹理化的矩形广告牌相交,并根据光线相交的距离,来检索预先计算的、模糊版本的纹理。这项工作要早于Drobot所提出的方法,但这个方法是一种更加经验主义的,不那么有原则性的方法,它确实试图与ground-truth的积分解决方案相匹配。
对于更加一般的平面多边形面光源(polygonal area light),Lambert 最早给出了完美漫反射表面的一个精确封闭形式的解。Arvo对该方法进行了改进,将光泽材质建模为Phong镜面波瓣。Arvo通过将向量irradiance的概念扩展到高维irradiance张量,并利用Stoke定理,将面积积分转换为沿积分域轮廓的简单积分,从而实现了这一点。Arvo的方法仅有一个假设:光源对于表面着色点是完全可见的(这是一个常见的假设,可以对与表面相切的光源多边形进行裁剪,来绕过这个假设),并且BRDF是一个径向对称的余弦波瓣。不幸的是,在实践中,Arvo的解析方法对于实时渲染而言十分昂贵,因为它需要计算一个方程,其时间复杂度与Phong波瓣中所使用的指数线性相关,同时还与每个面光源多边形的边缘数量有关。最近,Lecocq 找到了轮廓积分函数的一个 O ( 1 ) O(1) O(1)近似,并将这个解扩展到了一般的、基于半向量的BRDF中,这使得该方法更加实用。
到目前为止,我们所描述的所有实用的实时面光源光照方法,都采用了某些简化的假设,从而允许对解析结构的推导,以及对结果积分的近似处理。Heitz等人采用了一种不同的线性变换余弦(linearly transformed cosine,LTC)方法,据此产生了一种实用、准确且通用的技术。在他们的方法中,首先会在球体上设计一组具有高度表现力的函数(即这些函数可以具有多种不同的形状),这些函数可以很容易地在任意球面多边形上进行积分,如图10.14所示。
图10.14:线性变换余弦技术背后的关键思想是:一个简单的余弦波瓣(最左侧图像)可以很容易地进行缩放、拉伸,并通过使用一个 3 × 3 3×3 3×3的变换矩阵进行倾斜。这使得余弦波瓣在球面上可以有很多形状。
LTC只使用了一个由 3 × 3 3×3 3×3矩阵变换的余弦波瓣,因此它们可以在半球上调整大小、拉伸、旋转,从而适应各种形状。一个简单的余弦波瓣(与Blinn-Phong不同,它不包含进行指数运算)与球面多边形的积分已经很成熟了,它可以追溯到Lambert的工作[74, 967]。Heitz等人观察到,在波瓣上使用变换矩阵来对积分进行扩展,并不会改变它的复杂性,我们可以通过逆矩阵来对多边形定义域进行变换,并消去位于积分内部的矩阵,最终的被积函数仅仅是一个简单的余弦波瓣,如图10.15所示。
图10.15:给定一个LTC和一个球面多边形定义域(最左侧图像),我们可以通过LTC矩阵的逆来对其进行变换,从而获得一个简单的余弦波瓣和一个新的定义域(最右侧图像)。新的余弦波瓣在变换后的定义域上的积分,就等于LTC在原定义域上的积分。
对于一般的BRDF和面光源形状,剩下的唯一工作,就是找到将球体上的BRDF函数表示为一个或者多个LTC的方法(或者近似值),这些工作可以离线完成并构建一个查找数组,通过BRDF参数(粗糙度、入射角等)来进行索引。基于余弦的线性变换方法既适用于一般的纹理多边形面光源,也适用于专门的、更易于计算的光源形状,例如卡片光源、圆盘光源和管状光源。LTC方法可能要比代表性点方法更加昂贵,但是相应地也更加准确。
环境光照
原则上,反射(方程9.3)并不会区分是从光源发出的直接光,还是从天空或者场景其他物体散射过来的间接光,在着色点半球内的所有入射方向上都存在radiance,反射方程会对所有方向进行积分。然而在实践中,通常我们会认为直接光具有较高的radiance和相对较小的立体角,而间接光往往会以中等或者较低的radiance,来覆盖半球方向上的其余部分。基于这种划分方式和理由,我们可以将二者分开进行处理。
到目前为止,我们讨论了面光源的技术,它对从光源形状发出的恒定radiance进行了积分。这样做为每个表面着色点都创建了一组方向,在这些方向上都具有恒定的非零入射radiance。现在我们将要研究的是,在所有可能的入射方向上,对由不同函数定义的radiance进行积分的方法,如图10.16所示。
图10.16:同一个场景在不同的环境光照下的渲染结果。
虽然我们将在这里对有关间接光照和“环境”光照的内容进行讨论,但是我们所讨论的并不是全局光照算法。这里最关键的区别在于,在本小节所讨论的方法中,所有的着色数学表达式都不依赖于场景中其他表面的知识,而是仅仅依赖于一组少量的光源图元。因此,虽然我们可以使用一个面光源来模拟光线在墙壁上的反射效果,而且它确实也是一个全局效果,但是其中的着色算法并不需要知道这个墙壁的存在;它所拥有的全部信息都来自于这个光源,并且所有的着色计算都是在局部完成的。全局照明技术(第11章)通常会与本章中的概念紧密相关,因为全局光照的许多解决方案,都可以被视为计算正确的局部光源图元集合的方法,并将这些局部光源作用于每个物体或者每个表面位置上,从而模拟光线在场景中相互反弹的作用效果。
环境光(ambient light)是最简单的环境光照模型,环境光的radiance不会随着方向发生变化,具有恒定的值 L A L_A LA。但是即使是这样一个最基本的环境光照模型,也可以显著提升视觉质量。一个不考虑光线在物体之间反弹的场景会显得很不真实,在这样的场景中,处于阴影中的物体或者背对光源的物体将会是纯黑的,这与现实中我们所看到场景都不同。图10.1中所展示的月球表面很接近我们刚才描述的场景,但是即使在这样的场景中,也会有一些间接光线被附近的物体所反射。
环境光的确切影响将取决于BRDF。对于Lambertian表面而言,无论表面法线 n \mathbf{n} n或者观察方向 v \mathbf{v} v的具体情况如何,环境光固定的radiance L A L_A LA对于出射radiance 的贡献都是恒定的:
L o ( v ) = ρ s s π L A ∫ l ∈ Ω ( n ⋅ l ) d l = ρ s s L A (10.14) L_{o}(\mathbf{v})=\frac{\rho_{\mathrm{ss}}}{\pi} L_{A} \int_{\mathbf{l} \in \Omega}(\mathbf{n} \cdot \mathbf{l}) d \mathbf{l}=\rho_{\mathrm{ss}} L_{A} \tag{10.14} Lo(v)=πρssLA∫l∈Ω(n⋅l)dl=ρssLA(10.14)
在进行着色计算的时候,这种恒定的出射radiance 贡献会被添加到直接光源的贡献中。对于任意的BRDF,这个等价方程为:
L o ( v ) = L A ∫ l ∈ Ω f ( l , v ) ( n ⋅ l ) d l (10.15) L_{o}(\mathbf{v})=L_{A} \int_{\mathbf{l} \in \Omega} f(\mathbf{l}, \mathbf{v})(\mathbf{n} \cdot \mathbf{l}) d \mathbf{l} \tag{10.15} Lo(v)=LA∫l∈Ωf(l,v)(n⋅l)dl(10.15)
方程10.15中的积分部分与定向反照率 R ( v ) R(\mathbf{v}) R(v)相同(章节9中的方程9.9),因此这个方程等价于 L o ( v ) = L A R ( v ) L_{o}(\mathbf{v})=L_{A} R(\mathbf{v}) Lo(v)=LAR(v)。在一些较老的实时渲染应用中,有时会假设 R ( v ) R(\mathbf{v}) R(v)是一个恒定的值,它被称为环境颜色 c a m b \mathbf{c}_{amb} camb,因此可以进一步将方程简化为 L o ( v ) = c a m b L A L_{o}(\mathbf{v})=\mathbf{c}_{\mathrm{amb}} L_{A} Lo(v)=cambLA。
这里的反射方程忽略了遮挡情况,也就是说,在实际情况中,表面着色点的某些入射方向,会被其他物体或者同一物体的其他部分所遮挡。这种简化通常会降低画面的真实感,对于环境光照来说尤其明显;在忽略遮挡情况的时候,环境光照会显得非常均匀平坦。
球面函数和半球函数
上一小节中我们所讨论的环境光照还只是一个常数,为了将环境光照扩展到常数项之外,我们需要一种数学方法,来表示从任何方向照射到物体上的入射radiance。首先,我们会将radiance考虑为一个仅对方向进行积分的函数,而不是针对表面位置进行积分。之所以这样做,是因为我们假设光照环境是无限远的。
到达给定着色点上的radiance,在每个入射方向上可能都是不同的。从左边入射的光线可能是红色的,从右边入射的光线可能是绿色的;从顶部入射的光线会被遮挡,而从侧面入射的光线则不会被遮挡。这种类型的量可以使用球面函数(spherical function)来进行表示,这些函数定义在单位球体的表面上,或者定义在 R 3 \mathbb{R}^{3} R3的方向空间中,我们将这个定义域记为 S S S。最终生成单个值还是多个值并不会对这些函数的运行产生影响,例如:通过为每个颜色通道存储单独的标量函数,这些相同的标量函数同样也可以用于对颜色值进行编码。
假设现在我们有一个Lambertian表面,球面函数可以通过存储预先计算的irradiance函数来计算环境光照,例如:对于每个可能的表面法线方向,计算radiance与余弦波瓣的卷积。更加先进(sophisticated)的方式是存储radiance,并在运行过程中,计算每个表面着色点的BRDF积分。球面函数也广泛应用于全局光照算法中(第11章)。
与球面函数相关的是半球函数(hemisphere function),即只有一半方向上的值是有定义的,这些函数用于描述那些没有光线会从下方照射的表面时的入射radiance。
我们将这些表示函数称为球面基底(spherical base),因为它们都是定义在球面函数向量空间中的基底。虽然环境/高光/方向形式(AHD,章节10)在技术上来说,并不是数学意义上的基底,但是我们也将使用基底这个术语来指代它们。将一个函数转换为给定表示形式的操作被称为投影(projection),从给定表示形式中计算函数值的过程被称为重建(reconstruction)。
每种基底表示方法都有自己的一套权衡方式,我们将会在给定的基底中寻找如下属性,这些属性是我们想要基底能够具备的:
- 高效的编码(投影)和解码(查找)。
- 使用较少的系数和较低的重建误差来表示任意球面函数的能力。
- 投影的旋转不变性(rotational invariance),也就是将一个函数的投影结果进行旋转,与旋转这个函数,然后再进行投影所得到的结果是一样的。这个旋转不变性意味着使用近似函数(球谐函数)在旋转的时候,并不会改变所得到的结果。
- 易于计算编码函数的和与编码函数的乘积。
- 易于计算球面积分和球面卷积。
简单表格形式
想要表示球面函数或者半球函数,最直接方法就是直接选择几个方向,并为每个方向都存储一个值。在使用的时候,在所求方向周围找到一定数量的样本,并用某种形式的插值来对函数值进行重建。
虽然这种表示方式很简单,但是它的表征能力很强。将这些球面函数相加或者相乘十分简单,就像直接将它们所对应的表项相加或者相乘一样。我们可以对许多不同的球面函数进行编码,并使用更多的样本来降低重建误差。
想要以一种允许高效检索,同时又能相对平均地表示所有方向的方式,来将样本分布在一个球体上(如图10.17所示)并不是一件容易的事情。最常用的方法是,首先将球面展开为一个矩形区域(类似于世界地图),然后在该矩形区域内,使用点状网格来对其进行采样。由于一个二维纹理刚好可以和矩形区域内的网格相对应,因此我们可以使用纹素来作为样本值的底层存储方式。这样做可以让我们利用GPU加速的双线性纹理过滤,来进行快速查找(重建)。在章节10中我们将讨论有关环境贴图的内容,它就是这种形式的球面函数,在该小节中我们还会讨论将展开球面的不同方式。
图10.17:在球面上分布采样点的几种不同方法。从左到右分别是:随机分布,立方体网格点,球面t型设计。
这种简单表格形式当然也存在缺点。如果我们使用较低分辨率的贴图来存储这个表格,那么硬件过滤所提供的质量通常是不可接受的。卷积计算是处理光照时的常见操作,其计算复杂度与样本数量成正比,这可能会导致非常高的计算开销。此外,使用表格形式存储球面函数不具备投影不变性,这在某些应用中可能会出现一些问题,例如:想象一下,当光线从一组方向照射到物体表面上,此时我们已经有了对其radiance的编码;但是如果此时物体发生了旋转的话,那么编码结果可能会以不同的方式进行重建,这可能会导致编码的辐射能量发生变化,从而导致在场景动画的过程中,可能会出现脉冲瑕疵(pulsating artifact)。通过在投影和重建过程中,仔细构造与每个样本相关的核函数,可以缓解这些问题。不过更加常见的情况是,仅仅增加样本数量就足以掩盖这些问题。
通常来说,当我们需要存储复杂的高频函数,并且这些函数需要对许多数据点进行编码,从而保持较低误差的时候,就会使用表格形式。如果我们需要以一种更加紧凑的形式来对球面函数进行编码,并且这些函数只有少数几个参数的时候,我们可以选择使用更加复杂的基底。
作为一种常见的基底选择,环境立方体(ambient cube,AC)是最简单的表格形式之一,它由六个沿着主轴方向的平方余弦波瓣构成。之所以它会被称为环境“立方体”,是因为这种方法相当于在立方体的六个表面上存储数据,并在我们从一个方向移动到另一个方向的时候进行插值。对于任何给定的方向,只有三个波瓣是与之相关的,因此我们并不需要从内存中获取另外三个波瓣的参数。在数学上,环境立方体可以被定义为:
F A C ( d ) = d d ⋅ sel + ( c + , c − , d ) (10.16) F_{A C}(\mathbf{d})=\mathbf{d} d \cdot \operatorname{sel}_{+}\left(\mathbf{c}_{+}, \mathbf{c}_{-}, \mathbf{d}\right) \tag{10.16} FAC(d)=dd⋅sel+(c+,c−,d)(10.16)
其中 c + \mathbf{c}_{+} c+和 c − \mathbf{c}_{-} c−包含了立方体六个表面上的值; sel + ( c + , c − , d ) \operatorname{sel}_{+}\left(\mathbf{c}_{+}, \mathbf{c}_{-}, \mathbf{d}\right) sel+(c+,c−,d)是一个向量函数,它将一个方向向量作为输入,并会输出一个向量;对于输入参数 d \mathbf{d} d中的每个分量,会根据其正负性来选择取 c + \mathbf{c}_{+} c+还是 c − \mathbf{c}_{-} c−。
环境立方体和立方体贴图很类似,二者的不同之处在于,环境立方体的每个表面上只会存储一个纹素。在某些渲染系统中,针对这种特殊情况,在软件中执行重建过程可能要比在立方体贴图上使用GPU的双线性过滤更快。Sloan [1656]推导了一个简单的方程,可以在环境立方体和球谐函数基底之间进行转换。
使用环境立方体进行重建的质量相当低。通过对8个值(而不是6个)进行存储和插值,可以获得稍微好一点的结果,这8个值对应了立方体上的8个顶点。最近,Iwanicki和Sloan 提出了另一种被称为环境骰子(ambient dice ,AD)的方法,它的基底由沿二十面体顶点方向的平方和四次余弦波瓣组成。在重建的时候,需要使用12个存储值中的6个,确定检索哪6个值的逻辑要比环境立方体的稍微复杂一些,但是这种方法的质量要高得多。
球面基底
有无数种方法可以将函数投影(编码)到使用固定数量值(系数)的表示方法上。我们所需要的是一个跨球面的数学表达式,它具有一些可以改变的参数。然后,我们可以通过拟合,来对任意给定的函数进行近似,即找到一组参数,使得表达式与给定函数之间的误差最小。
最简单的选择是使用一个常量:
F c ( θ , ϕ ) = c ⋅ 1. F_{c}(\theta, \phi)=c \cdot 1. Fc(θ,ϕ)=c⋅1.
我们可以通过将给定函数 f f f在球面上进行求平均,从而将其投影到这个基底中,即 c = 1 4 π ∫ Ω f ( θ , ϕ ) c=\dfrac{1}{4 \pi} \int_{\Omega} f(\theta, \phi) c=4π1∫Ωf(θ,ϕ)。一个周期函数的平均值 c c c也被称为DC分量(直流分量)。这种基底的构建十分简单,甚至也符合我们正在寻找的一些性质(易于重构、加法、乘积、旋转不变性)。然而对于大多数球面函数而言,这种方法的表达能力并不好,因为这种方法只是使用了函数的平均值来代替这些函数。我们可以使用两个系数 a a a和 b b b来构造一个稍微复杂的近似:
F hemi ( θ , ϕ ) = a + cos ( θ ) + 1 2 ( b − a ) , F_{\text {hemi }}(\theta, \phi)=a+\frac{\cos (\theta)+1}{2}(b-a), Fhemi (θ,ϕ)=a+2cos(θ)+1(b−a),
这种表示方法可以对位于球体两极的值进行精确编码,并可以在球体表面上对其进行插值。这个表示方法的表现能力更强,但是投影过程变得更加复杂了,并且不是所有旋转都具有旋转不变性。事实上,这个基底可以看作是一个包含两个样本的表格形式,这两个样本分别位于球体的两个极点上。
图10.18:基函数的一个例子。在这个例子中,输入值为0-5之间的一个数,函数会返回0-1之间一个值,左侧的图展示了这样一个函数。中间的图展示了一组基函数(每种颜色都代表了一个不同的基函数)。右图则展示了使用基函数来对目标函数的近似,通过将每个基函数乘以一个权重并将它们相加来完成这个近似。右图中的每个基函数都按照各自的权重进行了缩放,图中的黑色线条代表了基函数求和之后的结果,这是对原始函数的近似结果;图中灰色线条代表了原始函数,用于和近似函数进行比较。
一般来说,当我们讨论函数空间中的一组基底时,我们的意思是:存在这样的一组函数,它们的线性组合(加权和求和操作)可以用来表示给定域中的其他函数。图10.18展示了这个概念的一个例子。本小节的剩余部分,将讨论一些可以用于近似球面函数的基底选择。
球面径向基函数
使用GPU硬件过滤的表格方法,其重建质量较低,这种较低的重建质量,在一定程度上是由插值样本时所使用的双线性函数造成的。可以使用其他函数来对样本进行加权重建,这样的函数可以产生比双线性滤波更高质量的结果,而且它们可能还会具有其他的一些优点。一类经常用于此目的的函数就是球面径向基函数(spherical radial basis function,SRBF),这些函数都是径向对称的(沿轴旋转对称),因此这些函数都只有一个输入参数,即函数所指方向与计算方向之间的夹角。基底就是由一组这样的函数所组成的,每个函数都被称为一个波瓣(lobe),它们分布在整个球面上。每个函数都由波瓣的一组参数进行表示,这个参数集合可以包含它们的方向,但是这样会使得投影过程变得更加困难(需要非线性的全局优化)。因此,我们通常会假定波瓣的方向是固定的,它们均匀地分布在整个球体上;并使用一些其他的参数,例如每个波瓣的大小或者每个波瓣所覆盖的角度(分布)。通过在给定方向上,对所有波瓣进行计算,并将结果进行求和,从而完成重建过程。
球面高斯函数
球面高斯分布(spherical Gaussian,SG)是一种十分常见的SRBF波瓣,在方向统计(directional statistic)中也被称为von-Mises-Fisher分布。需要注意的是,von-Mises-Fisher分布通常都会包含一个归一化常数,我们在方程中会避免使用这个常数。单个波瓣可以定义为:
G ( v , d , λ ) = e λ ( v ⋅ d − 1 ) (10.17) G(\mathbf{v}, \mathbf{d}, \lambda)=e^{\lambda(\mathbf{v} \cdot \mathbf{d}-1)} \tag{10.17} G(v,d,λ)=eλ(v⋅d−1)(10.17)
其中 v \mathbf{v} v是需要计算的方向,它是一个单位向量; d \mathbf{d} d是波瓣的方向轴,即分布的平均方向,同样也是一个单位向量;其中的 λ ≥ 0 \lambda \ge 0 λ≥0,它代表了波瓣的尖锐程度,即控制了波瓣的角宽度(angular width),也被称为集中参数(concentration parameter)或者扩散参数(spread)。
为了构造球面基底,我们会使用给定数量的球面高斯函数的线性组合:
F G ( v ) = ∑ k w k G ( v , d k , λ k ) (10.18) F_{G}(\mathbf{v})=\sum_{k} w_{k} G\left(\mathbf{v}, \mathbf{d}_{k}, \lambda_{k}\right) \tag{10.18} FG(v)=k∑wkG(v,dk,λk)(10.18)
将一个球面函数投影(编码)到这种表示方法中,需要找到一组参数集合 { w k , d k , λ k } \{w_k, \mathbf{d}_k, λ_k\} {wk,dk,λk},来使得重建误差最小化。这个过程通常会通过数值优化的方法来完成,通常会使用一个非线性的最小二乘优化算法(例如Levenberg-Marquardt法)。需要注意的是,如果我们允许在优化过程中改变整个参数集合,那么我们就不会使用函数的线性组合来构造基底,此时方程10.18并不代表一组基底。只有当我们选择一组固定的波瓣(固定的方向和固定的扩散角度)时,才能获得一个适当的基底,从而很好地覆盖整个定义域,并且只需要对权重 w k w_k wk进行拟合就可以完成投影过程。这样做也大大简化了优化问题,因为现在它可以使用普通的最小二乘法来进行优化。如果我们需要在不同的数据集(投影函数)之间进行插值,这也是一个很好的解决方案,对于这种情况而言,允许波瓣方向和波瓣锐度能够发生变化的坏处是很大的,因为这些参数是高度非线性的,很难进行拟合。
这种表示方法的一个优点是,在SG上进行的许多操作都有简单的解析形式,两个球面高斯函数的相乘,会产生另一个球面高斯函数:
G 1 G 2 = G ( v , d ′ ∥ d ′ ∥ , λ ′ ) , G_{1} G_{2}=G\left(\mathbf{v}, \frac{\mathbf{d}^{\prime}}{\left\|\mathbf{d}^{\prime}\right\|}, \lambda^{\prime}\right), G1G2=G(v,∥d′∥d′,λ′),
其中:
d ′ = λ 1 d 1 + λ 2 d 2 λ 1 + λ 2 , λ ′ = ( λ 1 + λ 2 ) ∥ d ′ ∥ . \mathbf{d}^{\prime}=\frac{\lambda_{1} \mathbf{d}_{1}+\lambda_{2} \mathbf{d}_{2}}{\lambda_{1}+\lambda_{2}}, \quad \lambda^{\prime}=\left(\lambda_{1}+\lambda_{2}\right)\left\|\mathbf{d}^{\prime}\right\|. d′=λ1+λ2λ1d1+λ2d2,λ′=(λ1+λ2)∥d′∥.
球面高斯函数在球面上的积分,也可以使用解析方法来进行计算:
∫ Ω G ( v ) d v = 2 π 1 − e 2 λ λ \int_{\Omega} G(\mathbf{v}) d \mathbf{v}=2 \pi \frac{1-e^{2 \lambda}}{\lambda} ∫ΩG(v)dv=2πλ1−e2λ
这意味着对两个球面高斯函数的乘积进行积分,也有一个很简单的方程。
如果我们能够将光线的radiance表示为一个球面高斯函数,那么可以将其与一个BRDF(以相同的形式进行编码)相乘,然后再对乘积进行积分,从而进行光照计算。由于这些原因,SG在许多研究项目和工业应用中得到了应用。
图10.19:各向异性球面高斯。左图展示了一个球体上的ASG,以及对应的俯视图。右图展示了ASG的其他四个例子,用于显示公式的表达能力。
对于平面上的高斯分布而言,可以将von Mises-Fisher分布进行推广,从而允许各向异性。Xu等人[1940]引入了各向异性的球面高斯函数(anisotropic spherical Gaussians,ASG),如图10.19所示,它是通过在单个方向 d \mathbf{d} d上,增加两个补充轴 t \mathbf{t } t和 b \mathbf{b} b来实现的,它们共同形成一个正交的切线坐标系:
G ( v , [ d , t , b ] , [ λ , μ ] ) = S ( v , d ) e − λ ( v ⋅ t ) 2 − μ ( v ⋅ b ) 2 (10.19) G(\mathbf{v},[\mathbf{d}, \mathbf{t}, \mathbf{b}],[\lambda, \mu])=S(\mathbf{v}, \mathbf{d}) e^{-\lambda(\mathbf{v} \cdot \mathbf{t})^{2}-\mu(\mathbf{v} \cdot \mathbf{b})^{2}} \tag{10.19} G(v,[d,t,b],[λ,μ])=S(v,d)e−λ(v⋅t)2−μ(v⋅b)2(10.19)
其中的 μ , λ ≥ 0 \mu,\lambda \ge 0 μ,λ≥0,它们控制了波瓣沿切线坐标系( t \mathbf{t} t和 b \mathbf{b} b)的扩散程度;其中 S ( v , d ) = ( v ⋅ d ) + S(\mathbf{v}, \mathbf{d})=(\mathbf{v} \cdot \mathbf{d})^{+} S(v,d)=(v⋅d)+是一个平滑项,这个平滑项是方向统计中的Fisher-Bingham分布与计算机图形学中所使用的ASG的主要区别。Xu等人还提供了积分算子、乘积算子和卷积算子的解析近似。
虽然SG具有许多令人满意的特性,但是它们具有这样的一个缺点,与表格形式和具有有限范围(带宽)的一般内核不同,SG具有全局支持(global support)的特性,即每个波瓣都会对球面上的任意一个方向产生影响。即使每个波瓣的衰减速度都很快,但是球体上的每个波瓣都是非零的。这个全局范围意味着,如果我们使用 N N N个波瓣来表示一个函数,那么对于任意一个需要重建的计算方向,我们都需要对所有的 N N N个波瓣进行计算,才能获得最终的重建结果。
球谐函数
球谐函数(spherical harmonic,SH)是球面上的一组正交的基函数。一组基函数的正交集(orthogonal set)具有如下特点:任意两个不同基函数之间的内积(inner product)为零。内积是一个类似于点积的概念。两个向量之间的内积就是它们的点积,即各个分量对应相乘再相加的结果。我们可以类似地推导出两个函数的内积的定义,即将这两个函数相乘再进行积分,其数学表达如下:
⟨ f i ( x ) , f j ( x ) ⟩ ≡ ∫ f i ( x ) f j ( x ) d x (10.20) \left\langle f_{i}(x), f_{j}(x)\right\rangle \equiv \int f_{i}(x) f_{j}(x) d x \tag{10.20} ⟨fi(x),fj(x)⟩≡∫fi(x)fj(x)dx(10.20)
上述方程是在相关定义域上进行积分的,即 x x x轴上。对于图10.18所示的函数,其相关的定义域位于 x x x轴上的0-5之间(请注意,图10.18所展示的基函数并不是正交的)。对于球面函数而言,定义域有所不同,但是基本的形式和概念都是相同的:
⟨ f i ( n ) , f j ( n ) ⟩ ≡ ∫ n ∈ Θ f i ( n ) f j ( n ) d n (10.21) \left\langle f_{i}(\mathbf{n}), f_{j}(\mathbf{n})\right\rangle \equiv \int_{\mathbf{n} \in \Theta} f_{i}(\mathbf{n}) f_{j}(\mathbf{n}) d \mathbf{n} \tag{10.21} ⟨fi(n),fj(n)⟩≡∫n∈Θfi(n)fj(n)dn(10.21)
其中 n ∈ Θ \mathbf{n} \in \Theta n∈Θ代表了在单位球面方向上进行积分。
标准正交集(orthonormal set)也是一个正交集,其附加条件是该集合中的任意一个函数与自身的内积都为1。更加正式的表述方式为,一组函数 { f j ( ) } \{f_j()\} {fj()}是标准正交的条件是:
⟨ f i ( ) , f j ( ) ⟩ = { 0 , where i ≠ j , 1 , where i = j . (10.22) \left\langle f_{i}(), f_{j}()\right\rangle=\left\{\begin{array}{ll}0, & \text { where } i \neq j, \\ 1, & \text { where } i=j .\end{array}\right. \tag{10.22} ⟨fi(),fj()⟩={0,1, where i=j, where i=j.(10.22)
图10.20展示了一个类似于图10.18的例子,不同之处在于,其中的基函数都是标准正交的。请注意,图10.20中的所展示的标准正交基函数都是互不重叠的,这个条件对于非负函数的标准正交集合是十分必要的,因为任何的重叠都意味着内积非零。而对于那些在部分范围内为负的基函数,则可以发生重叠,它们仍然可以形成标准正交集。这种重叠通常会得到更好的近似结果,因为它允许使用更加平滑的基底。而那些互不重叠的基函数,往往会导致近似结果的不连续性。
图10.20:标准正交基函数。这个例子中使用空间和目标函数,与图10.18所使用的完全相同,不同之处在于,这个例子中的基函数都是正交的。左图展示了目标函数,中间展示了基函数的标准正交集,右图展示了缩放后的基函数。为了方便对比,最终得到的近似函数使用黑色虚线进行表示,原始函数则使用灰色实线进行表示。
标准正交基的优点在于,想要找到最接近目标函数的近似值十分简单。为了完成投影操作,每个基函数的权重系数都是目标函数 f target ( ) f_{\text {target }}() ftarget ()与相应基函数的内积:
k j = ⟨ f target ( ) , f j ( ) ⟩ , f target ( ) ≈ ∑ j = 1 n k j f j ( ) . (10.23) \begin{array}{c}k_{j}=\left\langle f_{\text {target }}(), f_{j}()\right\rangle, \\[2mm] f_{\text {target }}() \approx \sum_{j=1}^{n} k_{j} f_{j}() .\end{array} \tag{10.23} kj=⟨ftarget (),fj()⟩,ftarget ()≈∑j=1nkjfj().(10.23)
在实践中,这个积分只能通过数值方法来进行计算,通常会使用蒙特卡罗采样,对平均分布在球面上的 n n n个方向进行计算,然后再取平均值。
标准正交基在概念上类似于章节4中所介绍的三维向量的“标准基底(standard basis)”。不同之处在于,标准基的目标并不是函数,而是一个点的位置;标准基由三个向量组成(每个维度一个向量),而不是一组函数。根据方程10.22中使用的定义,标准基也是标准正交的。将一个点投影到标准基上的方法也是一样的,每个权重系数都是位置向量和基向量点积的结果。这里有一个十分重要的区别,那就是标准基可以精确地再现每个点,而一组有限的基函数只能对目标函数进行近似。由于标准基使用了三个基向量来表示三维空间,而函数空间所具有的维度是无限的,因此有限数量的基函数永远无法完美地表示函数空间中的信息。也就说,对于有限数量的基函数,其近似结果永远都不可能是精确的。
球谐函数都是正交或者标准正交的,它们还具有其他一些优点。球谐函数是旋转不变的,并且SH基函数的计算成本也不高,它们都是单位向量在 x − x- x−、 y − y- y−、 z − z- z−坐标中的简单多项式。然而,与球面高斯函数一样,它们都具有全局支持的特点,因此在重建的过程中,需要对所有的基函数都进行计算。有关基函数的表示方法可以在一些参考文献中找到,包括Sloan的一篇演讲。他的演讲十分值得关注,因为他讨论了许多使用球谐函数的实用技巧,包括方程以及一些着色器代码。最近,Sloan还提出了一些方法,来对高效完成SH的重建过程。
SH基函数可以按照频带(frequency band)进行排列。第一个基函数是一个常数;接下来的三个基函数是线性函数,它们会在球面上缓慢变化;再接下来的五个基函数是变化稍快的二次函数,如图10.21所示。频率较低的函数(即在球面上变化缓慢的函数),例如irradiance等,可以用相对较少的SH系数来精确地进行表示。
图10.21:球谐函数的前五个频带。每个球谐函数都有正值区域(绿色)和负值区域(红色),当函数值接近零时,会逐渐变黑。
当投影到球谐函数的时候,所获得的系数代表了投影函数在各个频率上的振幅(amplitude),即其频谱(frequency spectrum),它代表了信号或者波形中各个频率成分中的强度分布。在这个光谱域(spectral domain)中,有这样一个基本的性质:两个函数乘积的积分等于函数投影系数的点积。这个特性能够使我们能够高效地计算光照积分。
球谐函数的许多运算在概念上十分简单,可以将其归结为对系数向量的矩阵变换。在这些操作中,有几个操作是很重要的,它们分别是:计算投影到球谐函数上的两个函数的乘积、旋转投影函数、计算卷积。在实际操作中,SH中的矩阵变换意味着,这些操作的复杂度与所使用的系数数量呈二次关系,这可能会是一个很大的复杂度。但幸运的是,这些矩阵通常都具有一些特殊结构,可以利用这些结构设计出效率更高的算法。Kautz等人提出了一种优化旋转计算的方法,它将旋转分解为关于 x x x轴和关于 z z z轴的两次旋转。Hable 给出了一种快速旋转低阶SH投影的常用方法。Green的综述讨论了如何利用旋转矩阵的块结构,来实现更快的计算。目前,最先进的技术(the state of the art)是由Nowrouzezahrai等人提出的,他将SH分解为球带谐波(zonal harmonic)。
光谱变换(例如球谐函数和H-basis)的一个常见问题是,它们会表现出一种叫做ringing的视觉瑕疵(也称为Gibbs现象)。如果原始信号中包含了无法使用带限(band-limited)近似来表示的快速变化,那么在重建的时候就会出现振荡瑕疵。在极端情况下,这个重建出来的函数甚至可能会产生负值。当然这个问题是有解决方法的,可以使用各种预过滤方法来解决这个问题。
其他球面表示
还有许多其他的表示方法,也可以使用有限数量的系数来对球面函数进行编码。线性变换余弦就是其中一个例子,它可以有效地对BRDF函数进行近似,同时易于在球面的多边形截面上进行积分。
球面小波(spherical wavelet)是一种具有平衡空间局部性(具有紧支撑,compact support)和频率局部性(平滑性)的基底,它可以用于高频函数的压缩表示。球面分段常数基函数(spherical piecewise constant basis function)将球面划分为常数值的区域;依赖于矩阵分解的双聚类近似(biclustering approximation)也被用于环境光照。
半球基底
尽管上面所介绍的基底都可以用来表示半球函数,但是它们太过浪费,因为总有一半的信号为零。在这些情况下,我们通常会更加倾向于使用直接在半球域上构造的表示方法,这对那些定义在表面上的函数而言特别相关,常见的例子包括:BRDF、入射radiance、到达物体某一点的irradiance等。这些函数天然局限于以给定着色点为中心,并与表面法线对齐的半球范围内,它们都不会指向物体内部。
AHD 基底
沿着这个思路,一种最简单的表示方法就是将一个常数函数,与半球面上信号最强的单一方向结合起来。它通常被称为环境/高光/方向(ambient/highlight/direction,AHD)基底,它最多的用途就是用来存储irradiance。AHD的名字体现了各个分量的含义:A代表一个恒定的环境光;H代表一个方向光,它用于近似“高光”方向上的irradiance;D代表大部分入射光所集中的方向。AHD基底通常需要存储8个参数,其中两个参数代表了角度,用于表示方向向量;另外六个参数(两个RGB颜色)用于环境光强度和方向光强度。它的首次显著应用是在游戏《雷神之锤3》中,动态物体的体积光照就是以这种方式进行存储的。从那时起,它便被广泛应用于许多游戏中,例如《使命召唤》系列。
想要投影到这种表示方法上有些棘手,因为它是非线性的,对于给定的输入,想要找到其最优的近似参数,具有很高的计算成本。在实践中,通常会使用一些启发式方法。该信号首先会被投射到球谐函数上,并使用最优的线性方向来确定余弦波瓣的方向。有了这个方向,可以使用最小二乘法来计算环境光和高光。Iwanicki和Sloan 展示了如何在保证非负性的同时,来执行这个投影操作。
辐射法向映射/《半条命2 》基底
图10.22:《半条命2》光照基底。三个基向量在切平面上的仰角约 2 6 ∘ 26^{\circ} 26∘,它们在该平面上的投影会以 12 0 ∘ 120^{\circ} 120∘的间隔均匀分布在法线周围。这三个基向量都是单位长度,其中每一个都垂直于另外两个。
Valve在《半条命2》系列游戏中使用了一种十分新颖的表示方式,用于表示定向irradiance,它被称为辐射法向映射(radiosity normal mapping)。其最初的设计目的是为了存储预计算的漫反射光照,同时允许使用法线映射,它现在通常被称为《半条命2》基底。它通过在切线空间中采样三个方向来表示表面上的半球函数,如图10.22所示。三个相互垂直的基向量在切线空间中的坐标分别为:
m 0 = ( − 1 6 , 1 2 , 1 3 ) , m 1 = ( − 1 6 , − 1 2 , 1 3 ) , m 2 = ( 2 3 , 0 , 1 3 ) . (10.24) \mathbf{m}_{0}=\left(\frac{-1}{\sqrt{6}}, \frac{1}{\sqrt{2}}, \frac{1}{\sqrt{3}}\right), \quad \\[2mm] \mathbf{m}_{1}=\left(\frac{-1}{\sqrt{6}}, \frac{-1}{\sqrt{2}}, \frac{1}{\sqrt{3}}\right), \quad \\[2mm] \mathbf{m}_{2}=\left(\frac{\sqrt{2}}{\sqrt{3}}, 0, \frac{1}{\sqrt{3}}\right). \tag{10.24} m0=(6−1,21,31),m1=(6−1,2−1,31),m2=(32,0,31).(10.24)
在重建的时候,对于一个给定的切线空间方向 d \mathbf{d} d,我们可以沿着基向量的方向,对 E 0 E_0 E0, E 1 E_1 E1, E 2 E_2 E2进行插值,其数学表达如下:
E ( n ) = ∑ k = 0 2 max ( m k ⋅ n , 0 ) 2 E k ∑ k = 0 2 max ( m k ⋅ n , 0 ) 2 . (10.25) E(\mathbf{n})=\dfrac{\sum_{k=0}^{2} \max \left(\mathbf{m}_{k} \cdot \mathbf{n}, 0\right)^{2} E_{k}}{\sum_{k=0}^{2} \max \left(\mathbf{m}_{k} \cdot \mathbf{n}, 0\right)^{2}}. \tag{10.25} E(n)=∑k=02max(mk⋅n,0)2∑k=02max(mk⋅n,0)2Ek.(10.25)
Green指出,如果在切线空间方向 d \mathbf{d} d上预先计算以下三个值,则可以显著降低方程10.25的计算量:
d k = max ( m k ⋅ n , 0 ) 2 ∑ k = 0 2 max ( m k ⋅ n , 0 ) 2 , (10.26) d_{k}=\dfrac{\max \left(\mathbf{m}_{k} \cdot \mathbf{n}, 0\right)^{2}}{\sum_{k=0}^{2} \max \left(\mathbf{m}_{k} \cdot \mathbf{n}, 0\right)^{2}}, \tag{10.26} dk=∑k=02max(mk⋅n,0)2max(mk⋅n,0)2,(10.26)
其中 k = 0 , 1 , 2 k=0,1,2 k=0,1,2,因此方程10.25可以简化为如下形式:
E ( n ) = ∑ k = 0 2 d k E k (10.27) E(\mathbf{n})=\sum_{k=0}^{2} d_{k} E_{k} \tag{10.27} E(n)=k=0∑2dkEk(10.27)
《半条命2》基底可以很好地用于表示定向irradiance。Sloan 发现这种表示所产生的结果要优于低阶的球谐函数。
半球谐波 / H-Basis
Gautron等人将球谐函数特化到半球域上,他们称之为半球谐波(hemispherical harmonic,HSH)。有很多种方法可以实现这种特化。
例如:Zernike多项式是类似于球谐函数一样的正交函数,但是它是定义在单位圆盘上的。与SH一样,这些函数也可以用于对频域(频谱)函数进行变换,这会产生许多很方便的性质。由于我们可以将一个单位半球转换为一个圆盘,因此我们可以用Zernike多项式来表示半球函数 。然而,使用这些数据来进行重建的计算成本很高。Gautron等人的解决方案具有较低的计算开销,同时还允许对系数向量使用矩阵乘法,来进行相对较快的旋转操作。
然而,HSH基底的计算开销仍然要比球谐函数更高,因为它是通过将球体的负极移动到半球的外边缘来构建的。这种移位操作使得基函数不再是一个多项式,在计算过程中涉及除法和平方根运算,这在GPU硬件上通常会很慢。此外,在半球边缘处的基底总是不变的,因为它在移位之前会被映射到球体上的一个极点。在边缘附近的近似误差可能会很大,尤其是当只使用少数几个系数(球谐函数的频带)时。
Habel 引入了H-Basis,它在经度参数化中使用了部分球谐函数基底,在纬度参数化中使用了部分HSH基底。这个基底混合了移位版本的SH和非移位版本的SH,它仍然是正交的,同时计算效率更高。