02 - 光照、材质和着色器
本文继续介绍了一些游戏渲染相关的基础知识,包括渲染方程,全局光照,PBR,着色器等内容。
PS:这篇笔记结构看起来还是有点乱,待我学完GAMES202相关内容后进一步修改。
光照部分
渲染方程
1986年Kajiya提出了渲染方程,图形学领域的命运齿轮就此转动。
如图,渲染方程主要有以下几部分:
- 自发光项Le:该点自己发出的光。
- 反射项(积分部分):半球区域周围的光在该点反射的光。其中fr是BRDF。
光的种类
渲染方程看起来简单,但动手做起来却很难,因为现实世界里有着各种各样的光。如上图,有直接光、环境光、反射光、折射光和Caustics
现象等。
渲染方程带来的挑战
利用好渲染方程去渲染那么多种类的光,给人们带来的许多挑战。
光的可见性
典型的例子之一就是阴影:
阴影给我们一种层次感,没有它就无法正确辨别物体间的空间关系。
除此之外,还有 光源 带来的问题:
光源的复杂性也是挑战之一,如点光源、面光源等。
计算复杂性
渲染方程中有个球面积分项,很难算,如何快速准确的算出光线与材质的积分结果也是一个问题。
所有物体都是光源
光有直接光和间接光,间接光是由直接光通过弹射产生的,典例为康纳尔盒。如何高效实现全局光照(Global Illumination,GI)这又给我们的算法/计算带来了挑战。
基础光照
接下来说说基础光照是怎么组成的。别想那么多复杂的东西,先从最简单的开始。
环境光
首先引入 环境光(ambient)这一概念,它综合了周边环境给着色点贡献的光,就是一个常量。
然后为了让物体表面看起来更真实(可以反射周边的环境),引入 环境贴图(Environment Map)这一概念。
这些东西其实是符合渲染方程的,我们简单地模拟了一个半球的环境:
Blinn-Phong光照模型
接下来引入Blinn-Phong
模型,它除了有环境光外,又有了漫反射项(Diffuse)和高光项(Specular),使物体看起来更好。该模型十分经典,上手简单,用于教学和早期游戏渲染。
但该模型有一些问题:
- 能量不守恒,因为这个模型不是基于物理的(例如环境光居然是个常数,没有物理定义)。
- 不真实,渲染的物体都有股塑料感。
阴影
然后引入阴影,阴影就是物体挡住光线,被人看见的部分。人们在这个领域上实现了很多算法,如shadow volume等。
但在游戏引擎行业,只用Shadow map
:
在GAMES101中有提到过,详见我之前的文章。但Shadow Map
还是有一些问题的,例如光源视角和相机视角的采样率不一样,会产生假象(artifact)。
综上,这就是渲染引擎的基础光照解决方案,基本解决了上边提出的三个挑战。
基于预计算的全局光照
对于3A游戏行业的工程师来说,他们对基础光照模型还是不满意,要精益求精。这里说说5~10年前3A游戏的流行技术:基于预计算的全局光照(Pre-computed Global Illumination)。
这是典型的空间换时间思路,认为场景中有90%的物体是静止的,这样就可以提前进行计算,加速他们的渲染。
全局光照
全局光照,就是直接光加上间接光:
全局光照使得画面更真实,玩家体验更好。
间接光
类比上边的环境贴图,我们也能将间接光做成一个材质球:
信息压缩
间接光数据量庞大,得先把这些数据给压缩一下,傅里叶变换就是一个很好的法儿。为了让计算更加方便,这里引入球谐函数(Spherical Harmonics):
球谐函数可以用多项式的形式近似(展开几阶,通常是1)表示出某一信号,利于傅里叶变换的卷积操作。
接下来,利用球谐函数对Irradiance进行压缩,可以发现它虽然很糊,但基本描述了光是从哪儿来的,且数据是连续的:
由于要存储4个RGB值,需要12个SH(球谐函数)参数,且它们的权重也不一样:
全局光照的表示
Light Map
用空间换时间,把整个场景的光照烘培到一张2D图上,被烘培的图被称作atlas
。
Lightmap的主要环节如下:
几何简化
省略过多模型细节,将它们进行分块简化操作,以便更好地烘培。
Lighting
然后开始正式烘培,消耗很长时间,得到成果:
上材质
最后将模型的材质上上去,得到的成果如下:
使用Lightmap的优缺点如下:
- 优点:
- 运行时高效率
- 对全局光照细节处理到位,艺术家很喜欢
- 缺点:
- 预计算时间(烘培时间)很长
- 只能解决静态场景/静态光
Light Probe
由于每个采样点是一个半球,那就索性在空间上铺满一堆半球作为探针(Probe),对它们进行采样。当有物体接近它们时,再做出改变。大多数Probe只是用于全局光照,因此也被称为Light Probe。
Probe的生成
早期工程中,Light Probe是人为摆放的,但效率低,容易出错。现代工程中,人们大多使用程序自动化生成的方法。
Reflection Probe
Probe大多数是搞漫反射的,因此采用信息压缩方式,对低频不影响。而有时候我们需要Probe做一些高频反射,且精度高,这就得特制一种Reflection Probe了:
使用Probe的优缺点如下:
- 优点:
- 运行时效率高
- 静态物体和动态物体都能被处理,可以在运行时更新
- 可以处理漫反射Diffuse(用Light Probe)和高光Specular(用Reflection Probe)
- 缺点:
- 计算量大
- 对全局光照的细节处理不到位
因此,将Light Map和Light Probe这两种技术结合起来,便能很好的表示预计算的全局光照了。
经典阴影方法
Cascade shadow
在经典3A游戏中,阴影的主流解法就是使用Cascade Shadow
。游戏世界越做越开阔,远处的山有影子,近处的枪也有影子,它们的精度各不相同。而如果只用shadow map
的话解决不了这个问题,于是分级的Cascade Shadow
便被提出来了。
Cascade Shadow
以视锥体为标准,做出分级的shadow map
(从近到远精度越来越低)。
插值问题
这个方法还存在一个插值问题,就是由于分级导致阴影精度骤降的问题。
通过在Shader里偷鸡可以解决。
优缺点
软阴影绘制
Percentage Closer Filter
大名鼎鼎的PCF算法:
Percentage Closer Soft Shadow
PCSS,基于PCF算法,人们更常用这个,是游戏引擎里的标配。
Variance Soft Shadow Map
VSSM算法,看下图知道比PCSS算法效率高,人们也喜欢用这个。
材质部分
微表面理论与BRDF
微表面理论描述了法线在微表面上的分布情况,详见GAMES101.
渲染方程中的fr就是BRDF,Fr有两项:
- Lambert漫反射模型
- CookTorrance反射模型
CookTorrance反射模型
CookTorrance反射模型里有著名的三项:
D项:
即法线分布方程,描述法线分布的程度(聚集/发散)或随机度。现在大家都用GGX着色模型(绿色部分),它高频部分很尖,低频部分很缓,很现实。
G项:
描述了微表面凹凸不平表面的内遮挡程度,有多少光在反射时被微表面挡住反射不出来。
F项:
菲涅尔项,例如产生水中倒影的效果。
物理测量的BRDF
与其对BRDF进行调参,仿真某物体的表面,不如直接进行物理测量,这样得到的效果更真实:
迪士尼BRDF信条
业界大牛迪士尼提出了有关BRDF的信条:
- 每一个参数都得符合艺术家的直觉,不要太抽象了
- 参数要尽可能少
- 参数值的范围最好是0~1,特殊情况(如调多了才能出现的效果)可以被豁免
- 所有参数组合都应是稳健和合理的
这些思想同样适用于游戏引擎的制作,游戏引擎不是对自然的模拟器,而是面向设计师的应用工具。
PBR模型
Specular Glossiness模型
简称SG模型,使用RGB参数,很直观:
该模型有一点小问题,就是它太灵活了,例如Specular
的RGB通道,调的不好会导致其他项炸掉。
Metallic Roughness模型
简称MR模型,仅使用一个RGB参数base_color
,剩下的两个参数为粗糙值和金属度。金属度的高低会影响菲涅尔项。
MR虽然符合直觉,但不好区分金属和非金属材质。
两者的对比如下:
此外,它俩还能进行转换操作。
Image-Based Lighting(IBL)
IBL提供了一张Cube的展开图,记录了整个环境光照对材质的运算结果,有细节感和凹凸感。
Diffuse部分
Specular部分
分成两个小部分,发光项和BRDF项:
对于发光项,根据粗糙度\(\alpha\)不同,将预计算好的结果存到一张map中:
对于BRDF项,根据粗糙度和角度不同,将预计算结果存到LUT图中:
将它们综合起来,就能得到IBL渲染效果:
3A游戏的渲染
掌握好这些技术,就能写一个5~10年前3A游戏的渲染引擎了,能写好的话出来找工作就不成问题了(我要努力啊qwq)。
Shader管理
Shader管理对于大厂来说是个问题,主要有以下因素:
- 艺术家创建了一堆shader,量很大
- 在不同条件下的shader内容也不同,碎片shader比较多
Uber Shader
因此可以将这些shader写到一起,用宏定义分开。这叫做Uber Shader
:
跨平台编译
Shader在不同平台有着不同版本,编译起来比较麻烦。
前沿技术
显卡和图形API的快速发展使得渲染行业涌出了许多新兴技术:
实时光线追踪
实时全局光照
更复杂的材质模型
Virtual Shadow Map
参考资料
- GAMES104 (boomingtech.com)