-
Notifications
You must be signed in to change notification settings - Fork 41
AntiAliasSummary
图像锯齿根据成因大致可分为两类:
- 几何锯齿
- 着色锯齿
几何锯齿是由于在光栅化阶段,受成像分辨率所限,导致几何体的边缘呈锯齿状。
而着色锯齿则是在ps阶段,由于渲染引起的物体表面色彩高频变化。
这里罗列以下常见的游戏当中的抗锯齿技术:
- SSAA
- MSAA
- SMAA
- FXAA
- TAA
以高分辨率渲染,然后再降分辨率输出。
例如目标屏幕分辨率为600x800,那么先以1200x1600分辨率渲染,然后DownSample到600x800,如此一来,屏幕上的单个像素最终由2x2个像素混合而成,因此起到抗锯齿效果。
优势:
- 效果好
劣势:
- 性能开销巨大。
- 显存、带宽占用均消耗很大
具体可以参考[1]这篇文章,介绍的比较详细。这里简单总结如下:
- 在一个像素内部生成若干采样点
- 针对采样点进行覆盖测试和深度测试
- 一个像素至多运行一次片段着色(假如有内部采样点通过测试)
- 将颜色复制给通过测试的采样点
- 对所有采样点进行混合(Resolve),得到像素最终颜色。
优势:
- 硬件支持
- 片段着色保持X1不变(一个像素只执行一次PS)
劣势:
- 显存占用同SSAA
- 只能处理几何走样,无法处理Shading走样、AlphaTest走样等等
- 难以兼容延迟渲染
- 对于一些复杂的几何场景,开销可能会高于基于后处理的一些AA算法
SMAA是MLAA的GPU优化版本(MLAA是纯CPU抗锯齿),因此两者的思路是一致的。 SMAA属于图像后处理抗锯齿算法。其原理可以概述如下:
- 通过算法判定当前像素是否为边缘
- 这里可以是基于亮度的、或者depth的、或者normal+objectInstanceId的。
- 这作为单独的一个Pass,将生成一张EdgeTexture
- 针对边缘像素,往边缘两侧(MainDirection)搜索直到尽头,得到两个端点。在端点处,往交叉方向(Cross Direction)采样,以确定锯齿形态,总共24种锯齿形态。根据锯齿形态,来计算权重贴图。这是第二个Pass。
- 为了加速计算过程,会使用一张预生成的AreaTex。
- 根据权重贴图,与周边像素进行混合。这是第三个Pass。
英文原版可以参考此篇: [6] Jorge Jimenez, Subpixel-Morphological-Anti-Aliasing, 2011
或者中文Blog可以参考此篇: https://www.qiujiawei.com/antialiasing/
FXAA是SMAA的简化版本。主要的理论方向是一致的,但是不会那么细致的去区分各种锯齿形态。其在边缘判定和形态判定算法上做了一定的简化,仅需一个Pass即可。牺牲一定的效果以获得性能的提升。详细的FXAA理论技术分析请参考此篇: FXAA算法演义
优势:
- 显存占用低
- 无硬件要求
- 可以处理Shading引起的走样
- 性能开销固定
劣势:
- 由于FXAA对所有颜色边缘进行柔化,会导致无差别的模糊
使用FXAA有如下的注意点:
- 在HDR模式下,FXAA必须在ToneMap到LDR空间后再进行
- 如果渲染计算是在线性颜色空间进行,那么FXAA必须在转到sRGB空间后再进行
关于第1点,[3]中描述如下:
For example a 0.0 intensity pixel and a 16.0 intensity pixel will average to a 8.0 intensity pixel which later might get tone-mapped to 1.0 intensity. (which results in no blend between the two pixels).
这个不难理解,因为HDR到LDR的映射不是线性的。因此即便在HDR空间进行反走样计算,在ToneMap后依然会失去"平均"的效果。
关于第2点,[3]中描述如下:
FXAA requires the non-linear (perceptually encoded) RGB input and texture filtering: as a performance optimization, the algorithm’s end-of-edge search step samples halfway between a pair of texels, and it is important that the fetch returns the perceptual blend of the two texels instead of the linearly correct blend.
TAA时利用历史帧,来进行超采样的抗锯齿技术。其步骤如下:
- 对投影矩阵进行抖动,以达到每帧采样uv在像素内部进行抖动。
- 理论上来说,我们将N帧采样结果进行混合后,就能得到超采样抗锯齿的效果。
- 但实际上,不可能存下N帧历史图像。因此仅存上一帧历史图像,并进行加权混合。
由于摄像机会运动,因此前后两帧摄像机的位置可能并不相同。因此在采样上一帧的像素时,需要:
- 保存上一帧的投影矩阵
- 根据当前帧像素的世界坐标,利用上一帧的投影矩阵,即可还原出上一帧的UV,并进行采样。(如果uv超出,则废弃)。
由于场景中存在运动的物体,因此即便摄像机静止不动,同一个位置的像素也会因为物体的运动而发生变化。因此需要:
- 保存一份VelocityBuffer,记录了每个像素的速度。
- 根据当前帧像素的世界坐标,利用速度向量反推出其在上一帧的世界坐标。
知乎有详细介绍的一篇文章 - chopper - 深入浅出Temporal Antialising
[2] RenderBufferLoadAction&RenderBufferStoreAction的详细说明
[3] Timothy Lottes, FXAA White Paper, 2009
[4] Simon Rodriguez, Implementing FXAA, 2016
[5] SIGGRAPH 2011 presentation on FXAA 3.11
[6] Jorge Jimenez, Subpixel-Morphological-Anti-Aliasing, 2011