如果不是最近特别在这问题上钻牛角尖,可能再过几年都不会意识到它的存在。分析出来,最大的问题竟然是出在那看似人畜无害的后处理栈和抗锯齿上。
最后还会提一嘴在游玩时造成卡顿感的其他因素(代码方面)。
抗锯齿是如何跟卡顿感挂钩的
一般情况下我们会默认使用FXAA抗锯齿方案。这种方案的好处就如同它的名字,很快,很省性能。而且近景抗锯齿效果也还行。
但是,它对于远景和动态物体的抗锯齿效果完全可以说是一坨屎,甚至你会发现远景的景物锯齿多到无比明显。
这样一种中远景锯齿多到令人无视不了画面,会在相机转动的时候变得更加明显,你会看到无数肉眼清晰可见的锯齿块粘成一坨在中远景处闪来闪去,如同透过冒险小虎队解密卡看到的幻灯片一样。
所以就算你的游戏本身帧率很高,这样的画面也会给你带来游戏不流畅的错觉,甚至看多了会觉得心理不适。
解决这个问题是非常简单的,你可以用unity自带的TAA,把jitter拉到0.9左右,中远景就会融合得非常自然,且不会出现时常闪烁的锯齿块。当然MSAA也不错,但不推荐用unity的SMAA(和MSAA不是一个东西,没打错),会造成细节崩坏的情况,相比之下TAA则可以保留更多画面细节,且在森林、草原这类动态物体较多的场景里也能有很高的细节保留度。
慎用后处理
后处理也是卡顿重灾区,有时候只是一个普通的效果进行了屏幕空间相关的计算,当你走到动态物体(或者是shader动画)多的地方时,就能让cpu延迟飙升为原来的2倍甚至3倍之多。(如SSAO、HBAO、各种AO)
并且,一些后处理效果是在抗锯齿计算结束之后才叠到画面上的,就像ps的画布那样新建了一层画布上去,这又会让你的画面远景带上很多锯齿,给你带来不悦的锯齿块,同时远近不匹配的清晰度也会让你游玩时感到难受无比。(如edge detection)
有时候,一些采样和抖动量低的bloom、径向模糊也会因为不平滑的像素色阶叠加而带来锯齿,同样也会让你感受到卡顿。而更糟糕的情况下,它们甚至会因为一些糟糕的算法拉低你的硬件效率,从而让你真正发生掉帧,而非心理上感受到掉帧。
总而言之,存在锯齿会让人在心理上感受到画面的不连贯,而一些滥用的后处理则会在硬件上带来意想不到的卡顿和掉帧。优化之后,对这几样东西稍加留意,即使做出来的场景cpu延迟有10ms、帧率低于200帧,在游玩的时候也丝毫不会感受到卡顿。
Time.deltaTime
没错,就是这个玩意,任何一个游戏行业从业者在写自己的第一段移动代码时,一定都被老师千叮咛万嘱咐过要在移动矢量后面乘上它。
为什么这玩意非乘不可?
先简述它的意义:deltaTime就是指当前每两帧之间的间隔时间(单位:s)。
这个时间自然不是固定的,也不可能是常量,由硬件设备的算力、引擎的算法来决定。所以难免会出现渲染后两帧的间隔时间比前两帧的间隔时间更长/更短的情况。
Unity的Time.deltaTime一直都不如UE做得稳定,值的波动区间非常大。虽然官方在社区里说过未来版本会把它变得更稳定,也是to do的东西,但我们总不可能等他们把这更好的deltaTime磨出来才去做游戏。
所以要养成在任何移动相关的矢量后面都乘上Time.deltaTime的习惯,无论是相机的移动代码,还是角色的移动代码。这两者只要其中有一个被deltaTime较大的值波动影响到了,那另一个也肯定会出问题。
简而言之,你的角色移动速度没有乘以deltaTime就会变得不平均,相机的运动画面也会变得撕裂而不连贯,即使你的相机本身运动代码是丝滑的,但由于跟随的角色不丝滑,最后呈现在屏幕上的感觉也会不丝滑。
算法:
1. 矢量||值 * (稳定而平均的deltaTime值/ Time.deltaTime)
2. 矢量||值 + (矢量||值 * Time.deltaTime)
如果使用该方法之后还有卡顿,那就build整个项目,你会发现不该出现的卡顿已经完全消失了。unity的编辑器并不是毫无性能消耗的,不要将编辑器里偶尔出现的卡顿看作是游戏里会出现的卡顿。
网友评论