UE4 战争迷雾

战争迷雾这个游戏机制在 RTS 游戏中非常常见,主要就是逻辑可见性的可视化表达。

Dota2 战争迷雾效果
Dota2 战争迷雾效果

本篇文章就是要在 UE4 中实现一个简单的迷雾效果。基本的思路就是计算可见性,将可见性信息保存到纹理中,然后在后处理材质中将这个纹理映射到世界中。

Result.png

Demo地址: https://github.com/jashking/UE4Practice

战争迷雾对象

这个类用来管理迷雾的基本属性,比如用到的后处理材质,迷雾颜色,范围,定时更新可见性纹理等功能。代码见 FogOfWar.h/cpp

简单解释:

  • 一共有三张纹理用来记录可见性,主要是为了要实现可见性变化时候的过渡效果,一张记录当前的可见性,一张是最新的可见性,一张是混合的结果
  • 纹理的 Filter 属性,要设置成 TF_Bilinear,不然边缘模糊效果会很奇怪
  • 混合可见性纹理的时候,有一个 FlipY 的参数,要根据 RHINeedsToSwitchVerticalAxis 结果来设定,因为在 Android 机器上会有上下颠倒的问题
  • BlendTime 用来控制从旧可见性到新可见性的变化速度
  • UpdateTime 用来控制每秒计算所有单位可见性的频率
  • BlockSize 是指纹理上的一个像素对应的世界中的大小

可见性计算

本例中可见性计算用的是的开源的 libfov 库,是基于 Tiled 的可见性计算。本例中做了点修改,主要是将原来的 C 代码改为 C++ 代码,见 Fov.h/cppAFovCharacter 继承了 IFovInterface 接口,并实现了 CanSee 虚函数,在这里只是简单的返回 true,表示都可见,如果返回 false 表示对应的坐标是不可见的,具体的可见与否根具体的游戏逻辑相关,就不扩展了,一般就是判断对应坐标上是不是阻挡视野的障碍物。

材质

这里用到两个材质,一个是用来做过渡效果的材质 M_FogBlend,一个是后处理材质 M_FogOfWar(实际用的是材质实例MI_FogOfWar)

M_FogBlend

这个材质很简单,就是根据 Blend 的值做个 Lerp 插值

M_FogBlend
M_FogBlend

M_FogOfWar

这个后处理材质主要有以下两个地方要注意,一个是边缘的模糊,这个可以根据自己需要修改模糊效果

高斯模糊
高斯模糊

另一个就是屏幕像素的 WorldPosition,本来可以直接用 WorldPosition 节点,但是这个节点对于移动端的后处理材质是无效的,所以换了用屏幕坐标和深度来计算世界坐标

float4 pos = mul(float4(((ScreenPos.xy - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy) * SceneDepth, SceneDepth, 1.0), View.ScreenToWorld);
return pos.xyz * 1 / pos.w;

WorldPosition.png

还有一个要注意的地方是后处理材质的 Blendable Location 要使用 Before Tonemapping,不然和之前说的一样,在 Android 上会出现上下颠倒的问题

参考文章

详细的迷雾相关的介绍和优化见逍遥剑客的文章: 游戏中的战争迷雾