手机端战争迷雾的实现

发表于2018-10-24
评论5 9.6k浏览
先展示效果:



最早是在war3看到战争迷雾,当时觉得真牛逼。到现在技术基本已经成熟,自己也就抽空做一个。

思路还是定在用tile来实现,毕竟从性能优化角度说,tile可以预先烘焙数据,比实时计算要快不少,这样的话手游也可以使用。

先画一批格子:

有了基本的地图数据,我们就需要开始考虑怎么实现我们的战争迷雾。首先把人的坐标转化到地图坐标,先考虑最基本的圆形,根据每个格子距离人的坐标的距离和视野半径比较,我们就可以得到这个格子是否可见。为了能够实现迷雾的效果,我们需要将这些数据保存在一张贴图中。而迷雾在人运动过程中需要变化,我们需要在这个过程中提供平滑的渐变过度,首先想到的是用两张图做过度,但其实只表示可见性的话,一个通道就够了,那么我们就用r通道存储上一次的可见范围,g通道存储这次的可见范围,然后做线性插值完成过度。

这里要注意,如果半径大,计算可见性范围其实会比较耗时,特别是如果要支持障碍视野的情况下,于是我们可以将这些计算放到子线程中做。现在手机多核,特别适合去用子线程做计算量大的东西。

算出全部的视野后,我们需要做一个世界坐标到屏幕坐标的投影,注意,这里的屏幕其实是贴图那个屏幕,

 实际使用过程中我们无需注意z轴,所以只需要设置好矩阵的xy和w部分就行。另外,由于这是opengl推倒出来的,我们可以知道它所对应的坐标系是(-1,1)的屏幕坐标,同时,纹理贴图是(0-1),这里要注意dx是左上角0,0,而opoengl是左下角0,0,这个我们可以通过在shader里处理,这里暂时先不管。

然后是要怎么具体实现迷雾效果的问题。首先我们思考在场景中的一个点,我们通过上面算的矩阵可以得到他在贴图中的坐标,根据贴图的像素值,我们可以得到这个点是否可见。问题在于,在知道点不可见后,我们如何遮住它。我们可以使用Projector,也可以在屏幕空间进行计算得到屏幕像素颜色。但考虑到手机上追求性能,我觉得将一个plane放在整个场景的上部,通过渲染plane达到遮盖的目的。当然问题也存在,就是如果地形高低变化很大,那么计算的迷雾就会产生错误,考虑到使用迷雾的大部分都是平地以及高低变化不大的地面,所以我认为这么做是值得的。

用了这样的做法,性能是达标了,但效果还是差了点。

仔细研究了一下,发现还有两个优化的点,一个是判断格子的时候,其实可以适当增加计算量,增加视野的精确度。

第二是需要改变先混合再计算这样的模式,而是混合时支持同步计算。这样可以是过度更加平滑。

最后我觉得还有一个点,就是场景要复杂一些,加上一点点半透明,整个战争迷雾的感觉会好很多。

修改了下判断格子的算法:

精确度上去了,然后就是平滑,首先把探索过的区域用一点点透明,然后把blend和update同时进行。

放到手机上跑了一下,可以到60帧,而且整个体验还算平滑。最后就是完善demo,做成插件了。

最后说几个细节点:

1.其实格子并不是越多越好,越多意味着性能开销越大,同时边界不为由于过度精确,做模糊的时候需要做更多模糊次数才有过度平滑的效果。个人觉得一个格子站住一个人调出来的效果其实是最好的。

2.如果是手机上,建议不要使用屏幕空间去计算,因为屏幕空间需要一张额外的深度图。除非你的地形高低变化很大,否则直接用一个大平面覆盖在你的地形上就好。只要起伏不大,位置误差还可以接受。

3.做迷雾变化过度要考虑到过度到一半视野发生更新的情况,要保证从现在的情况+多线程计算的时间到最终情况的过度。这样做出来的才会顺滑。

4.多线程立了大功,将迷雾计算和模糊都用多线程处理,基本不会引起帧率下降。而且视野计算精度可以用高一点的精度算法。

5.帧同步游戏我想了一下,应该没法使用多线程,或者说用多线程要做大量的额外工作去控制。所以帧同步估计还是需要地图预烘焙的方案,把模糊丢给gpu,应该就可以了。对于动态障碍物遮蔽视野,需要额外优化处理了。

最后是插件地址:

https://www.assetstore.unity3d.com/en/?stay#!/content/131480

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引