1. 光照交互
人之所以能够看见物体,是因为有光线进入人眼,而进入人眼的光线根据来源可以分为自发光与反射光,太阳,蜡烛,灯光等属于自发光,月亮其他物件上的光照属于反射光。
因为自发光计算比较简单,因此图形学中对于光照计算与模拟通常集中在反射光上。反射光根据反射次数又可以分成直接光照(从光源出来后经过单次反射到达人眼)与间接光照(经多次反射后到达人眼)两种。因为不同物体以及同一物体不同位置的反射光照不相同,才使得我们能够感知到不同物体的形状乃至属性。
按照反射理论,只有反射进入人眼的光线才能被人眼感知,但是将一个平整的物体(比如一块平滑的木板)放在完全阴暗环境中,之后只开启一盏聚光灯,我们却能够从各个角度看到物体,这说明看似平滑的物体,在光线的眼中实际上是不平滑的,如下图所示,将物体表面进一步放大以后,可以看到物体表面实际上是布满各种孔洞,使得入射的光线被反射到了各个方向,这种模型我们称之为微表面模型(microfacet model),而这种模型则是图形学中PBR光照理论的基础。
实际上,光线与物体的交互比这个更为复杂,上面的微表面模型只考虑了光线照射到物体上直接反射的情况,但是除了反射之外,光线还会出现透射现象,透射包括折射,多次反射,吸收等多种交互。
如下图所示,光线照射到物体上之后,直接反射的光线只占一部分,另一部分会进入到物体内部,在内部发生一次以及多次交互,之后部分穿出物体表面,部分就湮灭在物体内部。
在反射的光线中,方向比较一致的反射部分,我们称之为镜面反射(specular,这部分光线通常来自于较为光滑物体上的直接反射部分),方向比较随机的反射部分,我们称之为漫反射(diffuse,这部分反射来自于透射后穿出表面的反射以及极其粗糙物体上上的直接反射部分)。
1.1 金属与非金属
金属与非金属由于分子结构的不同,其对于光线的作用也是不同的。
对于非金属物体,光线与其的交互方式跟上述理论比较一致,光线垂直入射到物体表面上,直接反射的部分较少(大概只占4%[1]),大多数的光线会穿透物体表面,在其中经过透射交互后反射出来,因此主要表现为漫反射为主。
对于金属物体,其内部的分子结构为金属阳离子与自由电子,光线进入到金属内部后,会被自由电子完全吸收,因此金属物体通常只有镜面反射(不考虑物体表面粗糙度的情况下),没有漫反射。而金属物体上的直接反射比例也比非金属要大得多。下图给出了不同的材质上光线垂直入射时的直接反射比例(F0),可以看到金属与非金属之间的数值存在较大的差异。
至于金属与非金属为什么会有这种差别,ChatGPT的回复是:
1. 电子结构:光照射在物体表面上,之所以会发生反射,主要是因为物体内部的电子与光的电磁场相互作用的结果。
1.1 金属原子间的相互作用较弱,这使得金属中的自由电子容易在整个金属内部传播,因此金属的电子结构中存在许多自由电子,当光照射到金属表面时,这些自由电子会与光中的电磁场相互作用,产生反射。
1.2 非金属材料中的电子通常是与原子核紧密结合的,且非金属原子间的相互作用较强,这使得非金属中的电子在原子间的传播受到限制,不容易形成自由电子,因此非金属的反射率较低。
2. 能带结构:金属的导带与价带之间没有能隙,使得金属对光的吸收较弱,因此金属的反射率较高。而非金属的导带与价带之间存在能隙,使得非金属对光的吸收较强,从而降低了非金属的反射率。
3. 表面粗糙度:非金属材料的表面粗糙度通常较高,这会导致光在表面上产生多次散射,使得反射光的强度减弱,从而降低了非金属的反射率。
1.2 菲涅尔反射
所谓的菲涅尔反射指的是反射的强度与观察角度存在一定的关联的现象,法国物理学家菲涅尔最先观察并给出了一组反射率与折射率的公式,称之为菲涅尔方程,完整的菲涅尔方程比较复杂,对于日常工作而言,我们只需要知道,在菲涅尔方程的作用下,光线入射角度越大,与物体表面法线夹角越接近90度,那么反射的比例也就越大就行了。
2. 辐射理论
前面介绍的是一些定性的内容,下面来介绍一些定量的内容。
光是一种电磁波,具有辐射能量,对于一个表面积为A的物体而言,假设光源在时间段t内辐射到此物体上的总能量为Q,那么此物体单位时间内收到的辐射功率(我们称之为辐射通量(flux))在这里用来表示(单位为watt),那么:
又,令物体单位表面积上收到的辐射功率为辐射照度(irradiance,单位为),用E表示:
照度表示的是某个点所接收到的光照强度,这个是从接受光照的物件角度出发的概念,这也是渲染最终所需要计算的变量。因为某个点所接收到的光照强度需要考虑各个方向的入射光线,这里还需要对光线的角度做一个定义,为了描述方便,前辈们引入了立体角(solid angle)的概念。
如下图所示,立体角是二维平面角在3D空间中的延伸,2D平面角对应的是圆形上的一段圆弧所对应的夹角,而立体角对应的则是球面上的一个圆形曲面对应的夹角,其单位为球面度(sr),整个球的立体角为,半球的立体角为。
假设光源照射到物体表面时,对应的立体张角为,令单位立体角内的辐射功率为辐射强度(radiant intensity),从含义上来看,这个概念是用于光源的而非普通接受光照的物件的,用表示,单位为:
再令单位面积单位立体角内的辐射功率为辐射率(radiance),这个概念跟光辐射照度一样,是用于接受光照输入的物件的,用表示,单位为:
上式中,表示的是物体在光线方向上的投影面积,如下图所示,计算公式为:
3. 渲染方程
根据前面的基本理论,我们可以给出基本的渲染方程:
上述公式中表示的是输出的辐射率,表示的是物体自发光的辐射率,表示的是某个方向上输入的辐射率,考虑输入光方向与物体表面夹角导致的投影面积减损,还需要乘上。
表示的是光的波长,表示的是输入光方向,表示的是输出光方向,表示的是当前点的位置,表示的是时间,表示的是双向散射分布函数(BSDF, bidirectional scattering distribution function,有BSDF = BRDF + BTDF + BSSRDF,BRDF=bidirectional reflectance distribution function, 表示的是反射部分的输入输出关系,BTDF=bidirectional transmittance distribution function, 表示的是投射部分的输入输出关系;BSSRDF=bidirectional scattering-surface reflectance distribution function,表示的是光线在物体上的入射点与出射点不重合情况下的反射关系),是物体的固有属性,表示的是特定输入角度下,单位辐射率的输入光在经过与物体的交互后,沿着给定的输出方向上的输出辐射率。
根据渲染所关心的内容,我们可以将上述公式简化一下,得到如下公式:
从这个公式我们可以看到,输入光以及光线法线夹角都比较直观,只有双向光照分布函数比较抽象,而对应于这个函数的不同,人们给出了不同的光照模型。
4. 光照模型
为了模拟真实渲染效果,图形学界的前辈们开发了数目众多的光照模型,有的注重效果,有的则注重性能,为了方便对比,这里将平时工作中接触到的接受度比较高的光照模型做一下梳理,因为平时工作中使用最多的双向光照分布函数是BRDF,因此这里出于简单考虑,暂时忽略BTDF/BSSRDF等复杂光照交互。
4.1 BRDF
BRDF是bidirectional reflectance distribution function的缩写,而所谓的BRDF,指的是用于描述对于给定方向给定输入光强,给定方向的输出反射光强的分布函数,用公式来描述的话,可以写成如下形式:
这个等式来源于前面的公式(6)。
BRDF的公式设计不是随心所欲的,通常需要满足如下几个原则:
- 正值输出原则
- 光路可逆原则(即交换light vector与view vector,公式依然成立)
- 能量守恒原则
而BRDF设计的时候需要考虑如下的几个因素:
- 物理上要精确
- 数值上要精确,即通过对公式输出的反射lobe与测量得到的反射lobe数据进行对比,不应该出现太大偏差
- 计算上要高效
根据实现原理来看,BRDF可以分成两类,分别是解析式(Analytical)与非解析式(non-analytical,比如手绘或者通过测量数据模拟);而按照光照类型来看,又可以分成Local Illumination与Global Illumination两类,比如使用最早的Phong Reflection Model与Blinn-Phong Reflection Model就是Local Illumination Model,实际上目前实时渲染中使用的基本上都是Local Illumination Model。
4.2 Phong Reflection Model
Phong Reflection光照模型是具有比较悠久历史的光照模型,这个模型提出于1975年,是一种经验模型,也就是说,这个模型的提出纯粹是出于主观经验判断,其中的参数并没有太多物理意义。
整个光照公式可以写成如下形式:
求和之外的部分为Ambient光照,为材质的漫反射率,为材质的镜面反射率,根据能量守恒原则,通常有,为材质的基色,对于金属而言,,对于非金属而言,,总结起来就是。
求和针对场景中的多盏光源进行,用通俗一点的话来解释这个公式,可以写成如下形式:Ambient+Sum(Diffuse)+Sum(Specular)
这里需要对Specular部分做一下简单介绍,如下图所示,公式中的R对应的是入射光线沿着法线的反射方向,而V对应的则是视线方向:
其中R与N,L之间的关系可以用如下公式给出:
高光部分系数是一个指数形式:
这个公式说明了高光反射光强比例近似等同于视线与反射光线夹角的点乘,在这种情况下,得到的高光反射区域会比较广,参考下面n=1的曲线(其中的n对应的就是前面公式中的),可以看到光强随着角度的增加,下降较为缓慢,而增加n则可以缩小高光区域。
使用不同的指数,得到的表现效果有所不同,n越大高光越集中,强度也越高
另外,注意到,高光区域越广,根据能量守恒原则,对应的高光强度应该越低,因此还需要对上述Specular乘上一个调制参数Ks
不过由于指数计算消耗比较高,在实际使用的时候,还可以做一下近似,比如使用泰勒展开来模拟:
其中,这样做怎么能达到优化性能呢?如果我们选取的,那么上述公式中最后的计算就转换成了多次平方,而这个计算比直接计算指数要更为高效。
上图给出了与的效果对比,可以看到,在较小的时候,两者是非常接近的,也就是说,前面的假设成立的条件是要足够大,通常会选择,下图给出了当时以为自变量与的对比图:
可以看到当较小的时候,两者结果是比较一致的,越大,差的越远。而越小,差距越小,下图给出了不同下两者的差距对比图:
将这个光照模型改写成BRDF的形式,不考虑环境光,那么其BRDF对应的公式给出如下:
这个公式相当于最开始的光照公式除以,而这个除法是从BRDF的跟的计算关系中推导而来的。
对应的是diffuse部分的BRDF,而这就是众所周知的Lambert光照模型,此外,将满反射系数与基色结合起来,这个公式可以进一步可以改写成如下形式:
上述这个公式还有一个问题,那就是当接近0(也就是光线贴着物体表面入射时),specular项会接近无穷大,表现与真实表现不符合,因此在实际使用中有时候也会见到将这一项从分母中删除的情况,公式就变成了如下形式:
光照公式相应就变成了如下形式:
而实际上,移除了cos项之后,公式还满足光路可逆原则(?),更接近物理真实,此外,在这个公式下,我们可以很容易的求取出specular在单个输入光作用下输出光强的最大值,因此可以很方便的对specular进行归一化以满足能量守恒:
上述公式中的表示的是以Halfway Vector(H = normalize(L + V))为方向轴的半球积分,积分自变量是View Direction,当入射光线与表面法线方向相同的时候,此时得到的为最高,对应的就是上述公式中的,此时,用这个数值进行归一化的话,得到最终的specular brdf公式给出如下:
更换成这种形式,就可以避免在公式中添加进无意义的参数,转而使用材质本身的垂直反射数据来计算,并且参数更加物理,表现更加物理(越大,高光面积越小,高光中心亮度越高,原始Phong Reflection能够做到高光面积变小,却无法做到中心亮度增高),使用更加方便,美术同学不需要根据来调整,不足之处在于的意义依然比较模糊。
将diffuse跟specular结合起来,最终的brdf公式给出如下,在的情况下,这个公式是能量守恒的:
在上述公式作用下,diffuse lobe跟specular lobe的形状大致如下图所示:
Phong模型的优点在于实现简单,缺点则在于公式不够物理,通常需要美术同学凭直觉调整参数。
4.3 Blinn-phong光照模型
Blinn-Phong光照模型是以Phong光照模型为基础进行了一系列改进优化后的光照模型,这是OpenGL与D3D固定管线所使用的默认光照模型。
Blinn-Phong跟Phong的区别在于,Phong是反射式的BRDF,而Blinn-Phong则是微表面式的BRDF,在效果上,反射式的BRDF的高光形状是圆形的,而微表面BRDF的高光形状会随着观察角度的变化而出现伸缩,比较符合自然规律。
将上述光照计算公式改写成BRDF的格式,给出如下:
其中,当LHNR四个向量处于同一平面之中时,RV两个向量的夹角,是NH两个向量夹角的两倍;当四个向量不处于同一平面时,RV两个向量的夹角,接近NH两个向量夹角的两倍。
处于同一平面时,NH结果总是比RV要大(夹角小,余弦大),不同平面则不一定,而为了得到接近Phong Shading的效果,NH的指数就要大于RV的指数:
选取为原始的4倍比较接近Phong Shading的表现。
这个公式与Phong的BRDF的公式有如下区别
- 归一化系数存在差别
- cos角度含义存在差别,Phong的角度对应的是反射向量与观察向量之间的夹角,Blinn-Phong的角度对应的则是半向量Half-Vector与表面法线之间的夹角,这个夹角可以看成是表面粗糙程度的一种表征,存在物理含义
- 整个cos项可以看成表面法线分布函数,的含义比较明晰,可以看成是表面法线分布函数NDF的参数
如果用替换上述公式中的得到如下公式:
虽然上述公式将使得能量不再守恒,但是其效果却比修正前要更好看一点,对于绝缘体而言,随着入射夹角的增加,其反射的强度应该有所增强,这个公式符合这个规律(前面的不符合?)
能够满足绝大多数材质的需求,但是无法模拟一些特殊的效果,比如shadowing & masking。
Blinn-Phong光照模型通常是放在VS中计算的(当然,也可以放在PS中来提升质量),在效果上相对于Phong Shading,在视角方向与表面法线方向夹角较大的时候,反射表面的高光形状会呈现一种拉长的椭圆形,比较贴近太阳光在水面上的反射效果以及夜晚灯光在潮湿地表上的反射效果,Phong Shading的高光反射基本上是圆形的。
在特定情况下,H可以看成是一个常量,当观察者位于无穷远(正交投影)以及太阳光位置位于无穷远时(方向光),H可以看成是恒定不变的,与表面法线方向无关;Phong Shading中R的计算需要考虑N的方向,因此对于每个顶点或者像素都是不相同的,计算量更大,不过在透视相机的情况下,这种优化是不成立的,意义不大。
使用Blinn-Phong Shading可以消除部分视角下RV夹角超过90度被裁切掉所导致的瑕疵,效果如下图所示:
4.4. PBR理论
Disney在2012年的Siggraph上分享了他们实现Physically-based Rendering的相关理论,因为其易用性而得到了迅速推广,目前业界的PBR算法基本上都是以此为基础的。
传统的blinn-phong模型中主要由三个参数进行控制(漫反射参数,镜面反射参数以及光泽度参数),但是这几个参数的物理意义不是很明确,因此在使用的时候对美术同学就不太友好,而Disney给出的PBR模型则主要通过如下的三个参数来对材质进行描述:基色albedo,金属度metalness以及粗糙度roughness。(当然,还有一些其他的用于一些特殊材质的参数,比如次表面参数等,因为并不通用,这里就不做深入介绍了)
在这个模式下,其光照计算方法与Blinn-Phong模型有着较大的差别,下面的Cook-Torrance就是PBR模式下的光照模型。
4.5 Cook-Torrance光照模型
Blinn-Phong相对于Phong模型主要的区别在于Specular上,而Cook-Torrance模型的Diffuse部分也跟前面两个模型一样,区别只在于Specular部分。
可以看到整个公式最关键的就是分子中的三项D,F,G,接下来我们介绍一下这三项的物理意义与相应的计算公式。
4.5.1 法线分布函数 - D
D表示的是法线分布函数,从统计学上近似的表示了与中间向量取向一致的微平面的比率。
与这一项相关的参数有如下两项:
- 微表面粗糙度,这个参数表示的是微表面法线集中程度
- 宏观法线与视线的中间向量:h;仅m = h的表面点的朝向才会将光线l反射到视线v的方向,其他朝向的表面点对BRDF没有贡献。
常用的法线分布函数模型有如下几种。
4.5.1.1 Blilnn-Phong分布
(上面的形式从数值上看起来倒是更香Phong模型的?)由于直接使用上述公式会对美术制作不太友好(怎么不太友好?),实践中常常会取,变换后的NDF为:
4.5.1.2 Beckmann分布
上述公式中的与Blinn-Phong分布中的之间的关系给出如下:
4.5.1.3 GGX分布
这个分布也称为Trowbridge-Reitz分布,这个模型的特征为具有最长的尾部,即当增长到比较大的数值时,GGX的衰减相对更为缓慢,使得其表现更为优越,其公式给出如下:
其中,m为微表面上待计算的目标方向的法线(UE4中此处直接使用的是h而非m),n为当前当前平面的法线。
下图给出三种法线分布模型的函数曲线,红色为Beckmann,蓝色为Blinn-Phong,绿色为GGX,可以看到前两者基本上没有区别,而GGX衰减更慢。
下图给出了不同的NDF的高光对比图,其中左侧为Ground Truth,中间为GGX,右侧为Beckmann,因为其表现的优越性,GGX已经成为业界使用最为广泛的NDF了
下图给出了不同粗糙度下GGX模型的高光表现
4.5.2 菲涅尔方程 - F
F项表示的是菲涅尔方程,描述的是在不同的表面角下表面所反射的光线所占的比率。也就是前面Phong等光照模型中的一项,在使用这类光照模型的时候,可以通过这个公式计算出对应的之后使用求得。
4.5.2.1 None
如果不考虑菲涅尔效应,那么这一项可以直接取,即
4.5.2.2 Schlick
这一项目前使用最广泛的是Fresnel-Schlick模型:
其中表示的额是入射光垂直于物体表面入射时的镜面反射率,对于非金属材质而言,这个数值对于RGB三个分量都是相同的,约等于4%,但是对于金属材质而言,这个数值就是RGB各不相同了,且一般远大于4%,通常会将金属的基色用作,其数值可以通过查表来求得:
为了兼顾金属与非金属材质,在实际使用中,可以通过如下代码来计算:
vec3 F0 = vec3(0.04);
F0 = mix(F0, surFaceColor.rgb, metalness);
关于这个公式,UE4还做了进一步的优化,使用球面高斯替换指数计算。
球面高斯近似(Spherical Gaussian approximation)是一种曲线拟合方法,用于降低计算复杂度,在实时渲染中可以帮助光线计算节省shader指令数。
初始公式给出如下:
在这个公式下,其结果与直接指数结果之间的对比如下图所示:
为了提高拟合精准度,对参数做了进一步调整,修正后的公式给出如下:
在这个公式下,与原始的指数公式的图形对比如下图,可以看到,基本上一致了:
在经过UE修正后,原始的Fresnel-Schlick公式就变成了如下形式:
这个模型的缺点在于,在specular增加的时候,diffuse不一定会减少,能量不守恒;性能消耗比Blinn-Phong要高不少。
4.5.2.3 Cook-Torrance
4.5.3 几何函数 - G
G表示的是几何函数,描述的是微平面自身阴影的属性,从统计学上对应的是微平面间相互遮蔽的比率,这一项与表面的粗糙度以及法线恩不有关。如下图所示,主要可以分成shadowing部分与masking部分:
阴影(Shadowing)部分表示微平面对入射光的遮挡,一般为对光源方向L而言的;
遮蔽(masking)部分表示微平面对出射光的遮挡,一般为对观察方向V而言的。
如下图所示,整个G函数的表达具有如下两种形式:
其中G1为微平面在单个方向(光照方向L或观察方向V)上可见比例,分为遮蔽函数(masking function)和阴影函数(shadowing function);G2为微平面在光照方向L和观察方向V两个方向上可见比例,称为联合遮蔽阴影函数(joint masking-shadowing function)
在实际使用中,我们需要根据具体材质的实际情况,选取合适的微表面模型,从而实现对G的定量描述,常用的PBR微表面模型有如下几种:
4.5.3.1 Implict
4.5.3.2 Smith遮蔽函数(Smith masking function)
这是业界所采用的主流遮蔽函数,下图展示了Smith模型(右)与真实世界(左)的对比,Smith模型具有不相关的表面,即每个微平面与其邻域不相关的特点。
原始的Smith模型只描述了出射光遮蔽函数,而Walter等人对其进行了推广,将G做成可分离形式:遮蔽(masking)和阴影(shadowing)是独立的,并分别计算。
其中表示光线方向的几何阴影,简称为入射光遮蔽,而表示视线方向的几何遮蔽,简称出射光遮蔽
其中,单个遮蔽函数具有如下形式:
下面公式如果不做说明,均有:
4.5.3.2.1 Beckmann公式
4.5.3.2.2 Schlick-Beckmann/GGX等公式
下面这个公式是目前使用最广的分布函数,根据不同的k取值,可以得到一系列不同的G分布函数,
UE4中使用的Schlick-GGX模型对应的是如下一段代码:
// Tuned to match behavior of Vis_Smith
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
float Vis_Schlick( float Roughness, float NoV, float NoL )
{
float k = Square( Roughness ) * 0.5;
float Vis_SchlickV = NoV * (1 - k) + k;
float Vis_SchlickL = NoL * (1 - k) + k;
return 0.25 / ( Vis_SchlickV * Vis_SchlickL );
}
4.5.3.2.3 GGX
将上述公式代入前面公式得到:
将代入公式得到:
这个公式对应的是UE4中的下面一段代码:
// [Smith 1967, "Geometrical shadowing of a random rough surface"]
float Vis_Smith( float Roughness, float NoV, float NoL )
{
float a = Square( Roughness );
float a2 = a*a;
float Vis_SmithV = NoV + sqrt( NoV * (NoV - NoV * a2) + a2 );
float Vis_SmithL = NoL + sqrt( NoL * (NoL - NoL * a2) + a2 );
return rcp( Vis_SmithV * Vis_SmithL );
}
4.5.3.3 Neumann
4.5.3.4 Cook-Torrance
4.5.3.5 Kelemen
4.5.3.6 Smith-Joint
Smith-Joint是Heitz在2014年首次提出的遮蔽函数模型,这个模型考虑入射阴影和出射遮蔽之间的相关性,尝试模拟由于微表面高度引起的遮蔽和阴影之间的相关性。考虑到两者之间的关联,那么更为精确的表达形式应该如下述公式所描述:
微平面(microfacet)在微表面(microsurface)内升高得越多,对于出射方向未被遮蔽(unmasked)和入射方向未被掩蔽(unshadowed)的可见概率会同时增加。
按照上述公式,如果将前面的GGX函数模型代入会使得结果异常复杂,因此UE4对这个模型做了简化,
下面公式给出的是UE4中的计算模型:
相关代码给出如下:
// Appoximation of joint Smith term for GGX
// [Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"]
float Vis_SmithJointApprox( float Roughness, float NoV, float NoL )
{
float a = Square( Roughness );
float Vis_SmithV = NoL * ( NoV * ( 1 - a ) + a );
float Vis_SmithL = NoV * ( NoL * ( 1 - a ) + a );
// Note: will generate NaNs with Roughness = 0. MinRoughness is used to prevent this
return 0.5 * rcp( Vis_SmithV + Vis_SmithL );
}
在Cook-Torrance模型中,游戏和电影业界主流的方案是GGX分布和Smith联合遮蔽阴影函数的组合,而UE4方案为GGX与Schlick-Beckmann近似的结合体。
这个模型的特点是在不增加计算复杂度的前提下,可以得到比可分离的遮蔽阴影函数更精确的结果
参考文献
[1].PBR理论体系整理(一):基础理论
[2].Phong reflection model -wikipedia
[3].The Phong Model, Introduction to the Concepts of Shader, Reflection Models and BRDF
[4]. Specular BRDF Reference