实时渲染笔记:从光度学到PBR

这是笔者多年以来一直都在完善的实时渲染基础笔记,放出来给大家分享。

光度学与辐射度量学

光度学与辐射度量学是研究光与电磁辐射测量的姊妹学科。光度学(photometry)基于人眼的视觉响应特性,量化可见光的感知强度;辐射度量学(radiometry)则从物理角度客观测量电磁辐射能量,覆盖全波段(含不可见光)。两者在单位体系上存在严格对应关系,差异源于是否考虑人眼的光谱灵敏度。

光度学

光通量(luminous flux)\(\Phi\) 的国际单位是流明(lumen,lm),但它不是国际单位制的基本单位。光通量是考虑了人眼因素后的光的功率,因此某种意义上,与功率 \(\text{W}\) 的量纲可类比。

举例而言,1W 的 555nm 的绿光,1W 的 632.8nm 的红光和 1W 的 2000nm 的红外光,能量相同为 1W,但光通量不同:绿光是 1 流明,红光介于 0 到 1 流明之间,红外则是 0。具体的换算将涉及到光度函数 \(V(\lambda)\),这里不再赘述。

发光强度(luminous intensity)\(I\) 的国际单位(SI)是坎德拉(candela,cd;旧译烛光),它是国际单位制的基本单位之一,满足

\[ \text{cd} = \frac{\text{lm}}{\text{sr}} \]

其中 \(\text{sr} = \text{rad}^2\) 为立体角微元

\[ \mathrm d \omega = \frac{\mathrm dA}{R^2} = \frac{R^2 \sin \theta \mathrm d \theta \mathrm d \varphi}{R^2} = \sin \theta \mathrm d \theta \mathrm d \varphi \]

的量纲。

亮度(luminance)\(L\) 的国际单位是尼特(nit,nt),满足

\[ \text{nt} = \frac{\text{lm}}{\text{sr} \cdot \text{m}^2} \]

亮度对点光源是无效的,因为点光源的面积为 \(0\),因此该值会是无穷大。

此外还有照度或光照强度(illuminance)\(E\),国际单位是勒克斯(lux,lx)

\[ \text{lx} = \frac{\text{lm}}{\text{m}^2} \]

值得注意的是,照度 \(E\) 是定义在被光照的物体表面的,而非与其他光度学单位一样定义在光源表面。因此,一般不说面光源的强度单位是几勒克斯,而是说流明每平方米,尽管它们在量纲上完全一致。如果要用这一说法表达面光源的强度,它的物理量的名称是光度(luminosity),尽管有的领域并不把光度(luminosity)当作一个物理量。

游戏引擎中,方向光的强度单位是 lx,因为其很难定义功率,只能从被照射物体上间接定义。注意这里的方向光的“每平方米”是被照射物体的面积,而非光源的面积。

点光源的强度单位一般是 lm(总量)或 cd(某个方向),两者之间的转换公式(仅对点光源成立)为

\[ 1 \ \text{lm} = 4 \pi \ \text{cd}. \]

面光源的强度单位一般是 nit,该描述的隐含方向为光源的法线方向:如果一个正方形面光源的亮度为 1 nit,则无论光源面积多大,其每平方米表面在法线方向上发出的光强度为 1 cd 或 1 lm。等价地,有时,面光源的强度单位可能也用流明每平方米(或者直接用流明)描述,注意这里的“每平方米”是光源的面积而非被照射物体的面积。

  • 如果游戏引擎用点光源模拟面光源(如 UE 的矩形光源),则有可能用 cd 描述其强度。

辐射度量学

在辐射度量学中,不考虑光度学这一套人眼因素的映射,直接使用功率体系。

  • 光通量对应辐射通量(radiance flux)或功率
  • 发光强度对应辐射强度(radiance intensity)
  • 亮度对应辐射度或辐射率(radiance)
  • 照度对应辐照度(irradiance)
  • 光度对应辐光度(radiocity)
    • 有时 radiocity 会被翻译成“辐射度”。这不是一个好的翻译,因为容易与 radiance 混淆。

