Chango的数学Shader世界(十四)细线间断,发光闪烁,TAA削弱处理

目的:

减少游戏中的细线因屏幕分辨率不足和算法采样不足问题,导致的间断,以及相对的自发光闪烁。解决了此问题也附带解决了因TAA导致的细线自发光微弱的问题。

对比视频:https://www.bilibili.com/video/av67438336

参考:

无,原创。外网UE4 AnswerHub有类似问题,但无正确的解决方案。

观察:

方块的边缘线条材质,是根据UV坐标判定的材质,因视效要求,其边是完全"硬"的。也就是说,比如uv.x<0.1,自发光为90;一旦大于0.1,自发光就是0。

这样的材质,边缘线细,自发光高。

会出现如下问题:

1.一旦拉远,线开始间断:

2.一旦拉远,因TAA关系,线条开始闪烁,自发光开始闪烁;线有时变得过分细,自发光被削弱(无AA,FXAA,TAA):

(无AA和FXAA基本一样,只是FXAA边缘更模糊,TAA显得像是没有自发光,并线条闪烁)

当我把材质自发光减少到1(无AA,FXAA,TAA):

(无AA和FXAA基本一样,只是FXAA边缘更模糊,TAA显著改善,但线条闪烁难忍)

分析:

1.为何拉远线条间断?

你可以在任意3维软件(游戏引擎,游戏,拟真软件,GIS系统)中,由近到极远地观察细线。只要线不是完全垂直或水平,你会发现远到一定程度时,线条会先出现明显的锯齿,然后是很奇妙的带周期性的间断,最后消失(一般软件不会让你看到这么远)。

这个问题无法100%解决,处理方法也多种多样。就我最近看到的,《底特律·变人》中,采用了真实镜头景深,这样你远处的线就模糊了。(讲道理,如果我们的眼睛没有景深,岂不是也有锯齿...)

问题发生的实质:采样不足,不符合Nyquist定理

在此案例中,也就是uv采样不足,屏幕分辨率不够细+算法问题。回看文章二中采样不足后发生的奇妙的周期性波形:

是否和采样不足的间断线有些类似呢?

由于线条在视口中急剧减小,间断线的波长会稳步变大。但其因采样不足所导致的周期性是一致的。

要澄清一点,这里的线这么近就开始间断,与uv采样不足也有关系。也就是我们的Shader的那个"硬边",加剧了采样不足。

1.1线条间断问题

下面抽象地分析发生锯齿和间断地原因。图中的方格即是1个像素。

这个锯齿和传统锯齿没啥区别,抗锯齿算法也能基本应付。当采样点实在少了,锯齿实在大了,抗锯齿算法也无能为力。

周期性间断就是锯齿的夸张大采样版。

1.2TAA导致的线条闪烁->自发光闪烁;线条削弱->自发光削弱问题

接上面线条间断,这里能看出为什么TAA的一些优劣。

因为TAA算法本质是在玩家视点微调不同的角度,采样出的像素再平均。

同一条线在屏幕上以不同的斜率被采样过,间断有可能因此减少。

但因不随机断微调视角,结果又不稳定带来的难以忍受的闪烁。

(TAA抖动原理见某乎文章:https://zhuanlan.zhihu.com/p/41642855)

而且有些线条因为微调视角后都采样到的主要是方块内红间,平均下来,把亮边部分的亮度给稀释了,如上图3左下角的线段。

1.3UV采样导致的线条削弱->自发光削弱

即使不用任何AA,由于原材质的硬边,也会导致线条削弱问题。

下面抽象地分析原因。假设亮边部分值为1,方块内为0。

假设当采样步长为0.01,此时的亮边处于正常状态。

当采样步长为0.03(也就是方块离我们远了,现在1个像素代表的世界长度是原来的3倍),问题开始出现了:

p1,p2,p3没问题。p4照理来说应该是“三分之一个亮边”,但因中心点采样到uv.x>0.1,判定为0个亮边。这和实际是相违背的。

这本质上还是一个锯齿问题。。。

我们怎么做?想办法让p4就等于0.3啊。

于是和抗锯齿基本的解决办法—与周围作平均(模糊边缘)一样,我们想办法让亮边函数不再是阶越函数,而是模糊的连续函数。根据具体情况,调整连续函数的参数。

根据我们上面的推导,模糊边虽然近看不符合视效要求,但远看符合真实的效果。

效果对比(无AA,TAA):

其函数的连续性也顺带解决了TAA的抖动问题。

通过对不同距离段调整参数,获得不同的亮边函数,再根据距离判断,插值,能得到最终的解决方案。

解决方法虽然很简单,但知道在哪里画这个圈需要9999美元。

步骤:

由于我是instanced Mesh。所以不可能多个材质切换。只能在一个材质里根据距离切换函数。又发现ue4 instanced mesh中objectWSP-cameraWSP是固定的,但pixelDepth可以获得,所以根据pixelDepth切换。

我简单分了3个LOD。

LOD0是硬边函数,用于近处。

LOD1和LOD2是参数不同的软边。

其中LOD0切到LOD1和LOD1切到LOD0作了基于距离的lerp。因为0切到1距离很近(很近就开始出现锯齿了)。

而LOD1-2之间没有作lerp,因为太远看不清,没必要。

结语:

发布了43 篇原创文章 · 获赞 11 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41524721/article/details/100848315