1732130779485.png

什么是TAA?

TAA的原理借用SSAA的思想,SSAA在一个像素点上采样多个点提高采样率,最后加权平均。不同于SSAA在一帧中对一个像素点一次性采样多个点,TAA把对一个像素的采样过程均摊到多帧中,在当前帧结合先前的历史帧数据实现对一个像素点的多次采样

Jitter

为了抗锯齿,TAA的思想在于略微抖动相机(抖动uv),再将当前帧和前一帧混合。因此抖动算法的好坏会极大影响抗锯齿的效果,而影响TAA的好坏在于其随机抖动的偏移值是否均匀。为了得到更好的抗锯齿效果,这里抖动的选择并不是随机/伪随机序列,而是采用低差异序列,因为低差异序列有着更快的收敛速度和更高的画面质量

目前TAA最常用的是Halton(2,3)序列

具体来说是取Halton(2,3)序列的前八个采样点,这也是UE的做法。不过PlayDead提到过16个采样的效果更好

  • 实现

    抖动不在shader里实现,而是在render pass中改相机的裁剪矩阵

    这里提供常量offset和生成多种Halton序列多种方法

混合

抖动之后,就需要将当前帧和前一帧混合来抗锯齿。这里混合方法很简单,就是普通的插值

需要注意的是混合的时机

  • 实现

    虽然进行多帧混合效果会更好,但为了避免更高的性能损耗,还是只对两帧进行混合

    采用类似DX12的交换链的方法,只开辟两个缓冲区,在每一帧间交换它们,也能达到混合效果

    随后利用lerp,将当前帧和前一帧按一定比例α混合。α值越高,画面抖动越明显

鬼影

Motion Vector

  • 目前的效果在绝对静止的环境下没有问题,但当相机或物体运动起来,就会出现鬼影现象,这是因为采样时很可能前一帧和后一帧中,场景中同一点在屏幕上可能会有不同的位置,为了得到绝对正确的数据,需要对采样点重投影,也就是计算上一帧采样点的位置。但这只能解决物体不动,相机运动的情况,当两者同时运动,需要用Motion Vector贴图来记录物体在屏幕空间中的位置的变化,借此来还原物体在上一帧屏幕空间中的位置。Motion Vector贴图对精度有比较高的要求,一般采用RG16的格式存储。下图是笔者实现的Motion Vector效果

    1732128088626.gif

新的一帧里会暴露前一帧被遮挡的面元,而当前fragment在上一帧的位置是被别的物体覆盖,所以上一帧的错误的颜色就会混合至当前帧

  • 解决方案:基于当前帧某个3x3的uv区域来截断历史帧的目标像素的的颜色值,让其偏差不要太大,目前流行的有三种算法clamp、clip、VarianceClip

Clamping

对历史帧和当前帧颜色进行对比,将历史帧颜色 clamp 在合理的范围内

这种方法比较省,但效果不算太好,因为历史帧和当前帧的混合系数需要尽量低(最好在0.1左右)。但系数过低,会导致鬼影愈加严重;系数过高呢,抗锯齿效果会削弱

Clip

与clamp不同的是,clip用到了插值的思想。同样依然先计算九个像素的AABB颜色,判断历史帧的像素颜色值是否在该AABB范围内,在就直接用;不在则先进行AABB的平均颜色值,将历史帧颜色值和该颜色值相连,得到连线上的交点,使用交点处的颜色值作为插值因子

VarianceClip

锐化

TAA的结果比较模糊,模糊的反向其实是锐化,为此可以在最后对结果进行锐化

half3 sourceColor = GetSourceColor(uv_unJittered);
half3 sourceColorTL = GetSourceColor(uv_unJittered - _sourceTexSize.zw * 0.5f);
half3 sourceColorBR = GetSourceColor(uv_unJittered + _sourceTexSize.zw * 0.5f);
half3 corners = 4.f * (sourceColorTL + sourceColorBR) - 2.f * sourceColor;
sourceColor += (sourceColor - (corners * 0.1666667f)) * 2.718282 * _Sharpness;

优化

低通滤波

在采样AABB时是3x3采样的,可以优化为十字采样(上左下右中)
1732092650944.png

Color Space

采样AABB时会计算color,因为人眼对亮度更加敏感,这里可以使用RGB/Luminace/Ycocg三种方式来对color进行转换,它们的质量和性能消耗依次递

1732093017622.png

Better Motion Vector

Motion Vector不能完美解决当人物运动时TAA产生的鬼影,可以额外采样一张人物的Mask图,来避免和其他不属于人物的pixel混合,随后再做lerp和Clip

1732184156820.png

差异化处理动静物体

若历史帧的权重占比越高,画面会越鬼影越明显;若历史帧的权重占比越低,画面闪烁越严重

1732093510282.png

  • 鸣潮提到的方案是利用motion vector的大小对历史帧的权重控制,当速度越快(motion vector越大),当前帧的比例越高;当速度越慢,历史帧的比例越高

    1732119263321.png

测试性能

3080平台,在3x3滤波、Ycocg空间、VarianceClip条件下,总耗时0.49ms

unity-TAA

Reference

Unity URP实现TAA

Temporal Anti-Aliasing

[UFSH2023]《鸣潮》基于虚幻引擎4的多平台效果和性能优化实践 | 王宏波 库洛游戏


他们曾如此骄傲的活过,贯彻始终