战争迷雾FogOfWar---Unity中实现
从最初的即时战略《沙丘2》开始,战争迷雾的概念开始被引入和正式提出。在沙丘中每一次新开始游戏时,玩家只能观察到自己基地及单位周围极小的范围,而绝大多数地图区域均被黑色遮盖。当他命令单位向黑暗区移动后,经过的区域会被自动打开,地图变得可见,包括该区域的地形/敌人活动情况等等。
红警战争迷雾&小地图添加
战争迷雾的实现方式是通过在地图与相机之间放置一层黑色面片,通过动态修改面片的局部透明度实现。
1.通过动态修改顶点颜色实现:
(1)准备工作:
新建一个用于迷雾的材质球
选择其材质为如下图:
并将Tint Color设置为完全的黑色
新建一个Layer命名ShadowMask(任意与存在Layer名字不同即可)
接下来新建一个Plane,将它延申到覆盖场景,改变其层的名字为shadowMask,勾选其MeshCollider的Convex(不勾选的话后边的射线检测会不起作用)
新建一个ShadowMask脚本,将脚本挂载到ShadowMask物体上,
public class ShadowMask : MonoBehaviour
{public GameObject shadowPlane;public Transform player;public LayerMask shadowMaskLayer;public float shadowRadius = 10f;private float radiusCircle { get { return shadowRadius * shadowRadius; } }private Mesh mesh;private Vector3[] verteies; // 顶点坐标位置private Color[] verteiesColors; //顶点坐标的颜色void Start(){}void Update(){}
}
将用到的信息设置好
(2)检测玩家移动后是否能准确与迷雾网格产生碰撞
public class ShadowMask : MonoBehaviour
{public GameObject shadowPlane;public Transform player;public LayerMask shadowMaskLayer;public float shadowRadius = 10f;private float radiusCircle { get { return shadowRadius * shadowRadius; } }private Mesh mesh;private Vector3[] verteies; // 顶点坐标位置private Color[] verteiesColors; //顶点坐标的颜色void Update(){Ray r = new Ray(player.position, player.position + Vector3.up * 100);Debug.DrawLine(player.position, player.position + Vector3.up * 100);RaycastHit hit;if (Physics.Raycast(r,out hit,1000,shadowMaskLayer,QueryTriggerInteraction.Collide)){Debug.Log(hit);}}
}
如果一起顺利,则控制台会打印出信息
(3)更换顶点颜色
void Update(){Ray r = new Ray(player.position, player.position + Vector3.up * 100);Debug.DrawLine(player.position, player.position + Vector3.up * 100);RaycastHit hit;if (Physics.Raycast(r,out hit,1000,shadowMaskLayer,QueryTriggerInteraction.Collide)){Debug.Log(hit);for (int i = 0; i < verteies.Length; i++){//将迷雾平面的顶点坐标变换到世界空间Vector3 v = shadowPlane.transform.TransformPoint(verteies[i]);//计算变换到世界空间下的顶点坐标与碰撞点的距离float distance = Vector3.SqrMagnitude(v - hit.point);if(distance < radiusCircle){float alpha = Mathf.Min(verteiesColors[i].a,distance/radiusCircle);verteiesColors[i].a = alpha;}}}UpdateVerteiesColors();}void UpdateVerteiesColors(){//更换顶点颜色mesh.colors = verteiesColors;}
实现效果如下图:
如果感觉效果太粗糙,可以将ShadowMask物体的顶点数增加,顶点数越多效果会更好一些
2.通过动态修改贴图像素的颜色实现:
准备工作和通过修改顶点颜色类似,只不过shadowMask的材质球需要更换shader,使用我写的这篇文章中的shader
Unity ShaderLab --- 实现局部透明-CSDN博客
然后需要动态的生成迷雾贴图,代码如下
Texture2D fogTxtur;Color[] pixelColors;int width;int height;float shadowRadius;public FogOfWarTexture(int width,int height,float rad){this.width = width;this.height = height;this.shadowRadius = rad;fogTxtur = new Texture2D(width,height);pixelColors = new Color[width * height];for (int i = 0; i < width; i++){for (int j = 0; j < height; j++){pixelColors[i * height + j] = Color.black;}}this.SetPixels(pixelColors);}void SetPixels(Color[] colors){fogTxtur.SetPixels(pixelColors);fogTxtur.Apply();}
并且在执行中需要不断改变, 代码如下
public void HandlerTetureColors(Vector3 point){for (int i = 0; i < this.width; i++){for (int j = 0; j < this.height; j++){if(Mathf.Abs(j - this.width/2 + point.x) < this.shadowRadius && Mathf.Abs(i- this.height/2 + point.z) < this.shadowRadius && pixelColors[i * this.height + j] == Color.black){pixelColors[i * this.height + j] = new Color(0,0,0,0);}}}this.SetPixels(pixelColors);}
输入的point值就是玩家移动发出射线与迷雾的物体碰撞点,代码如下:
void Update(){Ray r = new Ray(player.position, player.position + Vector3.up * 100);Debug.DrawLine(player.position, player.position + Vector3.up * 100);RaycastHit hit;if (Physics.Raycast(r, out hit, 1000, shadowMaskLayer, QueryTriggerInteraction.Collide)){Debug.Log(hit);fogTexture.HandlerTetureColors(hit.point); }}
实现效果如下图
参考链接:
Unity Shadow, Fog Walk Path (Fog of war) (youtube.com)
Unity Fog Of War Tutorial. Dynamic shader based fog of war (youtube.com)