04 - 渲染管线、后处理与其他

终于要填坑了!本文将对引擎渲染向的一些内容作进一步补充,包括环境光遮蔽AO的做法,抗锯齿技术,后处理技术,渲染管线等。

环境光遮蔽AO

环境光遮蔽(Ambient Occlusion, AO)能让场景更有立体感。

它是场景中物体自遮挡导致环境光衰减的近似:

预计算AO

在早期人们通过光线追踪给物体预计算AO结果,并存储到纹理中。它只适合静态场景,且消耗存储空间,但效果好。

SSAO

SSAO,即屏幕空间环境光遮蔽,它对着色点所在球体内采样并计算遮蔽因子,进而决定环境光的衰减程度。详见Games202相关内容。

实际上不需要对整个球体采样,只需在表面法线上半球采样即可,这种优化被称为 SSAO+

HBAO

HBAO,即水平基准环境光遮蔽(Horizon-based Ambient Occlusion)。它会寻找着色点周围半球上的遮挡边界,然后用这个边界估算环境光对改点的贡献。

主要思想是使用光线步进方法找遮挡边界,然后求积分。

结果比SSAO和SSAO+效果好。

GTAO

即Ground Truth-based Ambient Occlusion。和前3个AO方法相比,它多考虑了从不同角度射入的光对着色点的贡献,即引入了\(\cos\theta\)项。

GTAO强的地方在于它较好地模拟了光多次弹射的情况。它对光多次弹射的结果进行数值分析,并给出和结果曲线差不多的三次多项式拟合曲线:

光追AO

可以用现代GPU进行实时光线投射的AO:

抗锯齿AA

由于最后成像都是逐像素对计算结果采样,导致会出现一定的精度问题,会出现一些走样现象:

因此需要通过抗锯齿以增加游戏体验,基本思路就是增加采样数后取均值,就可以产生较光滑的过渡区域:

SSAA和MSAA

  • SSAA(Super Sample AA),向原画面大x倍的画面进行降采样,性能要求高。
  • MSAA(Multi-sample AA),则只对必要的地方(如边缘处)进行单画面x倍采样,也有一定性能要求,尤其是场景三角形数量极大时。

这两者是古早阶段人们对抗锯齿技术的探索。

FXAA

即Fast Approximate AA,快速近似AA。它将每帧画面的边界提取出来,然后对其进行插值处理以达到快速近似AA的目的。

首先,它将画面的颜色空间从RGB转换到HSL/HSV,根据亮度去寻找整体画面边界:

找到整体边界后,需要计算AA的朝向以便进行混合操作。对边界进行水平和垂直方向的滤波计算,比较二者的值便能知道AA的朝向了:

有了混合朝向后,还需要搜寻和该点相邻的部分边界,需要用到下图的算法,通过比较亮度值找到和该点相邻的边界:

知道朝向和部分边界后,就能求自己朝该方向“偏移”采样的程度了,利用类似相似三角形的原理,通过边界信息求自身的偏移值:

发现结果还不错,效率也挺高:

TAA

TAA则利用时序上的数据(上一帧信息 + Motion Vector)进行AA操作。详细内容见GAMES202。

后处理

后处理是3D图形渲染中重要的环节,主要分为两种。一种是为了场景能够被物理真实地渲染,例如HDR;另一种是为了风格化表达,例如Color Grading。

泛光Bloom

肉眼看光源会有一种发散的效果,这种效果就是泛光Bloom。

要想得到泛光效果,首先需要提取场景中较亮的部分:

然后要对较亮的部分进行高斯模糊,以形成泛光效果。可以将一个大高斯核拆成两个横纵小高斯核减小工作量:

但上述方法的工作量仍然很大,可以将原图缩小几级,从最低级开始进行高斯模糊,然后将模糊图与原图混合并放大,重复操作直至模糊图与原图相同。

最后将原图和模糊图组合到一起即可实现泛光Bloom:

色调映射

色调映射,即Tone Mapping,它将HDR颜色值映射到LDR颜色值。

有多种色调映射曲线,首先看看顽皮狗的Filmic Tone Mapping,通过对曲线进行多项式拟合,进而得到电影级画质的色调映射:

然后是ACES曲线,该曲线更加专业,针对不同类型设备(SDR,HDR)有兼容性:

以下是常用色调映射曲线的对比图:

调色

调色,即Color Grading,用于PS调色等风格化表示。

调色需要用到LUT,用于进行对应风格的颜色映射:

渲染管线

之前提到的各种渲染算法需要有序进行,而这种排序规则便是渲染管线。

前向渲染

即Forward Rendering,对于场景中的每个物体,均要让所有光源渲染一次:

其中,在绘制透明物体时要从远到近地绘制,需要用到透明物排序算法:

但在现代游戏场景中有很多光源,此时前向渲染管线就很吃力,延迟渲染便登场了。

延迟渲染

即Deferred Rendering,分为两个阶段,几何阶段渲染所有物体,并获取相关信息至G-Buffer中;光照处理阶段则根据G-Buffer信息一次性计算光照。

对于渲染多光源场景,Debug等操作很容易;但G-Buffer在移动端上的读写比较麻烦。

基于分块的渲染

即Tile-based Rendering,主要针对移动端渲染。由于移动端容易发热,特别是存储芯片,于是这种渲染管线将场景分割为小块,进行分块渲染减少压力。

除了减少帧缓冲读写压力外,它还将光源进行分割,避免不必要的光照计算。

它还对深度距离进行了优化,通过获取每小块的最大/最小深度值,便能知道该渲染哪些物体不渲染哪些物体。

前向+ 渲染

即基于分块的前向渲染,对移动端非常友好。

基于集群的渲染

在分块渲染上再加一步,对深度值也进行划分,将3D场景分为一块块立体棱柱,对于超多光源光照的处理更灵活。

用V-Buffer代替G-Buffer

G-Buffer存储物体的材质信息,比如深度值、法向量等,在绘制大量物体的场景时上面的信息容易被覆盖掉,浪费许多空间,且采样G-Buffer也会耗时。

而V-Buffer则存储物体的几何信息,比如图元ID、重心坐标等,可以根据V-Buffer信息反差到该物体应该用什么材质。它是未来渲染管线的发展方向。

真实的渲染管线

但真实的渲染管线往往比上面的思想复杂很多,例如下图UE的渲染管线:

存在的挑战

这种渲染管线的管理存在很多挑战,如下图:

Frame Graph

可以用一个有向无环图去管理渲染管线,让人们正确处理依赖关系,减少出错:

渲染到显示器上

画面撕裂与V-Sync

有时候打游戏会出现画面撕裂的情况,这是因为引擎每一帧渲染的时间和屏幕的刷新时间对不上:

于是垂直同步V-Sync技术便出现了,它可以让引擎每一帧渲染输出的时间和显示器刷新的时间对上,但帧率会减少且会降低一定游戏体验。

在此基础上又有了可变刷新率技术,优化了垂直同步的不足。

参考资料

  • GAMES104 (boomingtech.com)