zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    实现只有0,1,2三种元素的乱序数组的排序
    请说明Request和Session的生命周期
    使用Enumeration和Iterator遍历集合类
    hive中分组取前N个值的实现
    世界知名网站的技术实现(转)
    蚂蚁变大象:浅谈常规网站是如何从小变大的(转)
    Hadoop管理员的十个最佳实践(转)
    internet笔记
    Instagram 架构分析笔记(转)
    Apache Pig入门 –介绍/基本架构/与Hive对比(转)
  • 原文地址:https://www.cnblogs.com/DOGame/p/14473560.html
Copyright © 2011-2022 走看看