辐射度(radiance)的量纲为

\[ L = \left[ \frac{\text{W}}{\text{sr} \cdot \text{m}^2} \right] \]

仅对点光源而言,其能量遵循平方反比定律,即

\[ L = \frac{I}{r^2}. \]

渲染与渲染方程

渲染的输入是场景(包括空间中的物体、光照等)和摄像机位置和角度,输出是基于该摄像机看向场景的图像。

大概在 1986 年,David Immel et al. 和 James Kajiya 基于物理原理,分别独立提出了渲染方程的概念,从此基于物理的渲染问题成为了一个严谨的数学问题。

反射方程

定义

\[ (\boldsymbol x_1 \cdot \boldsymbol x_2)_+ = \max(\boldsymbol x_1 \cdot \boldsymbol x_2, 0). \]

为正半球点乘。那么 BRDF 下的渲染方程,或反射方程为

\[ L_r(\boldsymbol x, \boldsymbol \omega_r) = L_e(\boldsymbol x, \boldsymbol \omega_r) + \int_{\Omega} L_i(\boldsymbol x, \boldsymbol \omega_i) f_r(\boldsymbol x, \boldsymbol \omega_r, \boldsymbol \omega_i) (\boldsymbol \omega_i \cdot \boldsymbol n)_{+} \, \mathrm d \boldsymbol \omega_i. \]

其中:

  • \(L_r, L_e, L_i\) 分别为反射出射辐射度、表面自发光辐射度和入射辐射度
  • \(f_r\) 为双向反射分布函数(BRDF),一般物体的实时渲染中通常只考虑纯反射。如果要考虑更一般的渲染方程,则需要使用双向光路分布函数(BXDF)
  • \(\boldsymbol \omega_r, \boldsymbol \omega_i\) 分别为表面半球上的反射出射方向和入射方向
  • \(\boldsymbol \omega_i \cdot \boldsymbol n\) 为 Lambert 余弦修正量。考虑光源方向越垂直,表面能量接收越多,且光均匀地反射,因此与观察者位置无关,故这里不使用 \(\boldsymbol \omega_r \cdot \boldsymbol n\)

镜面反射中的角度近似

\(\boldsymbol \omega_h = \frac{\boldsymbol \omega_i + \boldsymbol \omega_r}{||\boldsymbol \omega_i + \boldsymbol \omega_r||}\)\(\boldsymbol \omega_i\)\(\boldsymbol \omega_r\) 决定的半程向量。如果 \(\boldsymbol \omega_r, \boldsymbol \omega_i\) 是微表面模型的镜面反射对,那么 \(\boldsymbol \omega_h\) 就是“微表面法线”,即这是在微表面上的正确镜面反射法线。

通常地,一定有

\[ (\boldsymbol \omega_i \cdot \boldsymbol \omega_h)_+ = (\boldsymbol \omega_r \cdot \boldsymbol \omega_h)_+. \]

如果认为,在计算时 \(\boldsymbol \omega_r\) 总是位于镜面反射角附近,例如使用了只在镜面反射部分有显著支撑集的 BRDF 模型,或低粗糙度物体,那么 \(\boldsymbol \omega_h \approx \boldsymbol n\),故

\[ (\boldsymbol \omega_i \cdot \boldsymbol \omega_h)_+ = (\boldsymbol \omega_r \cdot \boldsymbol \omega_h)_+ \approx (\boldsymbol \omega_i \cdot \boldsymbol n)_+ \approx (\boldsymbol \omega_r \cdot \boldsymbol n)_+ = \cos \theta \]

如果并没有这一假设,例如仅使用了 Lambert 反射计算,或高粗糙度物体,上述近似通常将不再成立,需要明确一种表达方式。但若使用法线分布函数 \(D\) 如 GGX 对所有 \(\boldsymbol \omega_h\) 加权平均,仍会等价地得到 \(\boldsymbol \omega_h\) 的平均值位于 \(\boldsymbol n\) 附近的结论。也就是说,尽管 \(F\) 本身的以上近似不能成立,但综合考虑 \(\int_{\Omega} DF \, \mathrm d \boldsymbol \omega_h\),以上近似仍能成立。

