原文: http://www.cnblogs.com/gongminmin/archive/2011/05/16/2047506.html
Anti-alias,简称AA,在图形学中广泛地用于提升渲染质量。经过几十年的发展,AA也从离线渲染逐步普及到了实时渲染的领域。本系列文章将总结一下在实时渲染中使用的AA方法的前世和今生。本片集中讨论硬件提供的AA方法。
图1. 一个像素内部的采样点。16个红圈表示16个采样点,蓝色和黄色是覆盖了这个像素的两个三角形。
SSAA
Super Sampling Anti-Aliasing是最直观的一种AA方法。实现方法之一就是渲染一个大图,然后downsample,这相当于在每个最终像素内部做了一个均匀 分布采样。更通用的描述是,每个像素分布多个采样点(可以均匀分布、Poisson分布、随机分布、抖动分布等),每个采样点都有独立的color和 depth,pixel shader在每个采样点都执行一遍。如图1的情况,会得到1个白色,1个浅蓝色和14个黄色的采样点。最后这个像素的值是这16个采样点的平均,也就是 ((1, 1, 1) +
(0.77, 0.77, 1) + 14 * (1, 1, 0)) / 16 = (0.98, 0.98, 0.125)。在这些方法中,SSAA质量最好,毕竟是个最暴力的方法。在D3D 10.1+上可以选择per-sample或者per-pixel执行pixel shader,也就是直接支持了SSAA。
性能统计(采样数为N,下同):每个像素里PS执行次数为N,占用空间N个color + N个depth。
例如,16 x SSAA可以被理解为每个像素有十六个采样点,而采样点的分布是
而这种分布对于反走样并不是特别有效的,可以采用如下几种分布来替换
从左到右依次是随机分布,泊松分布和Jittered分布。随即分布的问题在于采样点数量不多的时候,算法的结果不是特别稳定。泊松分布的问题在于并不能轻易计算出泊松分布的位置,而且位置计算代价很大。当然还有很多其他的分布,这里就不多介绍了。不同的采样点分布算法可以不同程度的改变反走样的效果。
MSAA
SSAA需要在每个采样点都执行一次PS并保存color和depth,时间和空间开销都是惊人的。Multi-Sampling Anti-Aliasing的出现极大地改善了这点。MSAA在每个像素只执行一次PS,输出颜色写入所有通过depth-stencil测试的采样本 中。在Shader Model 3之前,PS的输入一定取自像素的中心;后来加入了centric插值,PS的输入属性就可以是三角形所覆盖的所有采样点的中心:
来自http://www.confettispecialfx.com/multisample-anti-aliasing
如图1的情况,没有centric插值的话,蓝色三角形的两个采样点将都得到纯蓝的颜色(外差而得),最终像素的颜色就是(2 * (0, 0, 1) + 14 * (1, 1, 0)) / 16 = (0.875, 0.875, 0.125)。有centric插值的话就是个更正确的浅蓝色((1, 1, 1) + (0.77, 0.77, 1)) / 2 = (0.885, 0.885, 1),最终像素颜色是(2 * (0.885, 0.885, 1) + 14 * (1, 1, 0)) / 16= (0.98, 0.98,
0.125)。如下图所示:
性能统计:每个像素里PS执行次数为每个覆盖到该像素的三角形一次,占用空间N个color + N个depth。
CSAA
MSAA虽然解决了计算的问题,但存储量还是很大,尤其是采样率到了8以上。NVIDIA在G80及以上的GPU增加了Coverage Sampling Anti-Aliasing的方法。CSAA解耦了color/depth的buffer和coverage的buffer,可以用较少的color /depth空间来存储原先高采样数才能得到的质量。比如图1的情况,用CSAA 16x来渲染,就会把一个像素分成左上、右上、左下和右下4块区域,每块区域有4个coverage采样点,但共享同一个color和depth。对于图
1的情况,结果就是,(0.25 * (0.885, 0.885, 1) + 0.25 * (0.885, 0.885, 1) + 3.75 * (1, 1, 0)) / 4 = (0.98, 0.98, 0.125)。
性能统计:每个像素里PS执行次数为每个覆盖到该像素的三角形一次,占用空间M个color + M个depth,M小于N。
总结
这三种方法是常见的硬件直接支持的AA方法,下篇文章将讲述各种基于post process的AA方法。
上一篇文章Anti-alias的前世今生(一)介绍了硬件支持的AA方法,本篇将重点阐述新兴的基于post
process的AA。
SSAA、MSAA、CSAA这些方法虽然硬件直接支持,但带来的额外开销不可小视。一方面是它们对存储空间带来的冲击是惊人的。尤其在非桌面平台 上,内存本来就不多,如果还需要AA的话就吃不消了。如果同时使用了MRT和AA,显存开销更是天文数字。另一方面,这些方法对“edge”的考量都是 primitive的边界,不管这个edge是否真的需要AA,所以会浪费很多计算量。
GPU Gems 2的第九章Deferred Shading in S.T.A.L.K.E.R.在 游戏界第一次宣传了Deferred Shading的概念,同时也提到了Deferred框架无法使用硬件MSAA的问题。虽然Deferred
Lighting部分解决了该问题,但再次渲染一边场景的代价还是不小的。更重要的是,由于Deferred框架的引入,人们终于开始正视MSAA的实际 上造成了很多时间和空间的浪费。于是乎这几年基于post process的AA蓬勃发展,大有取而代之的气势。
Edge AA
Edge AA就是Deferred Shading in S.T.A.L.K.E.R提出的方法,根据邻居的depth和normal的差异程度做一个边缘检测,每个像素可以得到一个权重,表示“像边缘的程度”:
根据这个权重,就可以把邻居像素的颜色拿来插值,得到AA的效果。
在GPU Gems 3第19章Deferred Shading in Tabula Rasa中,NCsoft对Edge AA做出了一些小改进,边缘检测不再依赖于图像分辨率,更加稳定。
Directionally Edge AA
Edge AA开创了post process AA的时代,但它的质量还是不足以与硬件AA抗衡的程度。AMD在HPG09上的论文A Directionally Adaptive Edge Anti-Aliasing
Filter改 进了Edge AA,不再采用独立的edge点来决定AA混合的方式,而是根据edge点周围的状况确定出isoline,然后根据isoline的垂直方向来确定混合 的方向。这样一个边界就会沿着朝向来混合,还原出更加精确的sub-pixel信息。这种方法进入了AMD的驱动,只要打开Adaptive AA就会自动启用。
MLAA
Adaptive Edge AA提出了以线代替点的研究方向,但isoline的计算量毕竟比较大,启用了之后对渲染性能下降明显。Morphological Antialiasing再次在这个方向作出了努力。它不计算isoline,而是把edge分门别类,总结成Z、U、L等几种特定的形状,而Z和U都可 以分解成L。
最终根据L划出一个三角形,确定混合区域。这样就省去了所有繁重的计算,提高AA速度。在AMD较新的驱动里,MLAA取代了Directionally Edge AA成为Adaptive AA的首选。MLAA的框架又派生出多个不同的方法:
CPU MLAA
Intel在HPG09上的Morphological Antialiasing一文是在CPU上实现的。代码用了非常深的分支来判断edge形状,完全是针对CPU优化的,不适合GPU硬件,也不适合实时渲染的情况。
GPU MLAA
SIGGRAPH 2010 poster的Practical morphological antialiasing on the GPU, 通过建立SAT来判断edge形状,需要log(width)+log(height)个pass。在确定了L之后,需要查询一个预计算的512×512
R32F的纹理,里面每个texel对应了一个特定大小的L所需要混合的面积。也就是边长最大是512个像素。可以看出这种方法非常暴力,虽然可能比读回 CPU快,但开销还是很大。
Jimenez’s MLAA
GPU Pro 2里的文章Practical Morphological Anti-Aliasing提出了一个更实用的GPU MLAA方法,命名为Jimenez’s MLAA以 示区分。在这种MLAA里,Z和U不需要分解成更简单的L,直接用一个预计算的表来做查询。每个像素根据自己在形状里的位置在查找表里寻找需要混合的各个
像素。720p的分辨率下,这种方法在一般的情况下能达到Xbox 360上3.79ms,Geforce 9800 GTX+上0.44ms。同等条件下8x MSAA需要5ms。
FXAA
NVIDIA在Graphics SDK 11里 面提供了一个称为Fast Approximate
Anti-Aliasing的方法。该方法很接近于MLAA,但只识别长边,而不识别形状。有了长边之后,就可以根据边和像素的求交来估算每个像素中 sub-pixel的覆盖率,并进行AA混合。后来Timothy Lottes还发展出了FXAA
II,质量有所下降,速度提高了,在Xbox 360上,720p的分辨率可以做到2.0ms。
DLAA
另一个在GDC11上公开的AA方法称为Directionally Localized Anti-Aliasing(前面介绍的Jimenez’s MLAA和FXAA也在GDC11的时候公开的,这也扎堆)。这种方法比较另类,它在垂直方向模糊后的图像上做水平方向边缘检测,得到的结果blend回去就得到AA后的图像。
左图为AA之前的,右图是经过DLAA的
DLAA还是比较快的,在Xbox 360上,720p需要2.2ms。
本篇介绍了几种基于post process的AA方法,下一篇讲讨论如何把硬件AA和post process AA结合起来。
上篇文章讲述了几种基于post process的AA方法,有没有可能将post process AA和hardware AA结合起来呢?本篇要讲的正是这样的hybrid AA。
首先补充一下,对于MSAA的计算浪费,可以从下面的对比图看出来:
MSAA需要计算的edge
真正需要计算AA的edge
有了这个对比,大家应该有了直观感受,MSAA实际上把很多计算量浪费在了实际上不必要AA的像素上了。如果样本数高,浪费会更严重。
上一篇提到的那些基于post process的方法其实都在做一件事情:试图通过pixel信息估计出sub-pixel级别的几何,然后做AA。Edge AA是通过独立点来估计,MLAA是通过L形来估计,FXAA和DLAA是通过线段来估计。Hybrid AA的方法想表达的是,为什么要“估计”,而不是干脆就先存出sub-pixel的几何?
SRAA
Subpixel Reconstruction Anti-Aliasing是 NVIDIA的研究员在I3D2011上发表的新方法。它寄予的事实是,shading的变化频率一般低于几何的变化频率,所以可以在较低分辨率上
shading,而用较高分辨率恢复几何。SRAA的基本流程为,在Deferred Shading的框架中,渲染一个高分辨率(或者带MSAA)的G-Buffer,但在shading的时候仅在普通的分辨率(或者没有MSAA)的情况 下做。累积的结果通过G-Buffer重建sub-pixel信息,来进行类似MLAA的AA计算。这种方法结合了MSAA和MLAA,但可以用较低的样 本数做到较高的MSAA才能得到的效果,同时不增加shading的计算量。SRAA由于原理问题,只能用在Deferred框架中(不过对于现代的游戏
来说这不是个大问题)。
GPAA
Geometric Post-process Anti-Aliasing是Humus独立提出来的AA方法。基本思路是在渲染几何之后在此用线框模式渲染一遍,这时候可以得到每个三角形在每个pixel的覆盖率:
通过这个覆盖率,计算AA就轻而易举了,结果比较如下:
这种方法的代价是多了一遍线框渲染,但可以用于Forward和Deferred两种框架。杯具的是,Humus的twitter上说这种方法实际上在1996年就被别人申请专利了。
Adaptive AA
Intel在SIGGRAPH 2010的course Deferred Rendering for Current and Future
Rendering Pipelines上 提到了一种很简单很暴力的AA方法,在edge的地方per-sample计算,在non-edge的地方per-pixel计算。和基于post process的方法一样,这需要执行一个边缘检测,并在stencil中标记出来,然后就可以分别计算了。下图中红线标记的地方就是检测出来的 edge:
这种方法的结果会和SSAA一样,同时没有MSAA重复计算的毛病。
总结
Hybrid AA综合了hardware AA和post process AA的优点(或者说,缺点)。优点是可以用低于hardware AA的内存开销和计算量达到一样的效果。缺点是需要修改原有的图形渲染流水线。
本系列总结了三类不同的空间AA方法,希望对大家有所帮助。