5.2 理论介绍
由于文章篇幅限制,本章简单介绍LTC理论部分,重点放在几何意义上,借助大量图表,帮助读者建立直观理解。
5.2.1 LTC简介
通过对球面函数Do(ωo)应用一个3×3的变换矩阵M将会得到一个新的球面函数D(ω),满足下列性质:

其中:

上述结论在求解面光源积分中的应用如下。
存在一个球面函数Do(ωo)对多边形求积分存在解析解,找到一个变换矩阵M将Do(ωo)变换成D(ω)≈fr(V,ω),那么就可以通过这个逆变换M-1,将多边形P变换为Po,通过求解来达到近似求解
的目的。其中,V为视向量(View Vector),fr为BRDF函数。
Do(ωo)可以为任意的球面函数,只需要保证这个函数对多边形可积分,可重要性采样即可。比较流行的选择有Spherical Harmonics及Clamped Cosine(后续章节出现的Cosine等价于Clamped Cosine),出于性能考虑我们使用Cosine函数。
球面Cosine函数对多边形积分为:

存在解析解:

式中,j=i+1;pi为多边形的第i个顶点。
论文中并没有给出上式的证明,感兴趣的读者可以查看文章[4]与文章[5],两篇文章分别对这一结果使用不同的方法进行了推导。由于这部分内容不是本章重点,不再深入阐述,跳过不会对后续阅读造成障碍。
5.2.2 使用LTC对Microfacet BRDF进行拟合
Real-Time Polygonal-Light Shading With Linearly Transformed Cosines[6]表示可以对半球面函数Do(ωo)=cosoω进行下列形式的M矩阵的变换,以此来达到对Microfacet BRDF的拟合。

目标是优化下面的函数,使得D(ω)与fr(V,ω)的误差尽量小。

在开始解决具体的问题之前,先来了解一下这5个变量的几何意义。
通过观察图5.1与图5.2,我们发现m00为关于x轴缩放,m11为关于y轴缩放,m22为关于z轴缩放,m02为在zx平面上旋转,m20为在zx平面上偏移。

图5.1 m00、m11与m22变量

图5.2 m02与m20变量
然而即使有了这5个变量的直观理解,想要直接求解这个5维的优化问题仍然很困难,需要降低问题的复杂性。
首先将问题简化,使用Phong BRDF代替游戏中常用的GGX BRDF,在Phong的情况下,可以将Cosine函数通过缩放与旋转矩阵来达到对Phong的近似,其中旋转矩阵的z轴为反射向量。另外,由于Phong模型相对反射向量是对称的,所以缩放矩阵的m00与m11相等,问题简化为单变量的优化问题,就很容易解决了。
图5.3所示为视线方向与法线的夹角成30°且物体表面的粗糙度为0.6时的缩放与旋转过程。通过使用上面描述的目标函数作为损失函数,用scipy.optimize.minimize来求解这个优化问题。

图5.3 LTC对Phong拟合的缩放与旋转过程
有了前面的经验,考虑将Phong替换成GGX。GGX相比Phong在BRDF的形状上有两个区别。
(1)GGX投影在球面上的形状是一个椭球,可以通过对m00及m11应用不同的缩放系数来近似。
(2)如图5.4所示,GGX反射的主要方向与反射向量存在一定的偏移,这种现象在文章[7]中被称为Off-Specular Peak,其给出了在Image Based Lighting的应用下,对这一现象的近似。在LTC的情况下,这一现象与我们对m02变量的直观理解一致,可以通过修改m02来对这一现象进行近似。
在拟合的过程中,为了提供一个更好的初始值,使用一个前置步骤来计算BRDF的主要方向并使用这个主要方向作为LTC旋转矩阵的z轴。

图5.4 Off Specular Peak现象

所以对于GGX的LTC近似问题,依然可以使用与Phong相同的思路进行求解,其中旋转矩阵的z轴为GGX BRDF的主要方向,缩放矩阵需要使用m00与m11进行缩放,同时使用m02进行zx平面上的旋转,图5.5展示了这一过程。同样使用scipy.optimize.minimize,不过这次从1维的优化问题扩展到了3维,然而这样依然比直接求解5维的优化简单许多。另外,对于优化问题的初始值,上次优化的结果会作为下一个迭代的输入,以此来保证结果的连续性。

图5.5 LTC对GGX拟合
通过上面的求解得到了缩放矩阵的m00、m11与m02,然而在游戏运行时并没有办法准确计算出GGX BRDF的主要方向,无法通过这3个变量还原出M矩阵,而且在运行时需要使用的是M-1,所以我们选择直接保存M-1矩阵,这样就需要存储5个变量,需要两次贴图查表操作,如果将变量控制在4个以内,就只需要一次查表操作。回顾LTC中关于D的解析式:

分析上面的解析式可以得到,用λIM-1替换M-1后,解析式依然成立。其中,λ为常量,I为单位矩阵。

所以可以将M-1矩阵除以m00、m11、m22任意一个来达到将数据压缩成4个的目的,同样的操作对M矩阵也成立,这里不再赘述。通过对各个数据的分析发现,将M-1通过m11进行归一化,将得到最好的结果,如图5.6和图5.7所示。

图5.6 原始M矩阵数据

图5.7 M-1通过m11进行归一化
5.2.3 简单实现
下面为Shader的实现代码,其中各量的含义如下。
N:法线向量。
V:视向量。
P:当前计算着色点的位置。
points:光源的顶点位置。
NoV:N与V的点乘。
linearRoughness:材料的粗糙度。
twoSided:光源是否为双面。