因此,有时会使用 \(\cos \theta\) 表示这些角度,Fresnel Schlick 近似也通常写成 \(\cos \theta\)

在 IBL 中,通常用 \((\boldsymbol \omega_r \cdot \boldsymbol n)_+ = \cos \theta\) 采样 specular BRDF LUT 的横轴。这个 \(\cos \theta\) 是 IBL 推导过程中的精确结果,不能写成其他形式的近似。

BRDF 与材质

在视角固定之下的渲染过程只与光源信息、几何信息和物体的材质信息有关系。显然,渲染方程中的 \(f_r\) 恰好就是材质信息。如何取得一个近似的,易于计算的 \(f_r\),一直以来是实时渲染领域中的难题之一。

一般的单波长光传播函数与 BSSRDF

一般的单波长电磁波传播函数 \(f(\boldsymbol x_i, \boldsymbol x_o, \boldsymbol \omega_i, \boldsymbol \omega_o)\) 的参数包括入射点 \(\boldsymbol x_i\),出射点 \(\boldsymbol x_o\),入射角度 \(\boldsymbol \omega_i\) 和出射角度 \(\boldsymbol \omega_o\),其中 \(\boldsymbol x\) 是一个在物体表面的 uv 上变化的二维坐标,\(\boldsymbol \omega\) 代表一个半球面上的方向,可用球坐标系的两个分量描述,因此整体可以看作是一个八维函数。

BSSRDF (bidirectional scattering surface reflectance distribution function) 的参数列表与这个函数相同,它们都考虑了完整的模型次表面光路,可完整描述次表面散射。

SVBXDF 与 BXDF

显然,八维函数的计算压力是很大的。如果近似认为,光线总是在同一点入射后出射,能量不会传播到其他点,那么 Spatial-Varying (SV) BXDF \(f(\boldsymbol x, \boldsymbol \omega_r, \boldsymbol \omega_i)\) 是一个六维函数,可直接用来描述该物体表面材质的变化信息。

如果我们不考虑材质在空间中的变化,那么 BXDF 就只具有两个输入:入射角度和出射角度。这样的 BXDF \(f(\boldsymbol \omega_o, \boldsymbol \omega_i)\) 可以看成是一个四维函数,可能包含多重散射,因此 BTDF、BSDF、BRDF 都可以是 BXDF 的组成部分(但 BSSRDF 不是)。它的定义式是

\[ f(\boldsymbol \omega_o, \boldsymbol \omega_i) = \frac{\text{Radiance outgoing}}{\text{Irradiance incoming}} = \frac{\mathrm d L_o(\boldsymbol \omega_o)}{\mathrm d E_i(\boldsymbol \omega_i)} = \frac{\mathrm d L_o(\boldsymbol \omega_o)}{L_i(\boldsymbol \omega_i) \cos \theta_i \, \mathrm d \boldsymbol \omega_i} \]

BXDF 的量纲是

\[ f = \left[ \frac{1}{\text{sr}} \right] \]

这可以由 \(\mathrm d \boldsymbol \omega_i\) 的量纲为 \(\text{sr}\) 直接推出。它的含义是:BXDF 是单位立体角上光的传播比例。

BRDF

在只考虑纯反射的近似下,实时渲染中的 BXDF 都是 BRDF (bidirectional reflectance distribution function)。我们将 BRDF 的出射向量从 \(\boldsymbol \omega_o\) 改写成 \(\boldsymbol \omega_r\)。BRDF 应当具有 BXDF 的以上性质,且如果它需要符合物理意义,那它就必须遵守光路可逆性,即

