AA反走样

锯齿产生的原因:

 

 

 

 

采样:

采样是 一种从模拟信号到数字信号再重建到模拟信号的过程

 

                    1倍频率和2倍频率 采样曲线

 

 

 

                       三角形采样

 

Nyquist采样定理

 

 说明:第一行 原始采样的轮子转动(假使第一行原始采样周期是1s 中转一圈,也就是周期是1)

    第二行 采样的轮子1/8 s 采样一次(此时看到的采样的轮子是逆时针旋转,明显是错误的)

    第三行 采样轮子 0.5s 采样一次(此时是该定理的临界值,无法看到轮子旋转方向)

      第四行  采样的轮子 0.25s 采样一次 (此时轮子可以恢复正确的转动方向,采样频率 > 2)

 

 重建:

 

 

 

卷积:

 

 

 

 

 

 

 AA 方案:SSAA、MSAA、FXAA、MLAA、SMAA、TXAA、TAA、DLSS

SSAA:

 

MSAA:

 

 

 

 

 

 TAA:

 

 

 

 

采样多帧颜色:

 

 

 

 

 

 历史颜色融合:

 

 

 

 

 

 TXAA:

 

 

 

 

FXAA:

 

 

 

 

 

 FXAA代码描述:

 

 

 

计算边缘朝向:

 

 

 

 估算梯度---计算边界:

 

 

 

 结果:

 

 

 

 

MLAA:

假设现在我们要对左边这样一张图片进行AA处理:

就需要找到中间图片中这条蓝色的线, 这就是对像素进行重矢量化(revectorization)

 

矢量化以后, 根据像素点被蓝色线覆盖的比例及位置, 就可以将像素进行处理, 得到右边图片. 这样, 我们就完成了AA处理的过程.

从这点出发, 我们可以大致梳理出我们想要的MLAA处理的流程:

  1. 边缘检测, 得到每个像素的边缘, 如下左图中绿色的线;
  2. 往左右两侧搜索边界线的终点, 即边缘线交叉的地方;
  3. 根据两侧交叉点位置, 将像素矢量化, 作出一条蓝色的线;
  4. 算出蓝色线覆盖像素的面积覆盖率;
  5. 根据覆盖率对像素进行处理

 

 

MLAA流程

实践中, 有这样几个问题需要解决:

  1. 每个点需要计算4条线;
  2. 搜索交叉边缘很慢;
  3. 重矢量化需要消耗大量带宽, 区域覆盖率计算很费;

针对这样几个问题, 我们提出了这样的解决方案:

  1. 像素边缘是共享的, 每个像素其实只需要计算左侧和上侧的边界;
  2. 借助双线性采样加速搜索;
  3. 使用预计算好的贴图, 避免实时计算.

 

接着来看具体的实现, 我们将MLAA实现分为三个PASS

 

 

PASS1:边缘检测

就是简单地检测目标像素和周围点像素之间是否构成边界, 因为边界信息是共享的, 所以这里我们只需要考虑左边和上边像素点的边界.

边界判断方式可以是以下几种之一:

  1. 根据颜色, 通过亮度函数 [公式] , 得到像素亮度, 再判断两个像素亮度差超过某个阈值(比如0.1), 则认为是边界. 最常用普适的方法;
  2. 根据深度值判断, 需要将深度值先转为线性的;
  3. 材质ID/法线, 适用于Deferred-Rendering.

这样, 我们成功得到了像素间的边界, 并保存到一张R8G8的贴图中(0表示无边界, 1表示有边界, RG分别是左侧和上侧).

 

PASS2:混合权重计算

包括这样三步:

  1. 在当前需要计算的边界线两侧进行搜索, 取得距离 [公式] ;
  2. 获取交叉处边界信息 [公式] ;
  3. 根据前面的信息算出像素覆盖率 [公式]

 

 

PASS3: 像素混合

这一步就是简单地取得上一步中的覆盖率信息, 并将颜色做混合.

 

 两个相邻像素颜色的混合, 其实就是两个颜色的线性插值. 这样, 我们又可以借助双线性采样, 从两个像素中间的某个位置取颜色, 直接得到插值后的颜色

 

SMAA:

SMAA对MLAA的几个部分做了如下改进:

1.更准确的边界判断

对于使用颜色判断边界的情况, 很容易出现边界误判, 使得本来不应该是边界的地方被视为边界, 比如一些光照很强的地方, 虽然亮度变化快, 但是不应该是边界. SMAA中使用Local contrast adaption对边界进行二次判断

 

 

 

             左图上侧, 红色部分是被错误计算的边界

假设我们现在要判断某个像素和左侧像素是否构成边界.

首先使用相对亮度差的绝对值和亮度差阈值初步判断是否构成边界:

[公式]

如果构成, 则需要根据周围点亮度再判断一次:

[公式]

如果二次判断通过, 这个边界被保留, 如果判断不通过, 这个边界被丢弃

2. 转角保留

在某些情况下, 一些几何体的棱角可能被错误地识别为是需要AA处理的部分.

 

 

 

比如图中左上的正方形, 很可能被MLAA处理成左中的样子, 这种情况下, 其实是不需要AA处理的.

那么如何分辨这样的情况呢? 这里SMAA沿着交叉边界, 往外再取一次边界值(图中 [公式]).

如果取不到边界, 则认为是需要进行AA处理.

如果还能取到边界, 则在原来计算出的覆盖率基础上, 再乘以一个转角系数 [公式] (范围是0~1, 通常取0.25). 比如右图中橙色, 黄色, 和蓝色, 分别代表三个不同转角系数下得到的新的覆盖率).

 

 

3. 对角线模式

MLAA中的模式, 主要针对的是水平方向和垂直方向. 然而这两种模式, 处理一些斜向的边界, 效果不是很好.

 

4. 更精确的边界搜索

前面在使用MLAA搜索边界时, 有可能在搜索途中遗漏一些交叉边界.

比如下图中在沿着左边进行搜索时, MLAA会使用橙色的点采样, 这样其实会将第一个左侧的边界遗漏, 因为搜索过程中, 仅判断了上边界, 没有判断左边界.

 

 

SMAA将双线性采样的技巧进一步发挥, 在右下图中的采样点采样, 在xy轴上取不同的偏移量, 这样就可以做到一次采样, 根据得到的值判断出周围4个点的信息.

如下图, 将采样点放置在2x2像素中心, 向左偏移1/3, 向下偏移1/6. 在R处采样, 在周围四个像素采样的权重分别为

 

 

 

 

2x2像素中, 共有16中可能的组合, 每种组合下, 双线性采样得到的值都是唯一的.

这样, 我们实现了带边界的搜索. 不过需要注意的时, 使用这种方法的话, 使用的边界信息必须是上下左右全部都包括, 而不能是MLAA中的只生成上左的边界.

 

 

https://zhuanlan.zhihu.com/p/342211163

https://zhuanlan.zhihu.com/p/71785353

https://blog.codinghorror.com/fast-approximate-anti-aliasing-fxaa/

posted @ 2021-03-03 15:15  GamesClient  阅读(116)  评论(0编辑  收藏  举报