179 lines
6.8 KiB
C#
179 lines
6.8 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System.Collections;
|
|||
|
|
|
|||
|
|
namespace DynamicFogAndMist {
|
|||
|
|
|
|||
|
|
[ExecuteInEditMode]
|
|||
|
|
public class DynamicFogOfWar : MonoBehaviour {
|
|||
|
|
|
|||
|
|
public int fogOfWarTextureSize = 512;
|
|||
|
|
|
|||
|
|
|
|||
|
|
Material fogMat;
|
|||
|
|
static DynamicFogOfWar _instance;
|
|||
|
|
Texture2D fogOfWarTexture;
|
|||
|
|
Color32[] fogOfWarColorBuffer;
|
|||
|
|
|
|||
|
|
public static DynamicFogOfWar instance {
|
|||
|
|
get {
|
|||
|
|
if (_instance == null) {
|
|||
|
|
_instance = FindObjectOfType<DynamicFogOfWar>();
|
|||
|
|
}
|
|||
|
|
return _instance;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnEnable() {
|
|||
|
|
fogMat = GetComponent<MeshRenderer>().sharedMaterial;
|
|||
|
|
UpdateFogOfWarTexture();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnDisable() {
|
|||
|
|
if (fogOfWarTexture != null) {
|
|||
|
|
DestroyImmediate(fogOfWarTexture);
|
|||
|
|
fogOfWarTexture = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Update() {
|
|||
|
|
fogMat.SetVector("_FogOfWarData", new Vector4(transform.position.x, transform.position.z, transform.localScale.x, transform.localScale.y));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
void UpdateFogOfWarTexture() {
|
|||
|
|
int size = GetScaledSize(fogOfWarTextureSize, 1.0f);
|
|||
|
|
fogOfWarTexture = new Texture2D(size, size, TextureFormat.ARGB32, false);
|
|||
|
|
fogOfWarTexture.hideFlags = HideFlags.DontSave;
|
|||
|
|
fogOfWarTexture.filterMode = FilterMode.Bilinear;
|
|||
|
|
fogOfWarTexture.wrapMode = TextureWrapMode.Clamp;
|
|||
|
|
fogMat.mainTexture = fogOfWarTexture;
|
|||
|
|
ResetFogOfWar();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int GetScaledSize(int size, float factor) {
|
|||
|
|
size = (int)(size / factor);
|
|||
|
|
size /= 4;
|
|||
|
|
if (size < 1)
|
|||
|
|
size = 1;
|
|||
|
|
return size * 4;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region Fog of War Public API
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Returns the alpha value of fog of war at a given world space position
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="worldPosition">in world space coordinates.</param>
|
|||
|
|
public float GetFogOfWarAlpha(Vector3 worldPosition) {
|
|||
|
|
if (fogOfWarTexture == null)
|
|||
|
|
return 1;
|
|||
|
|
|
|||
|
|
float tx = (worldPosition.x - transform.position.x) / transform.localScale.x + 0.5f;
|
|||
|
|
if (tx < 0 || tx > 1f)
|
|||
|
|
return 1;
|
|||
|
|
float tz = (worldPosition.z - transform.position.z) / transform.localScale.y + 0.5f;
|
|||
|
|
if (tz < 0 || tz > 1f)
|
|||
|
|
return 1;
|
|||
|
|
|
|||
|
|
int tw = fogOfWarTexture.width;
|
|||
|
|
int th = fogOfWarTexture.height;
|
|||
|
|
int px = (int)(tx * tw);
|
|||
|
|
int pz = (int)(tz * th);
|
|||
|
|
int colorBufferPos = pz * tw + px;
|
|||
|
|
return fogOfWarColorBuffer[colorBufferPos].a / 255f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Changes the alpha value of the fog of war at world position. It takes into account FogOfWarCenter and FogOfWarSize.
|
|||
|
|
/// Note that only x and z coordinates are used. Y (vertical) coordinate is ignored.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="worldPosition">in world space coordinates.</param>
|
|||
|
|
/// <param name="radius">radius of application in world units.</param>
|
|||
|
|
public void SetFogOfWarAlpha(Vector3 worldPosition, float radius, float fogNewAlpha) {
|
|||
|
|
if (fogOfWarTexture == null)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
float tx = (worldPosition.x - transform.position.x) / transform.localScale.x + 0.5f;
|
|||
|
|
if (tx < 0 || tx > 1f)
|
|||
|
|
return;
|
|||
|
|
float tz = (worldPosition.z - transform.position.z) / transform.localScale.y + 0.5f;
|
|||
|
|
if (tz < 0 || tz > 1f)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
int tw = fogOfWarTexture.width;
|
|||
|
|
int th = fogOfWarTexture.height;
|
|||
|
|
int px = (int)(tx * tw);
|
|||
|
|
int pz = (int)(tz * th);
|
|||
|
|
int colorBufferPos = pz * tw + px;
|
|||
|
|
byte newAlpha8 = (byte)(fogNewAlpha * 255);
|
|||
|
|
Color32 existingColor = fogOfWarColorBuffer[colorBufferPos];
|
|||
|
|
if (newAlpha8 != existingColor.a) { // just to avoid over setting the texture in an Update() loop
|
|||
|
|
float tr = radius / transform.localScale.y;
|
|||
|
|
int delta = Mathf.FloorToInt(th * tr);
|
|||
|
|
for (int r = pz - delta; r <= pz + delta; r++) {
|
|||
|
|
if (r >= 0 && r < th) {
|
|||
|
|
for (int c = px - delta; c <= px + delta; c++) {
|
|||
|
|
if (c >= 0 && c < tw) {
|
|||
|
|
int distance = (int)(Mathf.Sqrt((pz - r) * (pz - r) + (px - c) * (px - c)));
|
|||
|
|
if (distance <= delta) {
|
|||
|
|
colorBufferPos = r * tw + c;
|
|||
|
|
Color32 colorBuffer = fogOfWarColorBuffer[colorBufferPos];
|
|||
|
|
colorBuffer.a = (byte)Mathf.Lerp(newAlpha8, colorBuffer.a, (float)distance / delta);
|
|||
|
|
fogOfWarColorBuffer[colorBufferPos] = colorBuffer;
|
|||
|
|
fogOfWarTexture.SetPixel(c, r, colorBuffer);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
fogOfWarTexture.Apply();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ResetFogOfWar() {
|
|||
|
|
if (fogOfWarTexture == null)
|
|||
|
|
return;
|
|||
|
|
int h = fogOfWarTexture.height;
|
|||
|
|
int w = fogOfWarTexture.width;
|
|||
|
|
int newLength = h * w;
|
|||
|
|
if (fogOfWarColorBuffer == null || fogOfWarColorBuffer.Length != newLength) {
|
|||
|
|
fogOfWarColorBuffer = new Color32[newLength];
|
|||
|
|
}
|
|||
|
|
Color32 opaque = new Color32(255, 255, 255, 255);
|
|||
|
|
for (int k = 0; k < newLength; k++)
|
|||
|
|
fogOfWarColorBuffer[k] = opaque;
|
|||
|
|
fogOfWarTexture.SetPixels32(fogOfWarColorBuffer);
|
|||
|
|
fogOfWarTexture.Apply();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SetFogOfWarTerrainBoundary(Terrain terrain, float borderWidth) {
|
|||
|
|
TerrainData td = terrain.terrainData;
|
|||
|
|
int tw = td.heightmapResolution;
|
|||
|
|
int th = td.heightmapResolution;
|
|||
|
|
float ta = td.size.y;
|
|||
|
|
float[,] heights = td.GetHeights(0, 0, tw, th);
|
|||
|
|
float y0 = transform.position.y - 1f;
|
|||
|
|
float y1 = transform.position.y + 10f;
|
|||
|
|
//Vector3 halfSize = new Vector3(-td.size.x * 0.5f, 0, -td.size.z * 0.5f);
|
|||
|
|
Vector3 terrainPos = terrain.GetPosition();
|
|||
|
|
for (int j = 0; j < th; j++) {
|
|||
|
|
for (int k = 0; k < tw; k++) {
|
|||
|
|
float h = heights[j, k] * ta + terrain.transform.position.y;
|
|||
|
|
if (h > y0 && h < y1) {
|
|||
|
|
Vector3 wpos = terrainPos + new Vector3(td.size.x * (k + 0.5f) / tw, 0, td.size.z * (j + 0.5f) / th);
|
|||
|
|
SetFogOfWarAlpha(wpos, borderWidth, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|