\[ f_r(\boldsymbol x, \boldsymbol \omega_r, \boldsymbol \omega_i) = f_r(\boldsymbol x, \boldsymbol \omega_i, \boldsymbol \omega_r) \]

以及能量守恒性,即

\[ \int_{\Omega} f_r(\boldsymbol x, \boldsymbol \omega_r, \boldsymbol \omega_i) (\boldsymbol \omega_i \cdot \boldsymbol n)_{+} \, \mathrm d \boldsymbol \omega_i \leq 1. \]

PBR 的 BRDF 都具有这些性质(使用半程向量代替反射向量计算会破坏性质,但仍近似具有性质),但很多经验光照模型如 Blinn-Phong,以及 NPR 的 BRDF 并不具有这些性质。

纹理

最后,我们知道,现实生活中的物体材质其实并不均匀。因此,我们需要考虑同一物体的材质在空间中的变化。我们可以使用二维纹理来存储这一系列的变化,然后在运行时采样这一纹理贴图,获取相应的材质信息。

在其他领域中,“材质”和“纹理”可能会有一些其他的解释方式:

  • 纹理可用于材质,也可用于其他光照、深度表达和物理仿真等,如法线纹理、阴影映射、三维空间中的 SDF。
  • 图形 API 如 OpenGL 中的纹理,基本上是一个可采样的高维数组,因此帧缓冲也可以看作是“纹理”。图形 API 一般不会主动抽象“材质”。
  • UE5 里的材质是一个可编程的,计算光照时会调用的对象,而纹理则是一个图片。材质可以索引纹理,也可以完全由计算节点产生(程序化纹理)。

最后,我们可以给实时渲染中参与光照计算的材质下个定义:材质信息是物体表面存储的,与渲染有关的信息,包含纹理信息,并隐式地包含 BRDF 模型信息。值得一提的是,法线贴图、flowmap 等等虽然也是纹理,但并不是本文讨论的“参与光照计算的”纹理。

解析的 BRDF

直接使用四维或六维的查找表存放 BRDF ,在实时渲染中通常不具备可行性。因此,实时渲染中通常使用解析模型进行逼近。此时,我们只需要存储几个有限的参数,参数 \(\boldsymbol \omega_i, \boldsymbol \omega_r\) 会直接参与计算,所以这样解析的 BRDF 是一个存储上“零维”的函数。

由于解析的 BRDF 是 0D 的,所以只需一系列二维纹理(albedo, matallic, normal 等)即可表达物体表面。因此,这样的 SVBRDF 在存储上是 2D 的。

(Blinn-) Phong 模型

(Blinn-) Phong 模型可以说是最经典非物理的 BRDF 模型之一,它计算简洁,效果合理,至今仍在硬件性能不高的实时渲染应用中得到广泛应用。

严格而言,由于 ambient 项的存在,Blinn-Phong 模型实际上是对渲染方程做了近似,而非对 BRDF 做了近似。

但如果认为全局的 ambient 项近似等价于从积分中获取间接光照,可以认为,Blinn-Phong 模型就是 Lambert 漫反射模型 + Blinn-Phong 高光模型。

PBR:Albedo-metallic 工作流

对于实时渲染中漫反射和镜面反射的普遍误解

经过工业界和学术界的共同探索,基于物理的渲染(PBR)成为了十几年来次世代渲染模型的代名词,在无数影视和游戏作品中大放异彩。Albedo-metallic 工作流是 PBR 的代表模型,即运用微表面模型的光照模型的代表。这一工作流的 BRDF 的通式为

\[ f_r(\boldsymbol \omega_i, \boldsymbol \omega_r) = k_d \cdot af_d(\boldsymbol \omega_i, \boldsymbol \omega_r) + k_s \cdot f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) \]

其中:

  • \(a \in [0,1]^3\) 为 albedo 或 base color,它与 Albedo Specular 工作流中的 diffuse 有细微差别。
  • \(f_d\) 为漫反射(diffuse)分量,通常为 Lambert 模型。
  • \(f_s\) 为镜面反射(specular)分量,通常为微表面模型。

