本专栏内容整理了GAMES101的计算机图形学课程的主要内容,作为我学习计算机图形学的一份复习备份或叫做笔记。内容中如有错误,或有其他建议,欢迎大家指出。
通过上一篇文章对三角形的取样结果我们发现了在屏幕像素对待渲染场景进行位置的色值采样后会发生走样,产生锯齿的情况。这一篇我们来学习下怎么去优化这种情况。提醒,本篇内容较多,难度较大,建议结合原视频阅读。
鉴于内容较多,这里直接先写上抗锯齿方法MSAA:在原图像的一个像素区域内设置多个采样点,得到各个采样点的色值,再对他们加权平均归一(卷积操作),然后将得到的色值设置到屏幕对应的像素位置上。
走样
在渲染图画时采样的过程主要是指对一副源场景的各个位置取它的颜色色值显示在对应位置的屏幕像素点上。但由于分辨率大小的限制,像素点的个数是比较有限的,在仅有的一些像素内要显示出我们肉眼所能看到的场景的全部细节处的色值是无法做到的。这个时候,像素点就会对场景进行一个离散化。每隔一段间隔取源场景中的一个色值渲染在一个像素内。这时就必然会发生走样。
比如我们对一个连续的函数(x=>y),在x=2,4,6,8......处取y的值再将取得的值用光滑的曲线重新连接起来,我们会发现得到的新曲线跟原本的曲线差别非常大。这就是在函数上的采样和走样。
如下图的源函数蓝色的周期函数线条,采样后重新绘制的黑色的周期函数。
但是当我们提高了采样频率或者说提高了分辨率,比如在x = 0.001, 0.002, 0.003, 0.004......等位置进行采样时我们就可以得到一个更接近蓝色的曲线的线条。这就是高分辨率的好处。
生活中的采样结果除了产生锯齿外,还会产生一些其他的瑕疵。
比如摩尔纹:右边的图只采样奇数行和奇数列的像素
还有当我们看一个旋转物体时有时候会觉得它的旋转方向突然变了,这是以时间为横坐标(帧率)的采样会发生的情况。
以上的情况也都是走样。产生走样的本质就是信号变化太快,采样频率跟不上。
反走样
了解了走样,我们来看看如何去做反走样。一个广泛的反走样方法是:先模糊后后采样,当我们对源场景(源信号)先进行一个模糊(滤波)后再去进行采样会得到比直接采样渲染更好的效果。
以上就是运用了先模糊后采样的方法渲染的图片(右)和直接采样源场景渲染出来的图片(左)可以看到该反走样的效果还是不错的。
那么要如何具体具体进行这样一个反走样操作呢?这里涉及到了信号学的一些知识。
我们先回顾下周期函数,和周期函数中的各个要素(周期T,频率F,振幅)
傅里叶级数展开
傅里叶级数展开就是说任何一个周期性的函数都可使用一系列正弦和余弦函数的线性组合来表示,也就是说当我们对一个周期性函数做傅里叶级数展开后会得到很多不同频率的周期性函数,后续讲到的模糊(滤波)就是去掉一部分频率范围内的正余弦函数,原信号就会发生变化。
傅里叶变换:
傅里叶变换可以将一个函数从时域(图像上是:空域)变换到频域上
(图像=>频谱,逆:频谱=>图像)
时域:时域(时间域)——自变量是时间,即横轴是时间,纵轴是信号的变化。其动态信号x(t)是描述信号在不同时刻取值的函数,我们平时所熟悉的正余弦函数就是时域上的函数图像。
空域:空间域(spatial domain)也叫空域,即所说的像素域,在空域的处理就是在像素级的处理,如在像素级的图像叠加。通过傅立叶变换后,得到的是图像的频谱。表示图像的能量梯度。
频域:描述信号在频率方面特性时用到的一种坐标系,指频率域;横轴是频率, 纵轴是该频率信号的幅度,描述了信号的频率结构及频率与该频率信号幅度的关系。(个人理解:用于对级数展开后的一大堆不同频率的周期函数一起描述的频谱图)
图像的傅里叶变换
右图是左图的傅里叶变换后得到的频谱图,在图像频谱图的中间是相对更低频的位置,而越靠近频谱图的外围频率越来越高。通常自然界中的场景图像经过傅里叶变换后都是接近右图的一个频谱表述。即:自然图像经过傅里叶变换得到的一系列周期函数中:低频函数多,高频函数少。
接下来我们对之前得到的频谱进行一个滤波处理,删除掉低频的那些信息或者叫低频的正余弦函数,在进行逆傅里叶变换就会得到左图的一个图像。会发现只剩下图像内容的边界线条,而频谱上也就剩下一些高频的信息(这就是一个高通滤波器)。所以我们可以知道高频信息描述的就是图像中的一些边界线条。
个人强行理解:因为在边界处,一个小区域内的几个像素内存在更多种差异很大的不同色值变化,所以对应的就好像时域中的频率更高了。
接下来是低通滤波器过滤后得到的图像,这时就模糊了边界。
还可以对更多不同位置的频率进行一个过滤会得到各种各样的图像。
所以到这里,我们就可以做到之前所说的反走样方法的第一步,先进行图像的模糊,即做一个低通滤波器。要做滤波器,我们还需要了解-----卷积这个工具。
卷积
上图中,描述的就是一个卷积操作,其中,signal是一个一维数组表述的源信号,filter是一个滤波器,滤波器是可以左右滑动的,我们还可以看到滤波器有三个格子,里面有三个数,操作内容就是在移动滤波器的过程中将滤波器里的三个数和原信号同一位置的数做一个点乘,将得到的结果写到结果集上,结果位置为过滤器中间格子的位置的对应位置。
下一步卷积操作:
卷积定理:卷积定理是傅立叶变换满足的一个重要性质。卷积定理指出,函数卷积的傅立叶变换是函数傅立叶变换的乘积。具体分为时域卷积定理和频域卷积定理,时域卷积定理即时域内的卷积对应频域内的乘积;频域卷积定理即频域内的卷积对应时域内的乘积,两者具有对偶关系。
也就是说:在空间域中(实际图像)我们要对一副图像进行模糊,就是对这幅图用一个低通滤波器进行一个卷积运算,就等同于:将图的频谱 × 滤波器的频谱 = 过滤后的频谱,再做逆傅里叶变换得到模糊后的图片。
如下图,图中卷积操作是我们要将3*3的源像素色值平均到一个像素内,以此去模糊一张图片。就可以通过卷积定理对频谱进行操作从而简化运算。
基于以上内容,我们再了解下采样在频谱上的表示是什么:
我们对一个时域上的函数乘以一个冲击函数,得到一系列离散的点,这就是一个采样过程。因为频域内的卷积对应时域内的乘积,所以在频谱上就相当于是原函数的频谱和冲击函数频谱的卷积操作,得到的是原函数的频谱以一定的间隔进行复制粘贴。(冲击函数的频谱还是冲击函数,但是时间间隔会和频率成反比,所以越离散的冲击函数,频谱越密集)
当采样率不足时,越离散的冲击函数,频谱越密集,就会发生频谱叠加的情况,这就是信号学上产生走样的原因,基于这个原因,我们该如何进行反走样?
反走样
基于上面的内容,我们知道反走样就是要减少混叠错误
选项1:提高采样率,采样率的提高,时域中冲击函数密集,频域中则更分散,就不容易发生混叠。
做法:
•更高分辨率的显示器,传感器,帧缓冲器…
•但是:昂贵且可能需要非常高的分辨率
选项2:抗锯齿
•在重复之前使原函数的频谱“更窄”,则后续复制时就不会发生堆叠。
•即在采样前过滤掉高频,高频区域分布在频谱两侧,所以我们就需要使用一个一定大小的低通滤波器,对原函数进行卷积。对应到一个图形上就是,取一定区域内各个位置的色值,对这些色值经行一个平均归一计算(缩小各个位置的色值差异变化,等同于去掉高频),这就是对图像的模糊操作,因为屏幕以像素为单位去填充色值,所以滤波器大小是一个像素大小的区域。
抗锯齿
接下来我们对简单的三角形去进行一个模糊
我们就使用一个特定大小的低通滤波器,对三角形的频谱进行卷积。
左图是一个1个像素大小的低通滤波器(这里可以理解为取滤波器的域内的所有色值去加权平均得到一个平均值,滤波器越大,对应频普高亮区域越小,过滤结果越模糊。)右图是滤波器对应的频谱图,滤波器越大,对应频普高亮区域越小
现在用滤波器对三角形进行卷积操作。我们假设滤波器会从三角形原图的左上角一路来回移动到右下角,每移动一个像素就将滤波器内覆盖的色值设置到屏幕对应的像素位置上。当滤波器走到三角形边缘处就会出现像左图那样的情况,原图对应的一个像素的区域大小内有的部分是三角形内的颜色,有的部分是其他颜色。这时用滤波器对这个区域进行一次卷积操作,就可以得到一个平均计算后的色值(右图),这时我们就可以将屏幕上这个位置的像素设置为右图的色值。这就是在空域上的卷积操作。
那么实际中我们要如何对这些边缘处的像素区域进行平均计算呢?
可以采用 MSAA 超采样抗锯齿方法
如上图,在一个像素区域内我们可以设置多个采样点,得到各个采样点的色值,再对他们加权平均归一。当我们设置的采样点足够多,抗锯齿的效果也会更好些,但同时,要求到的计算量也就会更加大。
接下来我们看下采用这个方法在7*4分辨率屏幕上显示一个小三角形
我们先看下没有采用抗锯齿的渲染结果
下面是用MSAA滤波器进行卷积操作后得到的渲染结果
可以看到采用MSAA抗锯齿后有比之前更像一个三角形了,同时不需要使用更高的像素设备。
但是正如我们之前提到的,当我们使用了MSAA进行抗锯齿的使用会增加额外的计算量,并且似乎提升的效果并不是非常非常明显,所以在真正生产中,通常采用的是更加优秀的抗锯齿方法,比如采样点的位置会有所优化,需要思考如何分布这些采样点会得到一个更好的效果。
除了MSAA外,在实际生产中还有两个具有代表性的抗锯齿方法。分别是:FXAA和TAA
FXAA:Fast Approximate AA 快速近似抗锯齿,它是一个后置抗锯齿方法,先得到一个需要优化的锯齿图像,再识别图像的边界处,在这里有大量的锯齿,再给这些锯齿修成光滑的线条,这个方法与采样无关,是结合图像识别技术的方法。
TAA:Temporal AA 时间向上的抗锯齿 , 做法是对比前一帧同一像素(采样区域)内不同位置的点的色值。任意一帧只计算一个采样点,随着t帧的累积,就有t个采样像素,再归一结果,就相当于做了t个子像素的超采样。当然,每帧中像素需要做一定的抖动(Jitter),不然不同帧相同位置的像素值就完全一样,也就没有了分摊多帧的意义。通过对像素分摊至多帧的超采样,来提高采样效率,达到缓解锯齿的目的。
超分辨率
在提到抗锯齿这个概念时,不得不提一个与它很相似的概念:超分辨率
即:当把一张低分辨率的图放大到一个更高分辨率的显示器上时,我们就会很容易看到锯齿,与上面的抗锯齿一样本质上仍然是“样品不足”的问题,但是去消除这些锯齿的方法并不相同,放大出现的锯齿没有原高清图可以采样,所以只能靠猜锯齿处的位置色值应当是什么。在计算机中一切需要靠猜去完成的操作都是深度学习非常擅长的领域,也就是跟去除马赛克的做法相似。这就是:DLSS(深度学习超级采样)。
总结
这篇的内容难度属实高,建议多看几遍视频。文章中有部分视频内容没有记录。最后再强调下抗锯齿方法MSAA:在一个像素(采样区域)内设置多个采样点,得到各个采样点的色值,再对他们加权平均归一(卷积操作),然后将得到的色值设置到屏幕对应的像素位置上。