本篇对《Real-Time Rendering》一书中与图形渲染基础和视觉处理相关的知识进行概括总结。主要内容包括:
- 光照与材质
- 着色
- 抗锯齿总结
- 透明渲染
- 伽马校正
1 光照与材质
1.1 光源特性
光被不同地模拟为几何光线,电磁波或光子(具有一些波特性的量子粒子)。无论如何处理,光都是电磁辐射能,即通过空间传播的电磁能。光源发光,而不是散射或吸收光。根据渲染目的,光源可以以许多不同的方式来表示。光源可以分为三种不同类型:平行光源、点光源和聚光灯。
1.2 光的散射与吸收
从根本上来说,所有的光物质相互作用都是两种现象的结果:散射(scattering)和吸收(absorption)。
散射(scattering)发生在当光线遇到任何种类的光学不连续性(optical discontinuity)时,可能存在于具有不同光学性质的两种物质分界之处,晶体结构破裂处,密度的变化处等。散射不会改变光量,它只是使其改变方向。光的散射(scattering)一般又分为反射(reflection)和折射(refraction)。
吸收(absorption)发生在物质内部,其会导致一些光转变成另一种能量并消失。吸收会减少光量,但不会影响其方向。
1.3 镜面反射和漫反射
镜面反射光表示在表面反射的光。而漫反射光表示经历透射(transmission),吸收(absorption)和散射(scattering)的光。
1.4 颜色
入射光(Incoming illumination)通过表面辉度(irradiance)来度量。而出射光(outgoing light)通过出射率(exitance)来度量。出射率除以辉度可以作为材质的衡量特性。对于不发光的表面,该比率为 0 到 1 之间。出射率和辉度的比率对于不同的光颜色是不同的,所以其表示为 RGB 矢量,也就是我们通常说的颜色。
1.5 表面与散射分布
镜面反射项的方向分布取决于表面粗糙度(roughness,其反义词是 smoothness,光滑度)。反射光线对于更平滑的表面更加紧密,并且对于较粗糙的表面更加分散。我们可以看到下图中的这种依赖关系,它显示了不同粗糙度的两个表面的反射效果。
2 着色
可以查看以前的笔记【计算机图形学】(六)着色
3 抗锯齿方法总结
抗锯齿,也称反走样。它是一种消除显示器输出的画面中图物边缘出现凹凸锯齿的技术,那些凹凸的锯齿通常因为高分辨率的信号以低分辨率表示或无法准确运算出 3D 图形坐标定位时所导致的走样(aliasing)而产生的,抗锯齿技术能有效地解决这些问题。
关于抗锯齿的原理可以查看之前的笔记【计算机图形学】(四)反走样,下面将常见的抗锯齿类型进行总结介绍,也包括 RTR 中没有讲到的,最近几年新提出的常见抗锯齿类型。
3.1 超级采样抗锯齿(SSAA)
超级采样抗锯齿(Super-Sampling Anti-Aliasing,简称 SSAA)是比较早期的抗锯齿方法,比较消耗资源,但简单直接。这种抗锯齿方法先把图像映射到缓存并把它放大,再用超级采样把放大后的图像像素进行采样,一般选取 2 个或 4 个邻近像素,把这些采样混合起来后,生成的最终像素,这样每个像素拥有邻近像素的特征,像素与像素之间的过渡色彩,就变得近似,使得图形的边缘色彩过渡趋于平滑。再把最终像素还原回原来大小的图像,并保存到帧缓存也就是显存中,替代原图像存储起来,最后输出到显示器,显示出一帧画面。这样就等于把一幅模糊的大图,通过细腻化后再缩小成清晰的小图。比如在 1024x768 分辨率上开启 2xSSAA,GPU 会先渲染 2048x1536 图像,再“塞进”1024x768 的屏幕中,将画面精细度提升一倍,毫无疑问会改善边缘锯齿情况。超级采样抗锯齿中使用的采样法一般有两种:
- OGSS,顺序栅格超级采样(Ordered Grid Super-Sampling,简称 OGSS),采样时选取 2 个邻近像素
- RGSS,旋转栅格超级采样(Rotated Grid Super-Sampling,简称 RGSS),采样时选取 4 个邻近像素
另外,作为概念上最简单的一种超采样方法,全场景抗锯齿(Full-Scene Antialiasing, FSAA)以较高的分辨率对场景进行绘制,然后对相邻的采样样本进行平均,从而生成一幅新的图像。
3.2 多重采样抗锯齿(MSAA)
多重采样抗锯齿(Multi Sampling Anti-Aliasing,简称 MSAA),是一种特殊的 SSAA,MSAA 首先来自于 OpenGL。具体是 MSAA 只对 Z 缓存(Z-Buffer)和模板缓存 (Stencil Buffer) 中的数据进行超级采样抗锯齿的处理。可以简单理解为只对多边形的边缘进行抗锯齿处理。这样的话,相比 SSAA 对画面中所有数据进行处理,MSAA 对资源的消耗需求大大减弱,不过在画质上可能稍有不如 SSAA。
3.3 高分辨率抗锯齿(HRAA)
高分辨率抗锯齿方法(High Resolution Anti-Aliasing,简称 HRAA),也称 Quincunx 方法,出自 NVIDIA 公司。“Quincunx”意思是 5 个物体的排列方式,其中 4 个在正方形角上,第五个在正方形中心,也就是梅花形。此方法中,采样模式是五点梅花状,其中四个样本在像素单元的角上,最后一个在中心。
3.4 可编程过滤抗锯齿(CFAA)
可编程过滤抗锯齿(Custom Filter Anti-Aliasing,简称 CFAA)简单地说就是扩大取样面积的 MSAA,比方说之前的 MSAA 是严格选取物体边缘像素进行缩放的,而 CFAA 则可以通过驱动和谐灵活地选择对影响锯齿效果较大的像素进行缩放,以较少的性能牺牲换取平滑效果。显卡资源占用也比较小。
3.5 形态抗锯齿(MLAA)
形态抗锯齿(Morphological Anti-Aliasing,简称 MLAA),是 AMD 推出的完全基于 CPU 处理的抗锯齿解决方案。与 MSAA 不同, MLAA 将跨越边缘像素的前景和背景色进行混合,用第 2 种颜色来填充该像素,从而更有效地改进图像边缘的变现效果。
3.6 快速近似抗锯齿(FXAA)
快速近似抗锯齿 (Fast Approximate Anti-Aliasing,简称 FXAA) ,是传统 MSAA (多重采样抗锯齿) 效果的一种高性能近似。是最简单的、高效率的抗锯齿方式,FXAA 对图形边缘进行后处理。先进行边缘检测,然后通过提取边缘像素周围的颜色信息,通过混合颜色信息来消除高对比所产生的锯齿,其实就是对图像边缘进行柔化。
3.7 时间性抗锯齿(TAA)
时间性抗锯齿(Temporal Anti-Aliasing,简称 TAA),将 MSAA、时间滤波以及后期处理相结合,用于呈现更高的视觉保真度。与 CG 电影中所采用的技术类似,TXAA 集 MSAA 的强大功能与复杂的解析滤镜于一身,可呈现出更加平滑的图像效果。此外,TXAA 还能够对帧之间的整个场景进行抖动采样,以减少闪烁情形,闪烁情形在技术上又称作时间性锯齿。
Temporal AA 严格来说不是在光栅化时进行处理,而是以后处理的方式进行反走样,这也是目前比较主流的方式。Temporal AA 是近年来商业引擎最流行的几种反走样算法之一。
简单来说,Temporal AA 是基于历史帧缓冲,从历史帧中采样,在像素范围内进行加权抖动。相机抖动是 TAA 能够反走样最本质原因。相机随时间抖动过程中,引入了额外的子像素信息,对子像素的融合,使我们在时域上获得超采样的效果。具体来说,对于每一帧游戏画面,相机抖动 0.x~1 像素。那么在时域上,我们可以得到当前像素的多个子像素信息。时域上进行加权融合后,得到当前像素的最终颜色。
3.8 多帧采样抗锯齿(MFAA)
多帧采样抗锯齿(Multi-Frame Sampled Anti-Aliasing,MFAA)是 NVIDIA 公司根据 MSAA 改进出的一种抗锯齿技术。可以将 MFAA 理解为 MSAA 的优化版,能够在得到几乎相同效果的同时提升性能上的表现。MFAA 与 MSAA 最大的差别就在于在同样开启 4 倍效果的时候 MSAA 是真正的针对每个边缘像素周围的 4 个像素进行采样,MFAA 则是仅仅只是采用交错的方式采样边缘某个像素周围的两个像素。
3.9 深度学习超采样(DLSS)
利用神经网络的重建能力进行图像处理。DLSS 背后使用的技术是 Recurrent CNN,递归神经网络与卷积神经网络的一种结合。因此他能结合时域上的信息保证时域稳定性,即像素具有帧间连贯性,不会出现过多闪烁、跳变现象。其次,结合神经网络的强大图形重建能力,DLSS 能够分别对几何边缘以及着色进行重建。
3.10 图示抗锯齿
下图展示了不同采样方法的效果:
4 透明渲染
4.1 透明渲染算法
透明渲染是是图形学里面的常见问题之一,可以从《Real-Time Rendering》中总结出如下两个算法:
- Screen-Door Transparency 方法。基本思想是用棋盘格填充模式来绘制透明多边形,也就是说,以每隔一个像素绘制一点方式的来绘制一个多边形,这样会使在其后面的物体部分可见,通常情况下,屏幕上的像素比较紧凑,以至于棋盘格的这种绘制方式并不会露馅。同样的想法也用于剪切纹理的抗锯齿边缘,但是在子像素级别中的,这是一种称为 alpha 覆盖(alpha to coverage)的特征。screen-door transparency 方法的优点就是简单,可以在任何时间任何顺序绘制透明物体,并不需要特殊的硬件支持(只要支持填充模式)。缺点是透明度效果仅在 50% 时最好,且屏幕的每个区域中只能绘制一个透明物体。
- Alpha 混合(Alpha Blending)方法。这个方法比较常见,其实就是按照 Alpha 混合向量的值来混合源像素和目标像素。当在屏幕上绘制某个物体时,与每个像素相关联的值有 RGB 颜色和 Z 缓冲深度值,以及另外一个成分 alpha 分量,这个 alpha 值也可以根据需要生成并存储,它描述的是给定像素的对象片段的不透明度的值。alpha 为 1.0 表示对象不透明,完全覆盖像素所在区域; 0.0 表示像素完全透明。为了使对象透明,在现有场景的上方,以小于 1 的透明度进行绘制即可。每个像素将从渲染管线接收到一个 RGBA 结果,并将这个值和原始像素颜色相混合。
4.2 透明排序
要将透明对象正确地渲染到场景中,通常需要对物体进行排序。下面分别介绍两种比较基本的透明排序方法(画家算法和深度缓冲)和两种高级别的透明排序算法(加权平均值算法和深度剥离)。
4.2.1 画家算法和深度缓冲
可查看之前的笔记【计算机图形学】(五)深度缓冲
4.2.2 加权平均值算法(Weighted Average)
使用简单的透明混合公式来实现无序透明渲染的算法,它通过扩展透明混合公式,来实现无序透明物件的渲染,从而得到一定程度上逼真的结果。
NVIDIA 公司的 Louis Bavoil 在此基础上提出了新的算法,使用物体的不透明度作为加权值的加权平均值算法。此算法的主要思想如下:
对于某个位置的像素点,如果所有的不透明物件是相同的颜色,那么渲染的结果与它们的渲染顺序无关。那么,对于不相同颜色值的情况,如果我们用某一个颜色来替换这些颜色,比如这些颜色的平均值。对于这种情况,我们使用各个颜色的不透明度作为权重来计算出它们的加权平均值作为最终颜色替换这些颜色,这样渲染就与顺序无关。
此算法的优点很明显,效率高,速度快,只需要对物体进行一次的渲染,然后加上一次全屏的后处理。但是缺点也是同样的明显,透明结果只是一个近似值,而不是确切的正确结果。然而,它的效果仍然远远好过不做任何处理的简单透明混合,而且高效性也使得它有一定的应用空间。
4.2.3 深度剥离算法(Depth Peeling)
深度剥离是一种对深度值进行排序的技术。它的原理比较直观,标准的深度检测使场景中的 Z 值最小的点输出到屏幕上,就是离我们最近的顶点。但还有离我们第二近的顶点,第三近的顶点存在。要想显示它们,可以用多遍渲染的方法。深度剥离的每次渲染都需要一个深度缓冲,一个 Shadow Map 纹理和一个颜色缓冲,算法流程如下:
- 首先使用深度缓冲正常渲染,就可以得到离我们最近的顶点及其深度值,同时将所有深度值拷贝到 Shadow Map 纹理中
- 第二次渲染打开深度纹理的比较功能,使得深度值比较大的颜色通过测试,这样就把所有深度值小于前一次渲染的顶点全部剥离掉,剩下的顶点都是比上一次渲染离我们更远的顶点,再加上深度缓冲本身的取最小深度的功能,就可以得到比上一次渲染离我们更远的顶点中离我们最近的顶点的颜色
- 重复第二步操作,就把所有顶点颜色按照深度一层一层剥离出来,最后按照从后往前的顺序进行渲染,这样就可以得到正确的结果了。
这种方法与渲染物体的顺序无关,并且得到的结果保证正确,但缺点也很明显,需要剥离 N 次才能完成,就需要 N 个 Pass,N 是深度复杂度,因此性能是严重的瓶颈,另外如何确定 N 也是个问题。
5 伽马校正
查看之前笔记【RayTracer】(四)漫反射材质中的第三部分。