Files
2026-02-21 16:45:37 +08:00

172 lines
4.6 KiB
C#

using UnityEngine;
namespace DynamicFogAndMist
{
[ExecuteInEditMode]
public class DynamicFogOfWar : MonoBehaviour
{
public int fogOfWarTextureSize = 512;
private Material fogMat;
private static DynamicFogOfWar _instance;
private Texture2D fogOfWarTexture;
private Color32[] fogOfWarColorBuffer;
public static DynamicFogOfWar instance
{
get
{
if (_instance == null)
{
_instance = Object.FindObjectOfType<DynamicFogOfWar>();
}
return _instance;
}
}
private void OnEnable()
{
fogMat = GetComponent<MeshRenderer>().sharedMaterial;
UpdateFogOfWarTexture();
}
private void OnDisable()
{
if (fogOfWarTexture != null)
{
Object.DestroyImmediate(fogOfWarTexture);
fogOfWarTexture = null;
}
}
private void Update()
{
fogMat.SetVector("_FogOfWarData", new Vector4(base.transform.position.x, base.transform.position.z, base.transform.localScale.x, base.transform.localScale.y));
}
private void UpdateFogOfWarTexture()
{
int scaledSize = GetScaledSize(fogOfWarTextureSize, 1f);
fogOfWarTexture = new Texture2D(scaledSize, scaledSize, TextureFormat.ARGB32, false);
fogOfWarTexture.hideFlags = HideFlags.DontSave;
fogOfWarTexture.filterMode = FilterMode.Bilinear;
fogOfWarTexture.wrapMode = TextureWrapMode.Clamp;
fogMat.mainTexture = fogOfWarTexture;
ResetFogOfWar();
}
private int GetScaledSize(int size, float factor)
{
size = (int)((float)size / factor);
size /= 4;
if (size < 1)
{
size = 1;
}
return size * 4;
}
public void SetFogOfWarAlpha(Vector3 worldPosition, float radius, float fogNewAlpha)
{
if (fogOfWarTexture == null)
{
return;
}
float num = (worldPosition.x - base.transform.position.x) / base.transform.localScale.x + 0.5f;
if (num < 0f || num > 1f)
{
return;
}
float num2 = (worldPosition.z - base.transform.position.z) / base.transform.localScale.y + 0.5f;
if (num2 < 0f || num2 > 1f)
{
return;
}
int width = fogOfWarTexture.width;
int height = fogOfWarTexture.height;
int num3 = (int)(num * (float)width);
int num4 = (int)(num2 * (float)height);
int num5 = num4 * width + num3;
byte b = (byte)(fogNewAlpha * 255f);
Color32 color = fogOfWarColorBuffer[num5];
if (b == color.a)
{
return;
}
float num6 = radius / base.transform.localScale.y;
int num7 = Mathf.FloorToInt((float)height * num6);
for (int i = num4 - num7; i <= num4 + num7; i++)
{
if (i <= 0 || i >= height - 1)
{
continue;
}
for (int j = num3 - num7; j <= num3 + num7; j++)
{
if (j > 0 && j < width - 1)
{
int num8 = (int)Mathf.Sqrt((num4 - i) * (num4 - i) + (num3 - j) * (num3 - j));
if (num8 <= num7)
{
num5 = i * width + j;
Color32 color2 = fogOfWarColorBuffer[num5];
color2.a = (byte)Mathf.Lerp((int)b, (int)color2.a, (float)num8 / (float)num7);
fogOfWarColorBuffer[num5] = color2;
fogOfWarTexture.SetPixel(j, i, color2);
}
}
}
}
fogOfWarTexture.Apply();
}
public void ResetFogOfWar()
{
if (!(fogOfWarTexture == null))
{
int height = fogOfWarTexture.height;
int width = fogOfWarTexture.width;
int num = height * width;
if (fogOfWarColorBuffer == null || fogOfWarColorBuffer.Length != num)
{
fogOfWarColorBuffer = new Color32[num];
}
Color32 color = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
for (int i = 0; i < num; i++)
{
fogOfWarColorBuffer[i] = color;
}
fogOfWarTexture.SetPixels32(fogOfWarColorBuffer);
fogOfWarTexture.Apply();
}
}
public void SetFogOfWarTerrainBoundary(Terrain terrain, float borderWidth)
{
TerrainData terrainData = terrain.terrainData;
int heightmapWidth = terrainData.heightmapWidth;
int heightmapHeight = terrainData.heightmapHeight;
float y = terrainData.size.y;
float[,] heights = terrainData.GetHeights(0, 0, heightmapWidth, heightmapHeight);
float num = base.transform.position.y - 1f;
float num2 = base.transform.position.y + 10f;
Vector3 vector = new Vector3((0f - terrainData.size.x) * 0.5f, 0f, (0f - terrainData.size.z) * 0.5f);
for (int i = 0; i < heightmapHeight; i++)
{
for (int j = 0; j < heightmapWidth; j++)
{
float num3 = heights[i, j] * y + terrain.transform.position.y;
if (num3 > num && num3 < num2)
{
Vector3 worldPosition = base.transform.position + vector + new Vector3(terrainData.size.x * ((float)j + 0.5f) / (float)heightmapWidth, 0f, terrainData.size.z * ((float)i + 0.5f) / (float)heightmapHeight);
SetFogOfWarAlpha(worldPosition, borderWidth, 0f);
}
}
}
}
}
}