本篇不涉及技术细节*
一、高级光线传播*
1.有偏和无偏估计
无偏估计,比如我们在之前做路径追踪的时候,我们用许多样本去近似定积分的值,无论我们取的样本数量是多少,它的期望永远是对的,也就是我们真实的定积分的值,这样的叫做无偏的估计。其他情况,它的期望和准确值不同,称之为有偏估计,其中也有一种特殊情况,虽然它的期望值不正确,但是当样本接近无穷多的时候,它的期望值会收敛到正确值,我们称之为一致的。蒙特卡洛方法的统计量(有效性 无偏性 一致性)评估 - 知乎 (zhihu.com)
2.无偏光线传播
(1)Bidirectional Path Tracing (BDPT)—双向路径追踪
双向路径追踪,简称BDPT,顾名思义就是两条路径,从光源出发打出一条sub-path,从摄像机出发也打出一条sub-path,最后将两条sub-path的端点连起来形成一条完整的path。
BDPT适用于一种情况,如上图,BDPT明显优于PT,这是为什么?上图的场景中,光源只往一个角落中辐射,也就是说整个场景几乎都是由间接光照亮,而我们的PT出发的路径往往很难控制指定找到一条能量多的路径,而BDPT一遍从光源出发,一边从摄像机出发,最后端点连线则解决了这个问题。当然,BDPT会比PT慢很多。
(2)Metropolis Light Transport (MLT)—Metropolis光线传播
Metropolis光线传播,简称MLT,运用了马尔科夫链,一种统计学上的采样工具,它可以根据已有的一个样本,生成与之靠近的下一个样本。它的好处是给定足够的时间,马尔可夫链的蒙特卡洛方法可以生成以任意函数为形状的采用函数(PDF)的样本。我们之前说过,当被积函数和采样函数形状拟合的时候是最合适的,而马尔可夫链可以对任意形状的函数生成拟合的样本。
反映在采样和path上,如上图,如果我们有一条已知的蓝色path,它可以对该path做一些绕扰动,比如改变一下交点的位置,从而生成一条新的path,最后我们就可以找到所有的path。
MLT适合做比较复杂的光线传播,因为我们只需要找到一条path作为初始的种子,我们就可以在它周围不断生成更多的path。如上图中半开着的门,光线都是从门缝进来,同样的场景基本都是由间接光照亮的,或右图中的焦散(Caustics)现象,如果我们做路径追踪,我们发出的path要经过一个SDS(Specular Diffuse Specular)路径,从specular的水面进入池底又进行diffuse,而由此反射出的路径只会达到水面specular很小的一片区域才能形成一条有效的路径,所以路径追踪对焦散现象很难表示,而MLT则可以根据一条不断生成。
MLT很难在理论上分析它会在多长时间收敛,变成无噪声的图像。且MLT所有的操作都是局部的,也就是说有些像素会收敛的快,有些像素会收敛的比较慢,所以得到的结果看上去都比较“脏”。因此我们如果不知道一帧图像什么时候收敛,那么它就更不可能作为渲染动画的方法了。
3.有偏光线传播
(1)Photon Mapping—光子映射
光子映射特别适合渲染Caustics,也就是我们前面提到的焦散效果,也就是光一定程度的聚焦,如上图中的不规则棱镜和戒指,还很适合SDS路径。这里为大家介绍众多光子映射方法中的其中一种,分为两步。
第一步,我们从光源出发,从光源出发无时无刻不在向四周发出光子,这些光子碰到物体表面会弹射反射,直到碰到diffuse的物体,光子停下,然后整理记录这些光子。
第二步,我们从摄像机出发,打出许多sub-path,也是弹射反射,直到打到diffuse物体停下。
然后,我们做一个局部的密度估计。对任意一个着色点,我们取它离它最近的N个光子,而这是一个KNN算法,也就是最邻近算法,我们把所有光子组织成一个自上而下的加速结构模式,这样我们就可以迅速定位到一个着色点周围有多少光子,找到离它最近的一些,然后计算这些光子所占该着色点的面积,然后计算光子的密度,也就是用光子数N除以面积。
很显然,当取的光子数N比较少,那么图像就会产生比较大的噪声。而光子取多呢?图像就会比较模糊,这是为什么?前面说了光子映射是一个有偏的估计,我们计算光子密度的时候,正确的方法应该是对当前一个点的一个微小的面积dA进行计算它的光子数从而计算密度,但是我们却是对一定的光子数的实际面积进行的计算,所以两者本质上并不相等。
当然,当光源发出的光子足够多的时候,我们同样数量的光子覆盖的面积ΔA会更小,也就会更接近dA,当然最终的结果也会更准确,当打出的光子接近极限,ΔA=dA,那么结果也就正确了,这也就是我们说,光子映射是一个一致的方法。
(2)Vertex Connection and Merging(VCM)
Vertex Connection and Merging,简称VCM,简单地说就是结合了双向路径追踪和光子映射的一种方法。在做BDPT的时候,有一些光源发出的sub-path和摄像机发出的sub-path的端点几乎在同一面上非常接近,对此种情况,我们人为其中一条sub-path就不再是一条path,而是光子,然后用光子映射的方法将两条sub-path的贡献结合起来。
VCM渲染方法结合了这两种渲染方法的优点。它使用BDPT来生成相机路径和光线路径,然后使用光子映射来计算间接光照效果。具体来说,VCM方法将BDPT路径和光子映射的贡献结合起来,通过使用交点来连接它们,然后使用一个权重函数来决定BDPT路径和光子映射的比例,以得到更准确的渲染结果。
因此,VCM渲染方法可以更准确地模拟全局照明效果,并且在处理复杂场景时可以更有效地减少噪点。
(3)Instant Radiosity (IR)—实时辐射度
我们之前提到渲染方程的时候,我们说我们并不区分光是由光源发出的还是由其它物体反射而来的,反射出光的表面我们也可以将它看作是一个光源,而实时辐射度方法(IR)正是这种思想。已经被照亮的面,我们都可以把它们当作虚拟点光源(VPL),再用它们照亮别人。我们从光源打出许多sub-path,它们最终会停在某些地方,停在的地方我们就认为它们是光源,然后用新的光源取照亮我们观测的着色点,这也间接的考虑了光线的弹射多次,如上图所示。
当然,IR也有问题,如上图右图,有些缝隙会莫名其妙的发光。其实这与我们之前在路径追踪中改写渲染方程中的距离平方项有关,我们直接对光源进行采样的时候,产生了一个面积*cos/距离^2的一项,如果两点距离极近,那么我们就除以了一个接近0的数,所以就会产生比较大的值。其次,VPL不能渲染Glossy材质。
二、复杂外观建模*
1.非表面材质
(1)Participating Media—散射介质
散射介质,诸如云,雾,等,显然它们不是定义在一个表面上的,而是定义在空间中。
一根光线进入了散射介质会有若干事情发生,比如一根光线进入云,打到其中的某个小冰晶,它会被随机的打到其它方向上去,同样在传播的过程中也会接受到从其他方向反射而来的光。因而有些光线传播的过程中能量就消失了。
那么,当光线打到散射介质的时候,它会怎么散射呢?我们用一个函数Phase Function,也就是相位函数来定义,它规定了光是均匀的向四周散射,还是向某一方向散射的多一些,这一点和BRDF很相似,BRDF定义了光线如何反射,而相位函数定义了光线如何散射。
至于散射介质怎么渲染,我们不过多的介绍,类比表面渲染,我们同样发出一条path,但是随着path前进的距离增加,我们的能量会减少,同时在前进的过程中方向随时可能会被改变,最终同样的我们把着色点连向光源获得一条路径。当然这里不能再用渲染方程,因为渲染方程只告诉了我们表面的计算,而没告诉我们怎么样和体积作用,当然,它有别的方程,我们这里不做介绍,有兴趣的朋友自行了解。
(2)头发和毛发材质
头发显然也不是一种表面材质,因为它是一根一根的,如上图。观察我们发现头发的高光由两部分组成,一部分是无色的高光稍微发白,另外一种是有色的高光。
关于毛发有很多模型,我们首先介绍一个相对简单的Kajiya-Kay Model模型,它把头发丝当成一个圆柱,而当一束光打到头发的时候,它会散射出一个圆锥的范围的光,同时又会向四面八方取散射,这就好像Diffuse和Specular。当然它的效果并不怎么好,如下图。
第二种模型叫做Marschner模型,它表示,光线打到头发丝,不应该只有反射,还会穿过头发发生折射,我们把反射简写为R,穿过头发简写为T,那么就会有几种光线的传播,比如TT,表示,光线打到头发然后穿过头发第一层内壁,又从头发内部穿出去,还有TRT,表示光线穿过第一层内壁后到达第二层内壁又被反射回第一层内壁,然后穿过第一层内壁出去。
Marschner模型人为头发是一个玻璃圆柱,有两层结构,一个是cuticle(表皮) ,另外一个是cortex(皮质),cortex有色素会吸收光线,而当光线穿过头发再出来的时候会被吸收一部分能量。当然我们这只考虑了光线和一根头发如何作用,实际渲染种,要计算光线穿过一根头发后再和其他头发如何作用,需要进行很多的计算,计算量非常大。
接下来说动物的毛发,人们尝试过用头发的模型取描述动物的毛发,但是最后发现并不正确。
人们最后发现并不正确,原因是人的头发和动物的毛发还是有区别的,我们从上图,也就是生物学上的知识解释。上图所示,人的头发和动物的毛发都有三层,包括我们之前提到的Cortex,Cuticle还有一个Medulla(髓质),Medulla它像我们前面提到的散射介质一样,光线打到它回向四面八方散射。我们观察人的头发和动物的毛发,会发现区别,动物的毛发中的Medulla比人的头发中的Medulla大很多,也就是光线打到动物毛发的时候回更容易发生散射。
上图可以看到,即使人的头发髓质只占毛发直径的15%,有和没有,渲染的差异还是非常大的。
于是,有人(闫令琪老师)发明了Double Cylinder Model,双层圆柱模型,它把髓质精准的描述出来,从而模拟光线和双层圆柱的作用。这样我们就可以用五个分量来描述光线和一根头发的作用,包括我们之前提到的R,TT,TRT(TT,TRT存在是因为光线穿过头发的时候可能打不到髓质,或者打到髓质的时候没发生散射),还包括TRTs,TTs,也就是打到髓质后发生了散射的TRT和TT。
(3)Granular Material—颗粒材质
颗粒材质,如盐,糖,沙子等等,它们都有非常多非常小的表面构成,想描述它们非常的困难,当然,人们做了简化,如上图,我们可以认为沙堡由无数个小单元组成,而每个小单元由更小的微元组成,而每个单元中有很多种类不同的微元,然后我们规定每种微元所占的比例,就可以描述出来沙堡。
2.表面材质
(1)Translucent Material—透光材质
Translucent材质,如玉石,水母,人的皮肤,蜡烛等等。它描述一种光可以从一个表面进去又从另外一个表面出去的材质。玉石就是一种非常经典的Translucent材质。
实际上,在物理上这种现象叫做次表面散射(Subsurface Scattering),是指光从表面进入物体经过内部散射,然后又通过物体表面的其他顶点出射的光线传递过程。,因而Translucent材质又经常被称为3S材质。而次表面散射,实际上是对BRDF的概念做了个延申。
次表面散射定义了BSSRDF,我们说BRDF考虑的出射点和入射点是同一个点,但是BSSRDF则不一样,两个不同的点之间也可能存在着光照的贡献。因此BRDF改写后,渲染方程也同样的需要改写,我们不仅对方向积分同时还要对面积积分,如上图。
但是次表面散射的计算过于复杂,于是人们又发明了一种近似方法叫做Dipole近似,基本思想就是我们看到3S材质的时候,光线从它穿进穿出就好像它的里面一光源一样。所以这种近似方法是在表面下放置光源来达到和次表面散射差不多的效果,当然为了物理上的近似,人们后来发现还需要在表面上再加一个光源才行。
(2)布料材质
布料也很复杂,它有很多的层级,第一层级叫做fiber也就是一根纤维。而不同的纤维互相缠绕会形成Ply也就是一股。而不同的股进行缠绕会形成线,也就是Yarn。有了Yarn之后,就可以织成布。
于是我们可以根据织布的手法,也就是织布的工艺不同,来定义不同的BRDF来描述不同的布料。
但是对于特殊一点的布料,比如天鹅绒,它的结构是一根一根往外长得,显然不是表面模型,我们当然不能用BRDF来描述。于是我们换一种方法,把空间划分成非常非常小的很多格子,而每个格子我们知道里面纤维的朝向分布,复杂程度等等,从而我们就知道光是在里面如何折射,散射的。我们不再把它当成表面而是当成体积来渲染,当然这个计算量也是非常大的。
当然也有更暴力的方法,就是按我们之前说的层级,我们一根纤维一根纤维的进行渲染。
(3)Detailed Appearance—细节材质
观察上面的图,我们发现虽然好看,但是并不真实,因为它们太“完美”了。换言之,在现实生活中是不可能有这么完美的东西的,无论是车还是鼠标,或多或少都会有划痕/破损/污渍之类的东西。
上图是真实世界的照片,可以看到与两幅渲染图对比,它们是真实的。
我们之前说过各向异性材质,它们的BRDF有一个专门描述发现分布的项,但是我们并没有仔细说,而是简简单单用了一些没有细节的分布去描述它,如正态分布,高斯分布等等。过于“完美的”发现分布,如上图左,就会产生过于完美的材质。而我们实际想要的是上图右边的这种分布,基本符合统计规律,又有自己的细节,它没那么完美,但更真实。
思想虽然简单,但是渲染细节材质是非常困难的。因为我们考虑微表面是完美的镜面反射,那么许多微表面,我们打出一根光线,无论是从摄像机出发还是从光源出发,都很难打到对方身上。
解决方法是,我们考虑一个像素它会覆盖很多微表面,如果我们能把这个微表面的分布拿出来,也就是在一个范围内的法线分布算出来就可以替代原本的光滑的微表面然后用在微表面模型中。
当然,发现分布也会根据像素的覆盖范围发生变化,覆盖的法线分布区域足够大的时候,就会显现出统计学的分布规律,覆盖范围小就会有特殊的细节。
当然,特殊的法线贴图会有特殊的法线分布,如上图的各向异性贴图和离散的贴图。
海面的法线贴图和法线分布
当然这其中仍然存在问题。当我们描述的足够细节的时候,就不能再用几何光学来解释。物理学上我们知道,当物体非常小,小到和光的波长差不多的时候我们就不能假设光是沿着直线传播的了,而是应该把光当作波来描述,它会发生衍射,干涉等现象。
比如我们拍摄一个白色金属片的照片,当我们放大的时候,发现它并不是白色,而是五颜六色的,这时候就需要波动光学来解释。这里不做介绍。但是我们从上图可以看到波动光学得出的BRDF和几何光学类似,但又有自己的特点,这和光的干涉有关,因为干涉,有些地方会加强,有些地方会减弱,由此形成了如上图所示的不连续的样子。
(4)Procedural Appearance—程序化生成外观
程序化生成的外观,如Noise函数。例如对于上面的一张花瓶的三维纹理,我们之前讲过三维纹理应用后,如果我们把花瓶摔碎,我们是可以看到它内部的花纹的,但是我们并不专门定义一个所谓的三维数组取存储它每个坐标定义的值,而是给它一个函数,每个位置需要用的时候进行计算,给它一个空间中的位置x,y,z,它可以返回一个值。
经常应用于物体表面的纹理,比如上图中的车漆,我们定义一个噪声函数,然后对它进行二值化,取1也就是白色的时候是一个颜色,取0也就是黑色的时候是另外一个颜色。甚至噪声函数可以生成地形,水面等,无非就是对0~1进行了高度或者其它的映射。
同时噪声函数可以和真实的物理属性结合,形成更逼真的效果,如上图的木头,它定义了一个三位函数,可以调整函数进而控制木头的花纹来显现年轮之类的木头特征。