一个典型的 BRDF 代表取 \(k_d = (1 - F_{\text{avg}}) (1-m), k_s = 1\),即

\[ f_r(\boldsymbol \omega_i, \boldsymbol \omega_r) = (1 - F_{\text{avg}}) (1-m) af_d(\boldsymbol \omega_i, \boldsymbol \omega_r) + f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) \]

其中:

  • \(m \in [0,1]\) 为 metallic。
  • \(F_{\text{avg}}\) 为近似计算的菲涅尔项,可用 \(F_0\)\(F_0 + (\max(1 - \alpha, F_0) - F_0)(1 - (\boldsymbol \omega_r \cdot \boldsymbol n)_+)^5\) 近似。条件允许时,也可以精确计算 \(F\)\(1 - F_{\text{avg}}\) 这一项的加入是为了考虑一点能量守恒。

有一些 BRDF 的实现并没有考虑为 \(k_d\) 加入 \(1 - F_{\text{avg}}\) 这一项,取 \(k_d = 1-m, k_s = 1\),不过视觉上其实很难看出差异。

还有一些 BRDF 会取 \(k_d = 1-m, k_s = F_{\text{avg}} \approx F_0\),即

\[ f_r(\boldsymbol \omega_i, \boldsymbol \omega_r) = (1-m) af_d(\boldsymbol \omega_i, \boldsymbol \omega_r) + ((1-m)\tilde F_0 + ma)f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) \]

这种 BRDF 的效果看上去也是合理的,不过 specular 部分的权重相对会被略微缩小。不过,这个式子在 PBR 中很可能有问题,因为 \(f_s\) 里面还有一个菲涅耳项 \(F\),但外部又乘了一个,导致 \(F\) 实际以二次的形式作用于高光部分。但若 \(f_s\) 中不含菲涅耳项 \(F\)(如使用 Blinn-Phong 模型),\(k_s\) 这么设置是有道理的,可以控制高光的颜色。

PS:

  • Albedo Metallic 工作流中的 base color 和 Albedo Specular 工作流中的 diffuse 都可以叫 albedo。
  • Albedo Metallic 工作流中,不止漫反射,镜面反射也与 albedo (base color) 有关,这会体现在 specular BRDF 的菲涅耳项 \(F\) 中。
  • 有时,为了让美术达到效果,在某些材质中,可能会为 \(k_s\) 乘上 specular tint(高光染色)这个参数,这类似于仅在镜面反射部分有效的 base color。

解析的漫反射 BRDF

Lambert 模型

