【图形系统02】光栅化
光栅化 rasterization
光栅 raster 这个词就是德语中屏幕的意思,光栅化的意思就是将图像绘制在屏幕上进行显示。
[!NOTE]
要进行光栅化需要先将空间变换到屏幕空间,以下都是在屏幕空间上的操作
三角形-基本形状单元
三角形在图形学中有很多很好的性质:
- 三角形是最基本的多边形,并且任何其他的多边形都可以拆分为三角形。
- 三个点可以保证他在一个平面如果是四边形四个点就不能保证。
- 它可以很好地用叉积判断一个点是不是在三角形内部(三角形的内外定义特别清晰)
采样
采样就是给定一个连续的函数,在不同的点求它的值,也可以认为,采样是把一个连续的函数离散化的过程。
光栅化的过程其实就是在屏幕空间离散的像素中心点上进行采样来判断像素是否在三角形内。
比如下图中,要实现一个判断屏幕上的像素是否在三角形内的函数 inside (tri, x, y),然后将三角形顶点构成的最大长方形区域内所有点作为函数的输入,判断这些点是否在三角形内,如果在三角形内,就将屏幕上的像素点进行点亮。这个过程就是采样。其他采样的例子包括对视频进行时间上的采样,这样就可以得到视频中的某几帧画面。inside(tri,x,y)
1:point (x, y)在三角形内(判断方法见软光栅中的总结),如果碰巧点在三角形的边界,可以设定标准视为在内或在外
0:其余情况
遍历所有点,判断所有点是否在像素内
1 | for(int x = 0; x < xmax; ++x) |
一张照片其实就是所有达到感光元件的光学信息,通过把它离散成图像的过程,其实这也是采样。采样不仅可以发生在不同的位置,也可以发生在不同的时间,视频就是在时间中进行采样的。
包围盒(bounding box)
利用包围盒 (Bounding Box)对不会包含三角形的像素进行优化
Artifacts
Artifacts 可翻译为伪影、瑕疵, 表示了一切在图形学上的错误,异常,不希望看到的结果,看上去不对的效果以及各种瑕疵。
a、采样产生的第一个问题就是我们刚刚提到的锯齿问题(Jaggies)
在光栅化中表现为锯齿(Jaggies)。我们可以看到右边的图中三角形有明显的凹凸锯齿。
锯齿产生的原因就是因为信号的变化频率高,而相应的采样频率低。在计算机渲染中,由于绘制的图形在数学上是连续的,而渲染的像素点是离散的,从而导致在光栅化的三角形遍历阶段,将图形打散为像素时,会不可避免的产生锯齿(Jaggies)。
就三角形边缘不规则的情况来说,因为三角形的边上是无限多个点,而用有限个采样点去逼近这无限多个点,所以当然会产生不规则的锯齿,
如下图可以看到,在光栅化阶段进行图元转化时,当三角形覆盖像素中心的时候输出颜色,反之不输出,就会出现下图中右边的锯齿情况。
锯齿(Jaggies)现象也被称为走样(Aliasing)。常见的走样有几何走样,着色走样、动画走样。消除锯齿现象的技术就是抗锯齿,也被称为反走样(Anti- Aliasing,AA)。
- 几何走样:几何覆盖函数采样不足,即俗称的边缘锯齿,一般发生在光栅化阶段。注意下图立方体边缘
- 着色走样:渲染方程的采样不足,因为渲染方程也是连续函数,对某些部分在空间变化较快(高频部分)采样不足也会造成走样,反映在视觉上一般是图像闪烁或噪点,这类走样称之为着色走样,一般发生在各种着色阶段。注意下图中的高光,给人的感觉非常噪。
走样不可避免,只能减轻。主要通过硬件(像素点数量加倍)和软件(各种算法,如超级采样算法等)来反走样(抗锯齿)。
- 硬件增加采样率:本质上增加了频谱之间的距离,需要更高分辨率的显示器、传感器、帧缓冲区。
- 软件算法:先模糊后采样+各种抗锯齿算法
b、Moiré Patterns in Imaging—(摩尔纹)
如果我们把下面图片左图中的奇数行和列的像素剔除,就会出现摩尔纹效果。当我们拿手机拍显示屏的屏幕时也会出现类似的的效果,这些都是采样带来的问题。
c、Wagon Wheel Illusion (车轮错觉)
接着是车轮效应,当我们顺时针旋转纸片时,如下图所示:有些条纹显得在逆时针旋转,在生活中我们也经常能看到类似的现象,比如高速行驶的汽车,其轮子看上去在反向旋转,这是因为人眼在时间中的采样速度更不上运动的速度造成的。
反走样(抗锯齿)
先模糊再采样
如何进行反走样呢?可以在采样之前先做模糊再采样(模糊也可以认为是低通滤波器,把三角形边界的这种高频信号给过滤掉)。(注意:顺序不能变,先采样再模糊无法反走样)
抗锯齿算法
前向渲染:SSAA、MSAA、CSAA,RGSS 等
延迟渲染:FXAA、MLAA、SMAA 等
时域上的抗锯齿:temprial anti-alasing,TXAA
基于深度学习:DLAA
1、SSAA 超采样抗锯齿
SSAA (Super Sample Anti-aliasing)
SSAA 本质上是先渲染出一张 N 倍 屏幕分辨率的图像,然后再通过降采样的方式输出最后的渲染图像,这样输出一个屏幕像素就对应原来 N 个采样点计算的屏幕大小的图像,这是理论上最完美的抗锯齿。
先渲染一张大分辨率的图像,然后把它缩小,这样它的锯齿效果就减弱了,大致如下图:
上图中最右边有明显的锯齿,但是通过降采样一直输出到左边的话,这种锯齿感从肉眼来看的话就会明显地减弱。
假设最终屏幕输出的分辨率是 800x600,4xSSAA 就会渲染到一个分辨率 1600x1200 的 Buffer 上,然后再把这个放大 4 倍的 Buffer 采样输出至 800x600。这种做法在数学上是最完美的抗锯齿。但是缺点也很明显,计算量增大了 4 倍,render target 的大小也涨了 4 倍。
2、MSAA 多重采样抗锯齿
MSAA (Multi sample Anti-aliasing)
MSAA 是 GPU 在光栅化阶段对片段进行超采样,单个像素中的所有采样都决定像素中心点的着色结果,最后根据样本的覆盖率来计算像素最终颜色的方法。
它的原理是这样的,在逐像素阶段,如果我们只布置一个采样点,虽然如下图左边三角形虽然占据了像素一部分,但是却没有包含中心采样点,那么不输出颜色,,反之如果我们布置了多个采样点的话,那么根据覆盖的样本的百分比来输出最终的颜色,就如下图右边所示。
这种抗锯齿方式,布置的采样点越多越准确,但是随之计算的性能消耗也会增大。
下面是 MSAA 抗锯齿输出的颜色示例:
但是 MSAA 也有一些缺点:
1、MSAA 在与 HDR 一起使用时可能会产生问题,必须进行专门处理。
2、由于 MSAA 是在光栅化阶段对图元进行超采样,因此它只能解决几何走样现象 (即物体轮廓地锯齿),不能解决着色走样 (高光闪点)问题。
3、延迟渲染无法支持 MSAA。
CSAA 覆盖采样抗锯齿 (Coverage Sampling Anti-Aliasing)
在 MSAA 的基础上,将用来计算 Coverage 的采样点与用来存储色彩的采样点进行分离,这样可以用较少的显存来存储较多的专门用来计算 Coverage 的采样点,让覆盖率计算的更加精确,从而提升视觉效果。从结果上看,CSAA 在性能上比 4x 的 MSAA 稍微低一些,但也可以达到 8x 或 16xMSAA 的效果。
EQAA (Enhanced Quality Anti-Aliasing)
EQAA(Enhanced Quality Anti-Aliasing),是 AMD 在其 GPU 产品中对 MSAA 的优化实现。在 EQAA 中,也采用了与 CSAA 相同的做法,将计算 Coverage 的采样点和计算 Color 的采样点分开存储,例如,4f8x EQAA 表示有 4 个颜色采样点并且总共 8 个采样点。
EQAA 与 CSAA 一样,也采用了 Coverage 与 Color 两种类型的采样点。另外 EQAA 还使用了一个表格来存储采样点的颜色、深度、模板数据,而在采样点上通过索引的方式引用表格中的数据。因为在单个像素中,采样点公用数据的几率非常大,因此这种方法可以节省大量的显存资源。
3、TAA 时间抗锯齿
TAA 时间抗锯齿 (Temporal Anti-Aliasing)
TAA 的核心思想是将 SSAA 采样空间不同样本方法改成使用多个历史帧的渲染结果作为样本来达到类似 SSAA 的效果。它的实现需要 N 倍的显存空间,但是不需要额外的着色计算。
实现思路如下:
1、把多次采样的过程分布到每一帧中去,每一帧都平均前面几帧保存下来的数据。从下图可以看到将 4 次采样分布在 4 帧的运算中。
2、每一帧会有一定的偏移,继承了 MSAA 采样。从下图可以看到每一帧的采样点的位置并不一样。
3、用 motion vector 保存每帧移动的偏移。 下面是抗锯齿的前后对比:
在实际工程中,需要注意 TAA 带来的一些细节问题;
1、因为灯光改变、遮挡改变、相机或场景运动所带来的历史帧中的样本失效问题。
2、因为样本来自于多个历史帧而产生的画面收敛延迟 (残影)的问题等等。
3、HDR 协同工作的问题。
TXAA
TXAA 是 NVIDIA 在 GTX 600 及以上版本的显卡上基于传统 MSAA(CSAA?) 的基础上,引入了时间过滤器(TAA 的思想)的硬件抗锯齿技术。TXAA 旨在减少时间性锯齿 (运动中的蠕动和闪烁)。该技术集时间性过滤器、硬件抗锯齿以及定制的 CG 电影式抗锯齿解算法于一身。要过滤屏幕上任意特定的像素,TXAA 需要使用像素内部和外部的采样以及之前帧中的采样,以便提供最高画质的过滤。 TXAA 在标准 2xMSAA 和 4xMSAA 的基础上改进了时间性过滤。例如,在栅栏或植物上以及在运动画面中,TXAA 已经开始接近、有时甚至超过了其它高端专业抗锯齿算法的画质。TXAA 由于采用更高画质的过滤,因而与传统 MSAA 较低画质的过滤相比,图像更加柔和。
MFAA 多帧采样抗锯齿 (Multi-Frame Sampled Anti-Aliasing)
Maxwell 架构提供了一种名为动态超分辨率(Dynamic Super Resolution,DSR)的技术,能在硬件上实现超采样。另外 Maxwell 将 AA 的样本数据存放在了 RAM 中(以前的架构都是将 AA 样本数据存储在 ROM 中),从而提高了样本存储的灵活性和可编程性。借助这样的新的架构,实现了 MFAA。由于 RAM 中的数据是可以自由读写的,通过在时间和空间上交替 AA 样本的模式,MFAA 的样本在历史每帧(甚至同一帧的不同时刻)都可以不同。
4x MFAA 的画质于 4x MSAA 相当,但只需要 2x MSSAA 相当的性能开销。
4、FXAA 快速近似抗锯齿
后处理抗锯齿方法,渲染完之后进行后处理
FXAA (Fast Approximate Anti-Aliasing)
它的特点如下:
1、利用边缘检测有效的模糊混合。
2、是在后处理完成不依赖硬件支持。
测试场景中对应的后处理图像:
FXAA 本质就是在后处理中对图像进行描边,然后对描边图像进行模糊,之后再与原图像进行混合。
下图是对应的效果图:
相比于 MSAA,FXAA 的目标是速度更快、显存占用更低,还有着不会造成镜面模糊和亚像素模糊(表面渲染不足一个像素时的闪烁现象)的优势,而代价就是精度和质量上的损失。
MLAA 形态学抗锯齿 (morphological Anti-Aliasing)
它的基本思路是检测每帧图像的边缘 (通常可对亮度、颜色、深度或者法线进行边缘检测),然后对这些边缘进行模式识别,归类出 Z、U、L 三种形状,根据形状对边缘进行重新矢量化 (re-vectorization),并对边缘上的像素根据覆盖面积计算混合权重,将其与周围的颜色进行混合,从而达到平滑锯齿的目的。
以下图为例详细说明。用绿色标记的线条为检测到的 Z 形边缘,从这些边缘我们可以推断出原始边缘的形状,即图中蓝色线条。这个过程叫重新矢量化。此时我们能够得知边缘附近每个像素被蓝色线条截断了百分之多少。根据此信息将当前像素与邻近像素的颜色混合,便能得到平滑的边缘。
像素被蓝线截断面积的百分比(小于 50%的部分)叫做权重因子。对于任一个边缘像素,要计算其权重因子,只需要知道 d_left、d_right,以及两端交叉边的朝向(即边缘的形状,此处为 Z 形)即可。其中 d_left 和 d_right 为当前像素距离边缘两端的距离。得到权重因子 a 后,通过如下计算实现边缘平滑:
为了节省计算资源,Jimenez 为每种形状模式预计算了一张查找表(称作 areaTex)以便快速获取权重因子,如下图所示:
注意贴图中的每个像素保存了两个数值(分别储存在 R 和 G 通道里),这两个数值分别代表当前像素及共享同一边缘的邻接像素的权重因子。
以上是仅针对水平方向锯齿的情况,对于垂直方向的锯齿,处理方式类似。
MLAA 天然的能与延迟着色完美配合,但它只能用来消除几何锯齿,不能消除着色锯齿。
SMAA 增强型子像素形态学抗锯齿 (Subpixel Monorplogical Anti-Aiasing)
SMAA 是思路是建立在 Jimenez 版 MLAA 的基础之上,但是每个步骤都经过了强化或者彻底的更新。
Jimenez 版 MLAA 的处理流程如下图所示:
分为三个步骤:1、边缘检测;2、计算权重因子;3、混合周围像素。
SMAA 在(b)、(c)的基础上加入了针对尖锐几何特征的处理,并加入了对角线模式识别;在(d)中加入了对局部对比度的考虑;在(e)改善了距离搜索算法。
详情查看原文:(7条消息) SMAA算法详解_qezcwx11的博客-CSDN博客
5、DLSS 深度学习超采样
DLSS (Deep Learning Super Samping)
DLSS(Deep Learning Super Sampling),深度学习超采样,是 NVIDIA 于 2018 年在 GeForce 20 系列的显卡上推出的一种基于深度学习算法进行图像缩放的技术。2020 年 NVIDIA 推出了 DLSS 2.0。
这项技术在 Turing 架构中首次引入,它的工作原理是利用 NVIDIA 神经图形框架 NGX,在超级计算机中以极低的帧率和每像素 64 个样本对数万张高分辨率的精美图像进行离线渲染,训练出一个深度神经网络。基于无数个小时的训练所获得的数据,网络就可以将分辨率较低的图像作为输入,构建高分辨率的精美图像。
训练好网络后,NGX 会通过 Game Ready 驱动程序和 OTA 更新将 AI 模型传递到 GeForce RTX PC 或笔记本电脑。并借助 RTX GPU 中专用于 AI 计算的 Tensor Core,DLSS 网络可以与密集的 3D 游戏同时实时运行。
信号基础
上面我们出现了走样(Aliasing)问题,我们是通过先模糊后采样的进行反走样(Antialiasing )去优化它的。这里我们不仅不思考几个问题:
- 为什么采样频率低于信号变化频率就会产生走样?
- 为什么先模糊后采样就可以解决锯齿问题?
[!NOTE] 答案:
- 进一步理解走样:
图中蓝色为高频信号,黑色为低频信号,当我们采用相同的采样频率(图中的圆圈为对应得采样点)采样时,得到的结果相同。即在给定的采样率下我们无法区分他们得信号频率,这就是走样。- 模糊就是一个低通滤波先把高频的信息拿掉,这样做的原因就是让频谱覆盖的面小一些然后我们再以原本的间隔去采样它,这个时候我们发现它就不会产生信号重叠了。
要探究其根本原因,我们就需要了解一点信号原理。
时域/频域
- 频域是描述信号在频率方面特性时用到的一种坐标系。在电子学,控制系统工程和统计学中,频域图显示了在一个频率范围内每个给定频带内的信号量 。
- 时域是描述数学函数或物理信号对时间的关系的一种坐标系。
1、时域(时间域)(time domain)
自变量是时间, 即横轴是时间, 纵轴是信号的变化。其动态信号 $x(t)$ 是描述信号在不同时刻取值的函数。
图 1 是正弦波的时域图,示出了振幅与时间的关系。在时域图中,横轴是时间,纵轴是振幅。时域图显示振幅随时间的变化,可以看出峰值振幅为 5V,可以算出频率 f=6 Hz。
2、频域(频率域)(frequency domain)
自变量是频率, 即横轴是频率, 纵轴是该频率信号的幅度, 也就是通常说的频谱图。
图 2 是图 1 中正弦波的频域图,在频域图中,横轴是频率,纵轴是峰值振幅。频域图仅仅示出峰值振幅与频率,而不显示振幅随时间的变化。
从频域图可以看出,正弦波的频率为 6Hz,这个 6Hz 的正弦波的峰值振幅为 5V 。
频域图的优点是,从频域图中,可以一眼看出正弦波的频率和峰值振幅。整个正弦波在频域图上只是一个立柱立柱的位置显示了正弦波的频率,立柱的高度显示了正弦波的峰值振幅。
3、时域和频域
将时域频域一起放在一个三维的坐标系中,如图所示,与时域和频域的轴表示振幅:
另外一张动图:
4、时域变换到频域的意义
对信号进行时域分析时,有时一些信号的时域参数相同,但并不能说明信号就完全相同。因为信号不仅随时间变化,还与频率、相位等信息有关,这就需要进一步分析信号的频率结构,并在频率域中对信号进行描述。
动态信号从时间域变换到频率域主要通过傅立叶级数和傅立叶变换等来实现。 很简单时域分析的函数是参数是 t,也就是 y=f (t),频域分析时,参数是 w,也就是 y=F (w)两者之间可以互相转化。时域函数通过傅立叶或者拉普拉斯变换就变成了频域函数。
总的来说,在某种需求下将信号变换到另一种域中,有利于进行处理、计算和分析。
空间域/变换域
空间域(spatial domain)
空间域简称空域,又称图像空间 (image space),一般这个概念会出现在数字图像处理中,指由图像像元组成的空间。在图像空间中以长度 (距离)为自变量直接对像元值进行处理称为空间域处理。
简单来说就是是以图像左上为原点,横为 y 竖为 x 的二维平面。
实际上你可以简单理解为,像素空间,在空域的处理就是在像素级的处理,通过傅立叶变换后,得到的是图像的频谱。表示图像的能量梯度。
变换域:
在有些情况下,通过变换输入图像来表达处理任务,在变换域执行处理任务,方便我们的计算吗,然后再逆变换到空间域。比如使用傅里叶变换将图像转换到频率域进行滤波,再转换回空间域得到滤波后的图像。
简单来说,就是空间域经过傅里叶变换,变换为频域。我们在频域进行滤波等处理。这个频域我们也可以成为”变换域”,变换域是一个宽泛的概念,可以理解为一种中间状态。
[!important] 理解
广义上,傅里叶变换将时域转换到频域。而在图像处理中,傅里叶变换可以将空间域转换为频域(变换域)。空间域和时域在数学上是一个意思,不同仅在于自变量用 x 还是 t。下文讨论的傅里叶变换我们都认为是在图像处理中进行。
频率和周期
频率是 f,周期是 T。
频率越快,函数变化越快,如下图所示。
傅里叶级数展开
傅里叶级数展开: 任何一个周期函数都可以写成一系列正弦和余弦函数的线性组合和一个常数项。
通过傅里叶级数展开,我们将周期函数分解为多个不同频率的段(即上式中的正弦和余弦函数),随着展开式越来越多,越来越接近我们想要表达的函数:
从图中可以看出,在设置相同的周期性采样位置(对应采样频率)的条件下,低
频信号的采样点连接起来更接近原函数(对应信号变化频率),而高频信号的采
样点连接起来就和原函数相差很大。
这说明,信号变化频率越高,我们就需要越高的采样频率。
傅里叶变换 Fourier Transform
傅里叶变换(Fourier Transform):空间域转换为频域
傅里叶变换,傅里叶变换可以将信号分解为频率,并且能将满足一定条件的某个函数表示成三角函数(正弦和/或余弦函数)或者它们的积分的线性组合(如下图)。
左图:空间域图像/右图:频域图像(我们称之为频谱)
滤波 Filtering
- 滤波:去除特定的频率的内容
- 高通滤波器(High-pass filter):只保留高频信号(高频信号一般在边界)
- 低通滤波器(Low-pass filter):只保留低频信号(画面变模糊)
我们之前光栅化抗锯齿做的先模糊就是采用了低通滤波器,使其高频信号边界去除然后图形就会变得模糊。
应用滤波器时,使用的是卷积运算。(可以说滤波=卷积)
在空间域上的卷积等同于在频域上的乘积。
下图我们用了一个 33 的卷积核在实域做了一个卷积,因此图片变得模糊了。如果我用一个更大的卷积核($9\times9$)做卷积图片会变得更模糊(我们这里可以用极限的思想来想一想,如果这个卷积核无限大比图片像素还大,那是不是每个点积值几乎都是一样的,保留的信息就越少了越接近低频。如果我们用一个无限小比图片像素还小的卷积核去做卷积,那是不是意味着它相当于没有做滤波,值没有改变,也就是说把所有的频率信息都保留下来了)。
根据卷积定理,我们实现一个卷积操作可以有两种方法:
- 方法 1:图和滤波器直接在空间域上做卷积操作
- 方法 2:先把图傅里叶变换,变换到频域上,把滤波器也变到频域上,两者相乘;乘完之后再逆傅里叶变换到时域上
从频域的角度看采样
接下来我们从频域的角度来看什么是采样?采样其实就是在重复频谱上的内容。
我们可以看到时域上的连续函数(a), 它的频域对应的是(b)。
采样的过程就是让(a)乘以冲激函数(c,代表我们在某个时刻进行采样) 得到一系列离散点(e)。
从 (f) 中的频谱中可以看出,采样就是在重复原始信号的频谱。
左边时时域图像/右边是频域图像(频谱)
密集采样是没有问题的,但是如果采样频率过低(采样点数量很少),这就会导致频谱之间的距离减少,这可能导致了原始信号与重复的信号产生频谱混叠(也就是走样)如下图:。
知道了这个走样的原理,我们就可以解释为什么先做一个模糊再进行采样可以进行反走样。模糊就是一个低通滤波先把高频的信息拿掉,这样做的原因就是让频谱覆盖的面小一些然后我们再以原本的间隔去采样它,这个时候我们发现它就不会产生信号重叠了。