kirin77 发表于 2022-12-28 15:05

《Unity Shader入门精要》笔记(三十五)

本文为《Unity Shader入门精要》第十八章《基于物理的渲染》的第一节内容《PBS的理论和数学基础》。
本文相关代码,详见:

原书代码,详见原作者github:
<hr/>1. 光是什么

材质和光线会发生的两种物理现象:散射(absorption)、吸收(scattering)。

[*]散射
不会改变光的能量,但会改变光的传播方向。

[*]吸收
光被转化为其他能量,但吸收不会改变光的传播方向。

光传播过程中,影响光的一个重要特性:材质的折射率(refractive index)。光传播过程中,如果折射率突变,会发生光的散射现象。

光和物体的交互是非常复杂的,大多数情况下不存在一种可分析的解决方法,为了在渲染中对光照建模,往往只考虑一种特殊情况:两个介质的边界是无限大且光学平滑(optically flat)的。尽管实际物体表面并不是无限延伸的,也不是光滑的,但相比光的波长,它们的大小可以被近似认为是无限大以及光学平滑的。

基于上述前提,光在不同介质边界被分为两个方向:发射方向、折射方向。光线有多少百分比被发射,由菲涅尔等式(Fresnel equations)来描述。



虽然相比光的波长,物体表面可以被认为是光学平坦,但实际上它更像是一系列微小的光学平滑平面和光交互的结果,每个小平面会把光分割成不同的方向:



光线除了一部分被反射,还有一部分被折射到物体的内部,这里面一部分被介质吸收,另一部分又被散射到外部:



金属因为是导电介质,进入到金属内部的自由电子被金属吸收转化为其他形式的能量,因此不会发生折射后又散射出来的情况。
而非金属这种被折射后又散射到物体外面的光被称为次表面散射光(subsurface-scattered light)。

以上都是基于微表面理论,由微表面反射的光可以被认为是该点上一些方向变化不大的反射光,而折射光线需要考虑更多。
次表面散射光会从不同于入射点的位置从物体内部再次射出,这些离入射点的距离值和像素大小之间的关系会产生两种建模结果:

[*]如果像素大于这些散射距离,这些次表面散射的距离会被忽略(如下右图);
[*]如果像素小于这些散射距离,则需要考虑次表面散射,需要使用特殊的渲染模型(次表面散射渲染技术)(如下左图)。



2. 双向反射分布函数(BRDF)

2.1 概念


[*]辐射率
单位面积、单位方向上光源的辐射通量,常用L表示,被认为是对单一光线的亮度和颜色评估。渲染中常用基于表面的入射光线的入射辐射率Li来计算出射辐射率Lo,这个过程常被称为着色(shading)过程。

想得到出射辐射率Lo,需要知道物体表面一点是如何和光进行交互的,这个过程可以用BRDF来定量分析。
大多数情况下,BRDF用f(I,v)来表示,I为入射方向,v为观察方向(入射方向、观察方向是双向的含义)。


[*]各项同性(isotropic)的BRDF
绕着表面法线旋转入射方向或观察方向并不会影响BRDF的结果,这种BRDF被称为各项同性的BRDF。

[*]各向异性(anisotropic)的BRDF
与前者相反的被称为各项异性的BRDF。

BRDF的两种理解:

[*]给定入射角度后,BRDF可以给出所有出射方向上的反射和散射光线的相对分布情况;
[*]给定观察方向后,BRDF可以给出从所有入射方向到该出射方向的光线分布。

更直观的理解:
当一束光线延入射方向I到达表面某点时,f(I,v)表示了有多少部分的能量被反射到观察方向v上。

2.2 反射等式(reflection equation)




给定观察视角v,该方向上的出射辐射率Lo(v)等于所有入射方向的辐射率积分乘以它的BRDF值f(I,v),再乘以余弦值(n·I)。

通俗理解:
BRDF表示了不同方向的入射光在该观察方向上的权重分布,我们把这些不同方向的光辐射率(Li(I)部分)乘以观察方向上所占的权重(f(I,v)部分),再乘以它们在该表面的投影结果((n·I)部分),最后把这些值加起来(即做积分)就是最后的出射辐射率。

游戏渲染中,通常和精确光源(punctual light sources)打交道,而不是计算所有入射光线在半球面上的积分。
精确光源指:方向明确、大小为无限小的光源,如:点光源、聚光灯等,使用Ic来表示方向,使用clight表示颜色。
精确光源好处:大大简化上面的反射等式。

对于精确光源,使用下面的等式计算其在某个观察方向v上的出射辐射率:



上面式子是使用特定BRDF值代替积分操作,大大简化计算。如果场景中包含多个精确光源,只需将它们分别代入上面的式子进行计算,再将结果相加即可。

2.3 BRDF如何得到

BRDF决定了着色过程是否是基于物理的,它由两个特性来判断:

[*]是否满足交换律(reciprocity)
[*]是否满足能量守恒(energy conservation)

交换律要求当交换I和v的值后,BRDF的值不变。即:



能量守恒则要求表面反射的能量不能超过入射的能量。即:



BRDF可用于描述两种不同的物理现象:

[*]表面反射
[*]次表面反射

针对每种现象,BRDF通常会包含一个单独的部分来描述它们:

[*]用于描述表面反射的部分——高光反射项
[*]用于描述次表面散射的部分——漫反射项




