众所周知,走样是图形渲染的一大问题,其主要成因是低频采样无法完美呈现高频信号,因而形成了图形混叠,也就是我们所说的锯齿。

图形转化成图像的过程,是一个将连续信号经过采样转化成离散信号(显示设备的像素是离散的)的过程,之所以产生锯齿现象(失真,走样)就是因为信号的离散性被人眼识别出来。抗锯齿就是通过一些手段来重构丢失的信号。我们通常用的抗锯齿算法实际上是降低锯齿,并非消除锯齿。

android 相机surface渲染有锯齿 oc渲染出有锯齿_消除锯齿

 

为解决这些问题,抗锯齿算法应运而生。抗锯齿算法很多,如MSAA(Multi-Sample Anti-Aliasing),通过判断一个像素内不同位置的点是否在三角形内来确定该像素的最终颜色;FXAA(Fast Approximate Anti-Aliasing),是一种图像后期处理,通过一些图像匹配算法找到有锯齿的边界,之后换成没有锯齿的边界,速度非常快;TAA(Temporal Anti-Aliasing),基于图像前几帧的数据对图像进行抗锯齿处理,将样本分布在了时间上,并且在当前帧没有引入额外操作,缺点是对于运动的物体会出现“鬼影”现象。

接下来,我们详细讲述一下MSAA的原理。

MSAA的原理很简单,在每一个像素内进行多重采样并判断采样点是否在三角形内,然后对判断的结果进行平均,从而得到了改像素的颜色。

 

android 相机surface渲染有锯齿 oc渲染出有锯齿_开发工具_02

 

我们来看下面的例子:

一个采样点(No AA)

android 相机surface渲染有锯齿 oc渲染出有锯齿_消除锯齿_03

 

严重的锯齿,我们甚至是无法从结果分辨出这是不是一个三角形。

2X2超采样

android 相机surface渲染有锯齿 oc渲染出有锯齿_界面设计_04

 

Much better! 我们采用了MSAA2X,已经能够分辨出这是一个三角形了。当然,采样点越多效果越好。

接下来,我们需要根据采样点是否在三角形内来求出三角形对这个像素的覆盖率。判断点是否在三角形内很简单,我们只需对三条边分别进行叉积,结果如果同向的话那么说明该点在三角形内。如下图所示,改像素的覆盖率为75%。

 

android 相机surface渲染有锯齿 oc渲染出有锯齿_开发工具_05

 

我们对剩下的像素做同样的操作,得到一个完整的结果。

android 相机surface渲染有锯齿 oc渲染出有锯齿_开发工具_06

 

android 相机surface渲染有锯齿 oc渲染出有锯齿_图形学_07

至此,MSAA已经完成,我们得到了一张锯齿相对较少的图片,作为一种trade-off,我们需要花费额外存储空间来保存采样点的深度信息和颜色信息。