什么是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效果
新的一帧里会暴露前一帧被遮挡的面元,而当前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采样的,可以优化为十字采样(上左下右中)
Color Space
采样AABB时会计算color,因为人眼对亮度更加敏感,这里可以使用RGB/Luminace/Ycocg三种方式来对color进行转换,它们的质量和性能消耗依次递
Better Motion Vector
Motion Vector不能完美解决当人物运动时TAA产生的鬼影,可以额外采样一张人物的Mask图,来避免和其他不属于人物的pixel混合,随后再做lerp和Clip
差异化处理动静物体
若历史帧的权重占比越高,画面会越糊且鬼影越明显;若历史帧的权重占比越低,画面闪烁越严重
- 鸣潮提到的方案是利用motion vector的大小对历史帧的权重控制,当速度越快(motion vector越大),当前帧的比例越高;当速度越慢,历史帧的比例越高
测试性能
3080平台,在3x3滤波、Ycocg空间、VarianceClip条件下,总耗时0.49ms
Comments | NOTHING