\[ f_d(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{1}{\pi}, \]

由于 Lambert 模型过于简单,与 \(\boldsymbol \omega_i, \boldsymbol \omega_r\) 均无关,因此也有 Disney 改进的漫反射模型(并不能量守恒),考虑了表面的粗糙度,其与 \(\boldsymbol \omega_i, \boldsymbol \omega_r\) 的余弦有关。Frostbite 引擎中的漫反射可选用 Disney 改进的漫反射模型。

Lambert 模型中,漫反射与粗糙度(微表面法线偏离宏表面法线的程度)没有关系。这是因为,漫反射的原理是:光进入物体被吸收,光线在内部“随机”地继续向内被吸收或向外反射出去。在 Lambert 的假设下,由于经历了多次弹射,这些向外反射的方向宏观上是均匀的,故产生了全向的漫反射,不需要考虑表面的粗糙度。但在现实物理中,漫反射会与表面粗糙度有关,因此可以运用微表面模型进行更复杂的建模(尽管在实时渲染中一般用不到)。

对于金属 \(m = 1\) 的情形,没有漫反射,可以理解为此时金属全部吸收了非 base color 的光线,没有在内部经过多次弹射再从其他角度反射出去,而 base color 的光线则全都镜面反射出去了。

Half Lambert 模型

这是《半条命》的光照模型,让暗面也有亮度的变化。它没有物理依据,但能带来提亮的视觉效果,也常用于 NPR 中。

\[ f_d(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{\alpha(\boldsymbol \omega_i \cdot \boldsymbol n) + \beta}{\pi (\boldsymbol \omega_i \cdot \boldsymbol n)_{+}}, \]

其中 \(\alpha\)\(\beta\) 为可调节的参数。注意分子的点积可以为负值。对于背光面,\(\boldsymbol \omega_i \cdot \boldsymbol n < 0\),一般取 \(\alpha = \beta = 1/2\),如此即可将分子结果映射到 \([0,1]\),同时让暗面具有亮度变化。

分母的 \((\boldsymbol \omega_i \cdot \boldsymbol n)_{+}\) 是为了抵消渲染方程积分项中的那一项而存在的。

其他漫反射模型

漫反射也可以用微表面模型建模,但那大概是离线渲染才会考虑的内容,此处不再赘述。

解析的镜面反射 BRDF

完全镜面反射模型

已知入射向量和法线,那么镜面反射向量的计算

\[ \text{reflect}(\boldsymbol \omega_i, \boldsymbol n) = 2(\boldsymbol \omega_i \cdot \boldsymbol n) \boldsymbol n - \boldsymbol \omega_i. \]

如果反射仅发生在 \(\text{reflect}(\boldsymbol \omega_i, \boldsymbol n)\) 这个镜面反射的方向上,那么 BRDF 形如冲激函数

\[ f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{\delta(\boldsymbol \omega_r - \text{reflect}(\boldsymbol \omega_i, \boldsymbol n))}{K} \]

其中 \(K\) 是用于归一化的校正因子,满足 \(K = (\boldsymbol \omega_i \cdot \boldsymbol n)_{+}\),因为渲染方程积分项里面有这个,但镜面反射不考虑 Lambert 修正量,所以要抵消它。

Phong 高光模型

这是一个古老的 Specular BRDF:

\[ f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{(\boldsymbol \omega_r \cdot \text{reflect}(\boldsymbol \omega_i, \boldsymbol n))_{+}^{\alpha}}{K} \]

其中

  • \(K\) 的意义同上
  • \(\alpha\) 为光泽度,值越大高光越明显。但较大的 \(\alpha\) 并不会让材质显得光泽,反而会很假

Blinn-Phong / Kajiya-Kay 高光模型

这是一个在 Phong 的基础上改进的,古老的 Specular BRDF:

\[ f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{(\boldsymbol \omega_h \cdot \boldsymbol n)_{+}^{\alpha}}{K} \]

\(K\)\(\alpha\) 的意义同上。

半程向量常与 \(\boldsymbol n\) 做点积,该结果越大,则此处的微表面呈现高光(镜面反射)越明显。

https://zhuanlan.zhihu.com/p/135910659

(Blinn-) Phong 和 Kajiya-Kay 其实是同一个光照模型,只不过前者用于一般物体表面(正半球)上,后者用于毛发表面(微圆柱的一个截面)上,因此后者会用圆柱的走向向量 \(\boldsymbol t\) 代替法向量 \(\boldsymbol n\) 进行光照计算,实际上是只取了一个影响最大的法线做 Blinn-Phong 光照计算,得到近似的结果,公式为

\[ f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{\left(\sqrt { 1 - (\boldsymbol \omega_h \cdot \boldsymbol t)^2}\right)^{\alpha}}{K} \]

Marschner 高光模型

这是一个关于毛发的散射模型,比较复杂。

\[ f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) = \text{Gaussian}(\dots) \]

用于镜面反射的微表面模型

这是当下实时渲染引擎统一使用的 Cook-Torrance Specular BRDF (microfacet specular BRDF):

\[ f_s(\boldsymbol \omega_i, \boldsymbol \omega_r) = \frac{D(\boldsymbol \omega_h, \boldsymbol n, \alpha) F(\boldsymbol \omega_r, \boldsymbol \omega_h) G(\boldsymbol \omega_i, \boldsymbol \omega_r, \alpha)}{4 (\boldsymbol n \cdot \boldsymbol \omega_i)_+ ( \boldsymbol n \cdot \boldsymbol \omega_r)_{+}}, \]

  • 其中 \(\alpha \in [0,1]\) 为粗糙度(roughness),为微表面法线偏离宏表面法线的程度。光滑度(glosiness)= 1 - 粗糙度。

下列依次介绍 \(D, F, G\)

法线分布函数

法线分布函数(NDF),定义为物体表面微元的微表面面积与宏表面面积之比,再除以单位立体角,其量纲与 BRDF 相同。它描述微表面法线 \(\boldsymbol \omega_h\) 在宏观表面上的统计分布,故得名“法线分布函数”。\(D(\boldsymbol \omega_h, \boldsymbol n, \alpha) \cdot (\boldsymbol \omega_h \cdot \boldsymbol n)_+\) 是关于 \(\boldsymbol \omega_h\) 的概率密度函数。游戏引擎中,NDF 一般采用 GGX(ground glass unknown),为

\[ D(\boldsymbol \omega_h, \boldsymbol n, \alpha) = \frac{\alpha^2}{\pi((\boldsymbol \omega_h \cdot \boldsymbol n)_{+}^2 (\alpha^2 - 1) + 1)^2} \]

  • \(\alpha\) 较大时,specular 主要呈现 Diffuse Reflection,高光不明显——有人将这样 \(\alpha\) 较大的材质称为“漫反射材质”,实际上这与一般讨论的 Lambert 漫反射项没有关系,或称“粗糙反射材质”较合适。
  • \((\boldsymbol \omega_h \cdot \boldsymbol n)_{+} = 1\) 时,\(D = \frac{1}{\pi \alpha^2}\),即在镜面反射方向上,粗糙度越低,高光的亮度越高。
  • \((\boldsymbol \omega_h \cdot \boldsymbol n)_{+} = 0\) 时,\(D = \frac{\alpha^2}{\pi}\),即在镜面反射方向的垂直方向上,粗糙度越高,粗糙反射的亮度越高。
  • \(\alpha = 1\) 时,\(D = \frac{1}{\pi}\),此时为完全粗糙反射,类似 Lambert 漫反射。
  • \(\alpha \to 0^+\) 时,\(D \to \frac{0^+}{\pi(1- (\boldsymbol \omega_h \cdot \boldsymbol n)_{+}^2)}\),此时越接近镜面反射方向,高光的亮度越高,但需要很完美的镜面反射方向才能采集到高光,即高光与非高光区域的阶跃更明显。当 \(\alpha = 0\) 时,一般 \(D=0\),但在镜面反射方向,有 \(D = \frac{0}{0}\),常见的处理方式是直接认为 \(D = 0\),此时不存在高光,\(f_s = 0\)。为了避免这种反直觉的情况出现,一般的引擎会 clamp \(\alpha\) 的值,例如令其最小值为 \(0.001\)
菲涅尔项

菲涅尔项为 \(F\),描述在掠射角(\((\boldsymbol \omega_r \cdot \boldsymbol \omega_h)_{+}\) 接近 \(0\))时能观察到更强烈的镜面反射的现象,一般采用 Schlick 近似

\[ F(\boldsymbol \omega_r, \boldsymbol \omega_h) = F_0 + (F_{90} - F_0) (1 - (\boldsymbol \omega_r \cdot \boldsymbol \omega_h)_{+})^5 \]

  • 其中 \(F_0\), \(F_{90}\) 为材料在 $ _r, _h $ 分别为 0 度(垂直入射)和 90 度(掠射)时的菲涅尔反射率。
  • 由于这是镜面反射部分的菲尼尔项,因此 \((\boldsymbol \omega_i \cdot \boldsymbol \omega_h)_+ = (\boldsymbol \omega_r \cdot \boldsymbol \omega_h)_+ \approx (\boldsymbol \omega_i \cdot \boldsymbol n)_+ \approx (\boldsymbol \omega_r \cdot \boldsymbol n)_+ = \cos \theta\),式中的 \((\boldsymbol \omega_r \cdot \boldsymbol \omega_h)_{+}\) 可能以由不同的方式出现。
  • \(F_0, F_{90}\) 都有公式解,基于物体表面与光线传播介质的折射率。通常情况下,\(F_{90}\) 可以用 1.0 近似,因为在掠射角的镜面反射相当强烈。
    • 对电介质(非金属),一般取 \(F_0 = \tilde F_0 = \left| \frac{n_1 - n_2}{n_1 + n_2} \right |^2 = 0.04\),其中 \(n_1 = 1.5, n_2 = 1.0\) 为介质折射率,此时 \(F_0\) 为单分量标量;如果 specular 生效,\(\tilde F_0\) 由 specular 决定:在 UE 中,specular = \(\text{saturate}(\frac{\tilde F_0}{0.08})\),因此默认 specular = 0.5 对应 \(\tilde F_0=0.04\)
    • 对金属(导体),其折射率为复数,不能用上式计算 \(F_0\),一般不使用物理正确的 \(F_0\),而是取 $ F_0 = a$(albedo)。尽管不物理,但这样设置的视觉效果整体上是对的。
    • 对 metallic \(m \in (0,1)\) 的材质,可设 $F_0 = (F_0, a, m) $。这样计算是因为 \(m \in (0,1)\) 的情况下 \(F_0\) 应当介于电介质和金属之间。尽管不物理,但这样设置的视觉效果整体上是对的。
    • 一些渲染引擎可能还会有一些 hack,详见 Filament 的做法,这里不再赘述。

在游戏引擎中,菲涅尔项

\[ F = \text{saturate}( F_0 + (1- F_0)(1- \boldsymbol n \cdot \boldsymbol v)^\gamma) \]

往往可以用来做一些非物理的“造假”视觉效果。例如:

  • 获取物体边缘。可以想象对一个球体而言,物体边缘位于 \(\boldsymbol n \cdot \boldsymbol v \to 0\) 的位置,因此 \(F \to 1\),反之 \(F \to 0\),即可获得物体边缘的蒙版。进而可以:
    • 进行卡通渲染描边。
    • 勾勒透明物体的视效。观察到日常生活中,玻璃的边缘往往具有较高的不透明度,而中间往往透明度高。
    • 线性插值折射率,获得玻璃变形效果(UE 的 refraction 节点)
    • 对掠射角下的片元做额外着色。一些天鹅绒材质可能应用这种效果(sheen)
几何函数

几何函数为 \(G\),为统计学上的微表面自遮挡关系,近似方式多种多样。常用的几何函数有 Smith-GGX:

\[ G(\boldsymbol \omega_i, \boldsymbol \omega_r, \alpha) = G_1(\boldsymbol \omega_i, \alpha) G_1(\boldsymbol \omega_r, \alpha) \]

其中

\[ G_1(\boldsymbol \omega, \alpha) = \frac{2 (\boldsymbol n \cdot \boldsymbol \omega)_+}{(\boldsymbol n \cdot \boldsymbol \omega)_+ + \sqrt{\alpha^2 + (1 - \alpha^2)(\boldsymbol n \cdot \boldsymbol \omega)^2}}. \]

\(G\) 这一项可以在掠射角时,避免结果过亮。详见下文。

分母

分母 \(4 (\boldsymbol n \cdot \boldsymbol \omega_i)_+ ( \boldsymbol n \cdot \boldsymbol \omega_r)_{+}\) 为校正因子。当 \((\boldsymbol n \cdot \boldsymbol \omega_i)_+\)\(( \boldsymbol n \cdot \boldsymbol \omega_r)_{+}\) 接近于 0 时,即掠射角时,整个 \(f_s\) 可能很大,产生光晕的 artifact,这个时候就需要几何函数 \(G\) 项来修正:\(G\) 在掠射角时总会是一个很小的值。