一、Shadow from Environment Lighting
上篇我们说了给定Environment,如何计算一个着色点的Shading,但没说Shadow。而事实上,实时渲染中很难做到环境光的Shadow。
原因也很容易想到,一种观点我们把环境光当成多光源问题,如果这样,我们就要为每一个虚拟光源都生成一张阴影图,那自然不可能实现。其次是采样观点,但显然我们要采样整个半球,也就是说积分线非常长,而且显然环境光不一定是Smooth的,也就是说我们无法把环境光的Visibility从渲染方程里用之前的split sum方法拆分出来。
工业界解决多光源的方法通常是只渲染最重要的光源的阴影,或者几个相对来说重要的光源的阴影,如Unity中的前向渲染。
一些可能的解决方案,如实时光线追踪,以及我们这篇要说的 Precomputerd radiance transfer。
二、数学和信号知识回顾
1.傅里叶变换
任何一个函数都可以分解成许多不同频率的cos函数和sin函数的线性组合,这就是傅里叶变换告诉我们的,相信大家都很了解这个概念,我就不做赘述了。
2.滤波
在GAMES101里我们还介绍了滤波的概念,包括低通滤波,高通滤波,如上图就是一张图片经过低通滤波后的结果,它把高频部分都给抹除了。
3.卷积
其次我们还提到了卷积操作,其实也就是滤波操作,我们通常理解为加权平均操作,模糊操作。而时域上的卷积等于频域上的乘积,如上图。
而这里,我们可以认为,两个函数相乘再做积分就是一个卷积/滤波操作。而所谓低频和我们前面提到的smooth是一个概念,也就是变化没那么剧烈。而这个积分结果的频率由两个函数中各自的最低频决定。
4.Basis Functions—基函数
基函数,顾名思义,基础的函数。如上图公式所示,f(x)由一系列的Bi(x)函数的线性组合构成,那么Bi自然就是f(x)的基函数。自然而然,傅里叶级数展开也是一套基函数。多项式自然也是基函数。
三、Real-Time Environment Lighting (&global illumination)
1.Spherical Harmonics (SH)—球谐函数
球谐函数—Spherical Harmonics,简称SH,是一系列的二维基函数,并且每个基函数都是定义在球面上的。此处二维怎么理解呢?球谐函数的二维基函数实际上定义了三维空间中的一个方向,很容易理解,我们知道两个参数θ和Φ就可以表示三维空间中的一个方向。
并且可以看到,第l阶基函数的数量=2l+1,编号 -l 到 l。并且前n阶的基函数数量为n的平方。
也就是说SH就是一系列的基函数,有不同的阶数,各阶有不同的频率,阶数越高描述的频率越高,基函数也越多。(并且实际上每个基函数是用Legendre多项式写出来的)
其次这里涉及到一个投影的操作,什么是投影呢?给定任何一个球面函数,如果我们想把它展开成某阶的一系列球谐函数的基函数,那么其中某个基函数的系数ci是多少呢,事实上ci就等于把这个函数f和这个基函数做乘积再积分(product integral)得到的结果,这就是投影—Projection操作。这里和一个我们熟知的操作类似,假设我们三维空间有一个向量,我们需要用(x,y,z)坐标表示它,那么xyz的值各是多少呢?那自然就是这个三维向量在各个坐标轴上的投影喽。显然球谐函数的各个基函数就可以理解为三维空间的各个坐标轴,而想要表示的函数自然就是那个三维空间的向量。
其次,三维空间中我们的投影用的不是点乘吗?为什么这里的投影变成了乘积的积分(product integral)呢?事实上,乘积再积分的操作本质上就是点乘,也就是dot操作。其次我们想三维空间的三个坐标轴互相投影为0,也就是说它们是正交的/互相垂直的,而事实上球谐函数的各个基函数也互相垂直。
那么l是不是可以等于无限呢? 事实上并不是,人们通常用前有限阶的一系列球谐函数来近似还原想要的某一个球面函数。比如用前4阶,那只需写16项,而更高阶高频的项则选择丢掉。
关于球谐函数的更多解释和理解,可以参考两篇文章,这里不做赘述:
大二学生都会的球谐函数 - 知乎 (zhihu.com)球谐函数介绍(Spherical Harmonics) - 知乎 (zhihu.com)
2.球谐光照近似的Diffuse
Diffuse的BRDF是smooth的,这点我们之前提到过,也就是说,Diffuse的BRDF是低频的,那我们求Environment的Shading的时候,要把BRDF和环境光的函数相乘然后半球积分,这正是我们之前提到的乘积再积分(product integral)的操作。那么此时,因为BRDF是低频的,我们可以把BRDF看作一个低通滤波器,低通滤波?那当我们把它投影到球谐函数的时候,如上图,可以看到只需要0,1,2阶就足够了,因为从图中可以看到之后的阶数,它们的所属系数基本接近0,因为Diffuse的BRDF是低频的,所以根本没有高阶基函数描述的高频信息。
回到我们前面的product integral操作上,我们说过,乘积再积分的结果的频率取决于低频部分,由也就是说,即使外界环境光再复杂,遇到了Diffuse的BRDF,物体的表面也不会呈现出很复杂的杠光照,这也符合我们的常识。
由上面我们知道,既然BRDF可以用前三阶的SH函数很好的近似出来,为什么我们不能把光照也用有限阶的SH描述出来呢?于是经过实验得到了如上图所示,用前3阶的SH描述光照得到的结果和正确的结果基本一致,误差接近1%。一个更通用的结论,对于任何的一个光照条件,只要BRDF是Diffuse的,我们都可以用前3阶的SH来描述光照来照亮Diffuse的物体。
3.Precomputed Radiance Transfer (PRT) — 预计算辐射传输
我们重新分析一下渲染方程,它包括Lighting项,Visibility项,BRDF项,它们三个都可以表示为一个球面函数,或者说一张Cubemap,那最终结果的颜色(带着Shadow)自然就是它们三项的对应值/像素相乘了,但显然这是一个非常麻烦的步骤,它要耗费很多时间。
PRT的思想是,我们先假设场景中只有Lighting项可以变,如光照类型/反向,其它条件都不变。这样渲染方程就被我们拆成了两部分,一项我们叫Lighting,另一项我们叫它light transport。其次,在预计算的时候,PRT把Lighting项拆成了一系列SH基函数。又因为我们前面提到,场景中除了光照其他条件都不变,那么显然light transport项也不会发生变化,它相当于着色点自身的性质,既然light transport不变,那我们就可以在渲染之前把它预计算好。
其次我们之前说过了因为场景中除了光照其他条件都没有变,所以light transport项里的Visibility项,BRDF项,甚至cos项,都是球面函数,它们相乘后的结果仍然是球面函数,那我们自然可以把light transport项也用SH基函数表示。
(1)Diffuse情况
在这篇文章中,我们从Diffuse的情况来看,因为Diffuse的情况相对来说比较简单。首先因为Diffuse的BRDF是一个常数(我们之前提到过只不过当时把它写作了kd漫反射系数),所以我们可以把它从积分中提出,这里我们写作ρ。其次用我们前面提到的球谐函数可以把Li项用一系列基函数表示变成求和项。然后交换积分与求和的顺序(图形学中大多数情况都可以调换积分和求和的顺序),此时基函数的系数li也可以从积分中提出。此时我们可以看到右边划红线的部分变成了,Visibility项和cos项的乘积也就是light transport项,再乘一个基函数然后积分,这不就是Light transport项在SH各个基函数上的投影吗。
显然,上图划红线的部分直接可以预计算得到,最后组成一个表格存储计算的结果。于是最终的形式就如图所示,变成了L(o) ≈ ρ Σ li·Ti,也就是一个点乘,就可以计算出Diffuse下的环境光照并且带有Shadow。
当然,我们前面提到,我们只假设了光源可以改变,其它场景条件不变,那么Visibilty项如果不能变得话,计算着色点周围的遮挡关系就不能改变。
其次因为光源也做了预计算,如果要更换光源,我们要对不同的想要使用的光源都进行预计算。那么如果光源可以旋转呢?这里可以用球谐函数的一个很好的可以旋转的性质解决。
(2)球谐函数的性质
● 正交性,任何两个基函数互相垂直,在对方上的投影为0 (eg. B1·B2=0)
● 可以把任何函数投影到SH上,只需做product integral操作即可
●SH某个基函数发生旋转,这个旋转后了的基函数可以由同阶的其它基函数线性组合表示
若由SH表示的球面函数发生旋转,可由SH发生旋转来表示,只不过各基函数的系数会随之改变。就我们上面提到的光源旋转问题而言,用SH我们可以立刻得到旋转之后的光源投影在各个基函数上的系数是多少。
这里我更倾向与二维坐标系的理解,我们前面说过基函数和坐标系的坐标轴可以类比,那如果一个二维向量在二维坐标系旋转了,我们自然可以通过旋转坐标系来达到和旋转向量一样的效果。
球谐函数全面讲解 - 知乎 (zhihu.com)
可以看到,基函数的阶数越高,拟合出的光照效果越接近真实光照。
(3)小结
到这里我们就把Diffuse的PRT流程介绍完了,简单的说就是通过球谐函数的投影和求和积分顺序的交换,最后把渲染方程改写成了一个两个向量的点乘,左边是光照被投影在各个基函数上的系数,也就是光照值 ,右边则是预计算的light transport项。
可以看到,Diffuse的PRT最终在环境光照下得到的结果很好,并且带有Shadow。(最右边Shadow+Inter表示多次的light bounce的light transport项预计算后得到的结果)
至于PRT如何处理非Diffuse情况,我们下一篇介绍。
参考:
GAMES202_Lecture_06 (ucsb.edu)
Lecture6 Real-time Environment Mapping_哔哩哔哩_bilibili