标准光照模型
当光照射到物体表面时,物体对光会产生反射、吸收、透射、折射、衍射等现象,反射和透射的光进入人的视觉系统,使我们能看到物体。为模拟这一现象,我们建立一些数学模型来替代复杂的物理模型,这些模型就称为光照模型。 标准光照模型计算公式如下:
颜色 = 自发光 (emissive)+ 高光反射(specalur)+漫反射(diffuse)+环境光(ambient)
自发光:材质的自发光颜色。
环境光:通过周围的环境物体反射光的部分来模拟间接光照。
高光反射:我们假定物体表面光滑,只有一个镜面,那么所有的光都被反射向了同一个方向,这就是高光反射。受视角方向、光照方向、表面法线的影响,从不同角度观察,得到的结果不一样。在渲染中我们用BlinnPhong模型来表示高光反射。下面是该模型的计算公式
漫反射:漫反射是用于对物体表面随机散射到各个方向的光照进行建模,在漫反射中,因为反射完全是随机的,所以视角位置就不重要了,但是入射光线角度很重要。它的模型计算公式如下:
PBR光照
PBR,基于物理的渲染,全称(Physically Based Rendering),是与现实世界物理学原理相符的理论构建的渲染模型,使渲染的效果有迹可循,实现以真实物理参数为依据来编写渲染材质,得到具有物理意义的渲染效果。Unity自带的Standard Shader就是一个完整的PBR,但在实际使用中需要进行一些调优。
PBR光照模型满足下面三个条件:
1.基于微平面的表面模型。
2.能量守恒。
3.应用基于物理的BRDF渲染模型。
微平面模型
所有的PBR技术都基于微平面理论。这项理论认为,达到微观尺度之后任何平面都可以用被称为微平面(Microfacets)的细小镜面来进行描绘。根据平面粗糙程度的不同,这些细小镜面的取向排列就不一致。一个平面越是粗糙,这个平面上的微平面的排列就越混乱,当镜面反射时,入射光线更趋向于向不同的方向发散,然后产生范围更广泛的镜面反射;与之想反,对于光滑的平面,光线大体上会更趋向于向同一个方向反射,造成更小更锐利的反射效果。
我们一般用统计学的方法估算粗糙程度,粗糙度表示微平面上平均取向方向和半程向量方向一致的概率。半程向量的计算方法如下:
微平面的取向方向与半程向量的方向越是一致,镜面反射的效果就越是强烈越是锐利。如下图所示,当粗糙度越小的时候,反射更集中更亮,当粗糙度越大的时候,镜面反射轮廓更大颜色更暗。
能量守恒
出射光线的能量永远不能超过入射光线的能量。当一束光线碰撞到一个表面的时候,它就会分离成一个折射部分和一个反射部分。反射部分会直接反射开来,这就是我们所说的镜面光照。折射部分就是余下会进入表面并被吸收的那部分光线,也就是漫反射光照。
现实中光照能量不会被全部吸收,光线会继续沿着随机的方向发散,然后与其他粒子碰撞直到能量耗净或者再次离开这个表面,光线脱离物体表面会协同构成表面的漫反射颜色,这就是次表面散射(SubSurface Scattering)的原理,它会显著提示皮肤,蜡像这样材质的视觉效果,但伴随的是性能下降的代价。在PBR渲染中我们对光照传播进行了简化,假设对平面上每一点所有的折射光都会被完全吸收而不会散开。
于是根据能量守恒,我们先计算镜面反射,折射部分就可以直接由镜面反射部分计算得出:
float ks = calculate_specular(); //镜面反射
float kd = 1.0 - ks; //漫反射
BRDF
双向反射分布函数,这是PBR的核心,是如今我们所拥有的用来模拟光的视觉效果最好的模型。渲染方程如下:
半球积分表示多光源下光照的叠加。如果只考虑单个不衰减的直线光照,这个半球积分可以去掉
用比较通用的语言解释下,大概是这样的
如果把镜面反射比例设置为0,那么漫反射比例就为1,公式就可表示为如下:
这个就和Lambert漫反射光照模型差不多了,不一致的是除了这个π,把对应的漫反射亮度调低了。这里简单解释下除以π的原因, dw在辐射学里表示立体角,这里我们表示视角,用公式表示为 , 通过积分计算可以得出半球积分
,如果散射的光线最后都能汇集到一点的话,积分的结果就是会再乘一个π,而BRDF要求在半球内的积分值不大于1。所以分散的时候就需要除π。
,这个叫做Cook-Torrance的BRDF光照公式,表示镜面反射部分,分子上的3个系数含义如下:
镜面高光:法线分布函数(NDF)
估算在受到表面粗糙度的影响下,取向方向与中间向量h一致的微平面的数量。举例来说,假设给定向量h,如果我们的微平面有35%与向量h取向一致,则法线分布函数会返回0.35.目前NDF公式用的是Trowbridge-Reitz GGX那一套,公式如下:
h表示中间向量,a表示粗糙度。
在不同粗糙度参数下,我们可以得到如下图示的效果:
当粗糙度很低时候,与中间向量取向一致的微平面会高度集中在一个很小的半径范围内。由于这种集中性,NDF最终会生成一个非常明亮的斑点。但是当平面比较粗糙的时候,微平面取向就会随机发散,与中间向量取向一致的微平面分布在一个大得多半径范围内,但是同时较低的集中性也会让我们的效果显得比较灰暗,这是符合物理现实的。
GLSL的shader代码如下:
几何阴影:几何函数(Geometry function)
描述的是微平面自成阴影的属性。当一个平面比较粗糙的时候,平面表面上的微平面有可能挡住其他的微平面从而减少表面所反射的光线。
它采用的是Schlick-GGX那一套公式
其中Gsub公式如下:
k是粗糙度a基于几何函数针对直接光照或者IBL光照的重映射:
下图是不同粗糙度对应的亮度情况
表现出来的效果就是粗糙度越大,亮度越低。但视线和光线接近垂直时,受粗糙度的影响就越小,也比较符合现实。
k的取值范围都是逐渐逼近1/2.直接光和间接光的差别在于,直接光最小是1/8的吸收系数,而间接光没有,这是因为完全不吸收光线的物体是不存在的,即使是完全光滑的物体,也能吸收一些光线。
GLSL的shader代码如下:
菲涅尔方程:Fresnel equation
描述的是在反射的光线对比被折射的部分所占的比率,会随着观察的角度不同而改变。菲涅尔方程最早用在水体上,因为水的粗糙度低反光能力强,却又不是金属,是菲涅尔效应最明显的物体。
当垂直观察的时候,任何物体或者材质都有一个基础反射率,但是如果与物体法线有一定角度去观察的时候,所有的反光就会变得明显。如果从与法线90度视角观察,所有平面理论上都能完全反射光线。这种现象因菲涅尔而闻名并体现在菲涅尔方程中。菲涅尔Fresnel-Schlick版本的方程式如下:
F0是平面的基础反射率,对于金属物体而言,菲涅尔其实并不明显,因为金属F0参数对不同颜色值的反射率是不同的,而且还需要和表面颜色相乘,否则金属看起来就会很假,于是对F0做了一次这样的处理:
这个0.04代表绝缘体基本反射率,统计了大部分绝缘体取平均值得到。
代入公式结果就比较符合金属的物理属性,对于非金属,金属度较低,即使乘了表面颜色影响也不大。
GLSL的shader代码如下:
至此,关于PBR的直接光照部分就介绍完了,下一章介绍下PBR的IBL部分。