DynamicFogOfWar.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace DynamicFogAndMist {
  4. [ExecuteInEditMode]
  5. public class DynamicFogOfWar : MonoBehaviour {
  6. public int fogOfWarTextureSize = 512;
  7. Material fogMat;
  8. static DynamicFogOfWar _instance;
  9. Texture2D fogOfWarTexture;
  10. Color32[] fogOfWarColorBuffer;
  11. public static DynamicFogOfWar instance {
  12. get {
  13. if (_instance == null) {
  14. _instance = FindObjectOfType<DynamicFogOfWar> ();
  15. }
  16. return _instance;
  17. }
  18. }
  19. void OnEnable () {
  20. fogMat = GetComponent<MeshRenderer> ().sharedMaterial;
  21. UpdateFogOfWarTexture ();
  22. }
  23. void OnDisable () {
  24. if (fogOfWarTexture != null) {
  25. DestroyImmediate (fogOfWarTexture);
  26. fogOfWarTexture = null;
  27. }
  28. }
  29. void Update () {
  30. fogMat.SetVector ("_FogOfWarData", new Vector4 (transform.position.x, transform.position.z, transform.localScale.x, transform.localScale.y));
  31. }
  32. void UpdateFogOfWarTexture () {
  33. int size = GetScaledSize (fogOfWarTextureSize, 1.0f);
  34. fogOfWarTexture = new Texture2D (size, size, TextureFormat.ARGB32, false);
  35. fogOfWarTexture.hideFlags = HideFlags.DontSave;
  36. fogOfWarTexture.filterMode = FilterMode.Bilinear;
  37. fogOfWarTexture.wrapMode = TextureWrapMode.Clamp;
  38. fogMat.mainTexture = fogOfWarTexture;
  39. ResetFogOfWar ();
  40. }
  41. int GetScaledSize (int size, float factor) {
  42. size = (int)(size / factor);
  43. size /= 4;
  44. if (size < 1)
  45. size = 1;
  46. return size * 4;
  47. }
  48. #region Fog of War Public API
  49. /// <summary>
  50. /// Changes the alpha value of the fog of war at world position. It takes into account FogOfWarCenter and FogOfWarSize.
  51. /// Note that only x and z coordinates are used. Y (vertical) coordinate is ignored.
  52. /// </summary>
  53. /// <param name="worldPosition">in world space coordinates.</param>
  54. /// <param name="radius">radius of application in world units.</param>
  55. public void SetFogOfWarAlpha (Vector3 worldPosition, float radius, float fogNewAlpha) {
  56. if (fogOfWarTexture == null)
  57. return;
  58. float tx = (worldPosition.x - transform.position.x) / transform.localScale.x + 0.5f;
  59. if (tx < 0 || tx > 1f)
  60. return;
  61. float tz = (worldPosition.z - transform.position.z) / transform.localScale.y + 0.5f;
  62. if (tz < 0 || tz > 1f)
  63. return;
  64. int tw = fogOfWarTexture.width;
  65. int th = fogOfWarTexture.height;
  66. int px = (int)(tx * tw);
  67. int pz = (int)(tz * th);
  68. int colorBufferPos = pz * tw + px;
  69. byte newAlpha8 = (byte)(fogNewAlpha * 255);
  70. Color32 existingColor = fogOfWarColorBuffer [colorBufferPos];
  71. if (newAlpha8 != existingColor.a) { // just to avoid over setting the texture in an Update() loop
  72. float tr = radius / transform.localScale.y;
  73. int delta = Mathf.FloorToInt (th * tr);
  74. for (int r = pz - delta; r <= pz + delta; r++) {
  75. if (r > 0 && r < th - 1) {
  76. for (int c = px - delta; c <= px + delta; c++) {
  77. if (c > 0 && c < tw - 1) {
  78. int distance = (int) (Mathf.Sqrt ((pz - r) * (pz - r) + (px - c) * (px - c)));
  79. if (distance <= delta) {
  80. colorBufferPos = r * tw + c;
  81. Color32 colorBuffer = fogOfWarColorBuffer [colorBufferPos];
  82. colorBuffer.a = (byte)Mathf.Lerp (newAlpha8, colorBuffer.a, (float)distance / delta);
  83. fogOfWarColorBuffer [colorBufferPos] = colorBuffer;
  84. fogOfWarTexture.SetPixel (c, r, colorBuffer);
  85. }
  86. }
  87. }
  88. }
  89. }
  90. fogOfWarTexture.Apply ();
  91. }
  92. }
  93. public void ResetFogOfWar () {
  94. if (fogOfWarTexture == null)
  95. return;
  96. int h = fogOfWarTexture.height;
  97. int w = fogOfWarTexture.width;
  98. int newLength = h * w;
  99. if (fogOfWarColorBuffer == null || fogOfWarColorBuffer.Length != newLength) {
  100. fogOfWarColorBuffer = new Color32[newLength];
  101. }
  102. Color32 opaque = new Color32 (255, 255, 255, 255);
  103. for (int k = 0; k < newLength; k++)
  104. fogOfWarColorBuffer [k] = opaque;
  105. fogOfWarTexture.SetPixels32 (fogOfWarColorBuffer);
  106. fogOfWarTexture.Apply ();
  107. }
  108. public void SetFogOfWarTerrainBoundary (Terrain terrain, float borderWidth) {
  109. TerrainData td = terrain.terrainData;
  110. int tw = td.heightmapResolution;
  111. int th = td.heightmapResolution;
  112. float ta = td.size.y;
  113. float[,] heights = td.GetHeights (0, 0, tw, th);
  114. float y0 = transform.position.y - 1f;
  115. float y1 = transform.position.y + 10f;
  116. Vector3 halfSize = new Vector3(-td.size.x * 0.5f, 0, -td.size.z * 0.5f);
  117. for (int j = 0; j < th; j++) {
  118. for (int k = 0; k < tw; k++) {
  119. float h = heights [j,k] * ta + terrain.transform.position.y;
  120. if (h>y0 && h<y1) {
  121. Vector3 wpos = transform.position + halfSize + new Vector3( td.size.x * (k+0.5f) / tw, 0, td.size.z * (j+0.5f) / th);
  122. SetFogOfWarAlpha(wpos, borderWidth, 0);
  123. }
  124. }
  125. }
  126. }
  127. #endregion
  128. }
  129. }