UE4 战争迷雾
战争迷雾这个游戏机制在 RTS
游戏中非常常见,主要就是逻辑可见性的可视化表达。
本篇文章就是要在 UE4
中实现一个简单的迷雾效果。基本的思路就是计算可见性,将可见性信息保存到纹理中,然后在后处理材质中将这个纹理映射到世界中。
Demo地址: https://github.com/jashking/UE4Practice
战争迷雾对象
这个类用来管理迷雾的基本属性,比如用到的后处理材质,迷雾颜色,范围,定时更新可见性纹理等功能。代码见 FogOfWar.h/cpp
简单解释:
- 一共有三张纹理用来记录可见性,主要是为了要实现可见性变化时候的过渡效果,一张记录当前的可见性,一张是最新的可见性,一张是混合的结果
- 纹理的
Filter
属性,要设置成TF_Bilinear
,不然边缘模糊效果会很奇怪 - 混合可见性纹理的时候,有一个
FlipY
的参数,要根据RHINeedsToSwitchVerticalAxis
结果来设定,因为在Android
机器上会有上下颠倒的问题 BlendTime
用来控制从旧可见性到新可见性的变化速度UpdateTime
用来控制每秒计算所有单位可见性的频率BlockSize
是指纹理上的一个像素对应的世界中的大小
可见性计算
本例中可见性计算用的是的开源的 libfov
库,是基于 Tiled
的可见性计算。本例中做了点修改,主要是将原来的 C
代码改为 C++
代码,见 Fov.h/cpp
。AFovCharacter
继承了 IFovInterface
接口,并实现了 CanSee
虚函数,在这里只是简单的返回 true
,表示都可见,如果返回 false
表示对应的坐标是不可见的,具体的可见与否根具体的游戏逻辑相关,就不扩展了,一般就是判断对应坐标上是不是阻挡视野的障碍物。
材质
这里用到两个材质,一个是用来做过渡效果的材质 M_FogBlend
,一个是后处理材质 M_FogOfWar
(实际用的是材质实例MI_FogOfWar
)
M_FogBlend
这个材质很简单,就是根据 Blend
的值做个 Lerp
插值
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;
还有一个要注意的地方是后处理材质的 Blendable Location
要使用 Before Tonemapping
,不然和之前说的一样,在 Android
上会出现上下颠倒的问题
参考文章
详细的迷雾相关的介绍和优化见逍遥剑客的文章: 游戏中的战争迷雾