渲染方程
从方程上可以看出某一点的渲染可以归结为该点的自发光加上所有的反射光组成。
- 代表该点的出射光亮度
- 代表该点的自发光亮
- 代表某一入射光线的反射比例,既BxDF,一般为BRDF
- 代表某一入射光的亮度
- 代表入射角带来的入射光的衰减
- 代表入射方向半球的积分
反射方程
顾名思义只描述反射的方程
- 代表被渲染的点
- 代表出射光线的方向
- 代表入射光线的方向
- 代表法线
Cook-Torrance反射方程
因为 已经包含了 所以正确的数学表达应该是
- 代表漫反射所占的比例,根据能量守恒定律
- 代表镜面反射所占的比例
- 代表该点材质的颜色,只有非金属材质才有漫反射,对于金属来说它的颜色隐藏在中
- 代表法线分布函数,描述微正确法线的概率
- 代表菲涅尔方程,描述不同的入射角下反射光线所占的比例
- 代表几何函数,描述微表面未被遮挡的百分比,遮挡包括入射光的自阴影以及出射光的自遮挡
法线分布函数-Trowbridge-Reitz GGX(GGXTR)
- 代表入射光线和出射光线的半角向量
- 代表微表面的粗糙度
菲涅尔方程-Fresnel-Schlick
- 代表出射光线方向,也就是视线方向
- 为基础反射率,也就是当视线垂直与微表面时的反射率,非金属和金属计算 的方法不同,因此 通常都是预计算好的数值
几何函数-Schlick-GGX
- 代表为入射光线
- 代表未被遮挡的光线的比例,它是由未被遮挡的出射光线和未被遮挡的入射光线的乘积计算出来的
直接光照
对于直接光照可以使用Cook-Torrance反射方程计算每个光源的值,然后将它们累加起来,这里不涉及到积分问题,注意反射方程没有包含光线的距离衰减。
非直接光照(全局光照)-IBL
全局光照需要处理半球方向上的积分,为了方便预处理将反射方程分为漫反射和镜面反射两个部分。
漫反射积分处理
立体角不容易积分,将立体角转换为球面坐标系下的面元面积,设球面的半径为1,则可得:
法向量和入射向量均为单位向量,法线为球面坐标的正z轴,入射角即为天顶角,因此可得:
替换上面的等式,将其转变为球面坐标的二重积分,其中天顶角的范围是0~1/2,方位角的范围是0~2
我们需要使用蒙特卡洛方法求解积分,蒙特卡洛积分公式为:
因为样本是均匀分布的,所以可得:,带入上面的公式可得:
根据上面的公式可得漫反射积分的离散形式:
对于irradiance map的预处理我们可以根据上面的公式(去掉kd和c,这两个参数预处理的时候无法获得)使用一张cube map,以法线为半球积分的中间向量进行卷积计算。
镜面反射积分处理
因为漫反射对于各个方向的散射是均匀的,所以我们在半球上均匀采样就可以获得比较准确的近似。但是镜面反射的强度跟视线方向,宏观表面的法线以及微表面的粗糙度相关,在半球上均匀采样误差会比较大,如下图:
从上图我们可以看出镜面波瓣的形状是由粗糙度决定的,镜面波瓣的朝向是由宏观表面法线以及视线决定的(视线的反射向量R)。
假设wi是光源方向,只有在镜面波瓣中的入射光线对反射才有贡献,其他的入射光线对镜面反射是没有贡献的,因此我们需要尽量采集镜面波瓣中的入射光线,这就需要使用重要性采样。
如果我们已知视线的方向,已知微表面的法线方向,那么我们求得的反射方向r就是我们需要的重要性采样。因为r一定会通过微表面反射到视线中,对镜面反射产生贡献,所以如何求得微平面的法线h,就成了问题的关键。
回想一下法线分布函数,它的定义是给定一个粗糙度a以及一个宏观表面法线n,我们可以确定一个微表面模型,然后再给定一个中间向量h,我们可以根据法线分布函数D(n,a,h) = y,来估算这个微表面中与h取向一致的微表面的比例。换句话说这里的h可以理解为微表面的法线向量。
如果我们知道y值就可以通过反函数D'(y,n,a) = h,来求得微平面法线h。但是法线分布函数的y值不好求解,我们需要换一个思路来解决这个问题。
我们都知道概率累加分布函数CDF的值域是[0,1],如果我们知道CDF函数的反函数,我们就可以在[0,1]中随机取一个值,然后根据这个值求解出一个样本。我们可以从一个离散的分布图来理解这个采样过程。
假定有四个样本1,2,3,4,上面是它们的概率密度分布图。
这个是累积分布函数图,可以看到当我们取值域上的一点ξ,它对应的定义域值为3,这个3就是我们所求得的样本,最后给出UE4重要性采样的做法:
在球面坐标系下,假定球的半径为1,我们已知天顶角和方位角,就可以确定一个方向向量。这个方向向量就是通过GGX重要性采样获取的h向量,获取h向量的步骤如下:
- 使用低差异序列,随机两个数x,y,0<=x<=1,0<=y<=1
- 将x,y带入CDF的反函数中,求出天顶角和方位角
- 根据天顶角和方位角求出h向量
现在的关键问题就是求解CDF的反函数,接下来让我们继续数学之旅。
微表面法线的累加概率分布函数为
- n代表宏观表面的法线
- h代表微观表面的法向量
- 为什么要乘以n和h的点积这个就不解释了,想要了解的请跳转https://www.reedbeta.com/blog/hows-the-ndf-really-defined/。
n和h都是单位向量,因此可以将点积转换为余玄
GGX的NDF形式如下:
将其转换为概率密度函数:
为什么会多乘一个sin,是因为将立体角转换为球面坐标系,其实是求解球面面元的面积,球坐标的面元面积是:
求的边缘概率密度
求条件概率:
分别求和的概率累积分布函数:
通过代数求得:
的概率累积分布函数:
基于上面的公式我们就可以使用GGX重要性采样来获取样本h了。但即便我们使用了重要性采样来加速收敛,实时计算量依然很大,我们还需要进行预处理,因为镜面反射的积分涉及到很多变量,我们必须想办法将预计算的结果保存到少量的资源中,因此UE4提出了分裂和算法。
在推导分裂和算法之前,先解决一个问题,我们需要pdf(wi),但是我们只有pdf(h),我们需要根据pdf(h)来求解pdf(wi),下面给出转换公式以及证明过程:
如上图:
因为因此
因为且因此则
因为且则
因为且则
因此
因为带入上面的等式
因此最终推导出
分裂和公式
在介绍分裂和公式之前先看一下镜面反射的积分公式
首先ks我们可以从积分中提取出来,我们观察这个积分公式需要哪些参数,参数有粗糙度a,F0,视线方向V,法线N,全局的入射光线Wi。第一反应就是先把全局的入射光线搞定,方法类似于漫反射的辐照图,因此我们需要把Li部分从积分中提取出来,按照这个思路UE4给出了分裂和公式:
其中权重函数
接下来对上面的分裂和公式进行推导
首先把L从积分中去掉
之前我们已经推导过pdf(h)和pdf(wi)的转换公式因此可得:
将概率密度带入上面的等式:
上面的方程中需要很多参数,比如宏观表面的法线向量n,视线的向量v,这些参数无法在预处理阶段给出,于是UE4继续进行了简化,它令Wo=N=R,也就是说输出向量Wo等于反射向量等于法线向量。因为N=R,所以R=V,所以Wo=N=R=V。因为V=N,所以根据菲涅尔定律,我们可以知道F是一个定值。
因此可以把F项从函数中舍去,那么约去点乘式上面的函数可以简化为:
根据Smith shadowing-masking approximation可知:
那么有:
注意这里面因为R=n,所以G(n,n,k)=1
近似变换后有:
因为:
这个约等感觉有点硬贴了,为了能够得出UE4的公式,估计这两个函数的曲线应该比较接近,我没有进一步验证。
最后得到:
其中就是预处理贴图的计算公式。
预计算环境贴图(prefilter environment map)
在预计算环境贴图的时候,我们需要使用重要性采样,上面我们已经了解到CDF的反函数需要传入一个粗糙度,为了得到这个a值,UE4使用了mipmap,将a值离散到不同的mipmap中。因此我们会获得一个带有mipmap的cubmap。在采样的时候,使用三线性插值即可。因为这篇文章关注点在数学上,这里只是提一下。
BRDF LUT
这是最后一步了,让我们看看需要求解的积分:
观察这个积分涉及的变量,有基础Fo,a,Wo,n这四个变量,先想办把Fo去掉:
通过上面的推导我们把Fo变量提取出来,因为fs中已经包含了F,所以F(Wo,h)可以约掉。我们将scale和bias的值存储在LUT的两个通道中。接下来只需要求解scale和bias即可,我们继续使用蒙特卡洛积分求解这两个变量:
可以看到,上面的函数只与a和dot(n,Wo)相关,因此我们可以将a与dot(n,Wo)做为LUT的uv坐标,然后进行积分求解,获得的scale和bias分别存储在LUT贴图的两个通道中即可。
最后感谢以下链接的博主
https://www.cnblogs.com/timlly/p/10631718.html?from=timeline&isappinstalled=0
https://zhuanlan.zhihu.com/p/95865910
https://zhuanlan.zhihu.com/p/66518450
https://www.cnblogs.com/wickedpriest/p/13788527.html