3. 漫反射项

准确的兰伯特BRDF的表示:



上图拼写错误,应该为:Lambert


[*]cdiff表示漫反射光线所占的比例,被称为漫反射颜色;
[*]与之前的兰伯特光照模型不一样的是:上面的式子实际是定值,常见的余弦(n·I)因子是反射等式的一部分,不是BRDF的部分;
[*]除以π:因为假设了漫反射在所有方向上的强度相同,且BRDF要求在半球内的积分值为1。

基于上述,给定入射方向I的光源在表面某点的出射漫反射辐射率为:



虽然兰伯特模型简单,但很多基于物理的渲染选择使用了更复杂的漫反射项来模拟次表面散射的结果。如:Disney使用的BRDF中,它的漫反射项为:



其中,FD90 = 0.5 + 2 * roughness * (h · I)2。在Disney的实现中,baseColor是表面颜色,通常由纹理采样得到,roughness是表面的粗糙度。
上面的漫反射项既考虑了在掠射角(glancing angles)漫反射项的能量变化,还考虑了表面的粗糙度对漫反射的影响。

4. 高光反射项

在基于物理的渲染中,BRDF中的高光反射项大多数是建立在微面元理论(microfacet theory)的假设。

微面元理论认为,物体表面有许多人眼看不见的微面元组成,虽然物体表面并不是光学平滑的,但这些微面元可以被认为是光学平滑的,换言之,它们具有完美的高光反射。

当光线和物体表面一点相交时,实际是和一系列微面元交互的结果。
当光线和这些微面元相交时,光线会被分割成两个方向——反射方向、折射方向。

假设:
表面法线为n,微面元的法线m,并不都等于n;
因此:
不同微面元会把同一入射方向的光线发射到不同的方向上。

当:
计算BRDF时,入射方向I和观察方向v都会被给定;
这意味着:
只有一部分微面元反射的光线才会进入人眼,这部分微面元恰好把光线反射到方向v上;
即:
这些微面元的法线m等于I和v的一半;
也就是:
半角度矢量h(half-angle vector,也称half vector)等于法线m。



然而:
不是所有m=h的微面元都会被添加到BRDF的计算中(被反射到人眼);
因为:
一部分在入射方向I上被其他微面元挡住(shadowing):



另一部分在反射方向v上被其他微面元挡住(masking):



基于微面元理论的假设,BRDF的高光反射项可用下面的形式来表示:



上面式子就是著名的Torrance-Sparrow微面元理论,其中:

[*]F(I,h)
菲涅尔反射(Fresnel reflectance)函数,表示反射光线占入射光线的比率。

[*]G(I,v,h)
阴影-遮掩函数(shadowing-masking function),用于计算那些满足m=h的微面元中有多少会由于遮挡不会反射到人眼。

[*]D(h)
法线分布函数(normal distribution function,NDF),用于计算有多少比例的微面元法线满足m=h,只有这部分微面元才会把光线从I方向反射到v上。

[*]4(n,I)(n·v)
用于校正从微面元的局部空间到整体宏观表面差异的校正因子。

上面几个部分可以根据不同的BRDF模型使用不同的函数,如:Blinn-Phong模型中使用的法线分布函数D(h):



实际上Blinn-Phong模型并不能真实反映真实世界中物体的微面元法线反射分布,因此很多更复杂的分布函数被提出,如:GGX、Beckmann等。
阴影-遮挡函数G(I,v,h)也有很多相关工作被提出,如:Smith模型。

这些数学模型都是为了更加接近使用光学测量仪器测量出来的真实物理的反射分布数据。

5. Unity中的PBS实现

Unity的PBS实际上是受Disney的BRDF的启发,只需要一个Shader通过少量参数就可以渲染绝大部分常见的材质。

Unity实现了2种PBS模型:基于GGX模型、基于归一化的Blinn-Phong模型。它们使用了不同的公式来计算法线分布函数D(h)和阴影-遮掩函数G(I,v,h)。Unity默认使用基于归一化后的Blinn-Phong模型实现基于物理的渲染。

前面提到,Unity使用的BRDF中的漫反射项公式如下:


其中,FD90 = 0.5 + 2 * roughness * (h · I)2。

下面讲高光反射项公式:



基于归一化的Blinnn-Phong模型的高光反射公式可在UnityStandardBRDF.cginc文件中找到实现。
而基于GGX模型的高光反射项公式,其中法线分布函数D(h)的实现:


其中,a = roughness2。

阴影-遮掩函数G(I,v,h)则使用了有GGX衍生出的Smith-Schlick模型:



而菲涅尔反射F(I,h)则使用了图形学中常用的Schlick菲涅尔近似等式:



其中,F0表示高光反射系数,Unity中通常指高光反射颜色。

上面难懂晦涩的公式都是来源于对真实世界中各种物体的BRDF的分析,再使用不同的数学模型进行逼近。这些已经被Unity封装到了基于物理着色的Shader——Standard Shader中,可以直接调用。

以上是本次笔记的所有内容,下一篇笔记我们将学习《Unity的Standard Shader》的相关知识。

<hr/>
写在最后

本文内容会同步发在笔者的公众号上,欢迎大家关注交流!
公众号:程序员叨叨叨(ID:i_coder)
页: [1]
查看完整版本: 《Unity Shader入门精要》笔记(三十五)