CompassProFogOfWar.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using System;
  4. using System.Text;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using UnityEngine.SceneManagement;
  8. namespace CompassNavigatorPro {
  9. public partial class CompassPro : MonoBehaviour {
  10. [NonSerialized]
  11. public bool needFogOfWarUpdate, needFogOfWarTextureUpdate;
  12. const string FOG_OF_WAR_LAYER = "FogOfWarLayer";
  13. Texture2D fogOfWarTexture;
  14. Color32[] fogOfWarColorBuffer;
  15. Material fogOfWarMaterial;
  16. int fogOfWarAutoClearLastPosX, fogOfWarAutoClearLastPosZ;
  17. #region Fog Of War
  18. void UpdateFogOfWarOnLoadScene(Scene scene, LoadSceneMode loadMode) {
  19. if (loadMode == LoadSceneMode.Single) {
  20. UpdateFogOfWar ();
  21. }
  22. }
  23. void UpdateFogOfWarTexture () {
  24. if (miniMapCamera == null)
  25. return;
  26. Transform fogOfWarLayer = transform.Find (FOG_OF_WAR_LAYER);
  27. if (fogOfWarLayer != null) {
  28. DestroyImmediate (fogOfWarLayer.gameObject);
  29. }
  30. if (!_fogOfWarEnabled) return;
  31. if (fogOfWarTexture == null || fogOfWarTexture.width != _fogOfWarTextureSize || fogOfWarTexture.height != _fogOfWarTextureSize) {
  32. fogOfWarTexture = new Texture2D (_fogOfWarTextureSize, _fogOfWarTextureSize, TextureFormat.Alpha8, false);
  33. fogOfWarTexture.hideFlags = HideFlags.DontSave;
  34. fogOfWarTexture.filterMode = FilterMode.Bilinear;
  35. fogOfWarTexture.wrapMode = TextureWrapMode.Clamp;
  36. }
  37. // Update bounds
  38. ResetFogOfWar (_fogOfWarDefaultAlpha);
  39. CompassProFogVolume[] fv = FindObjectsOfType<CompassProFogVolume> ();
  40. Array.Sort (fv, VolumeComparer);
  41. for (int k = 0; k < fv.Length; k++) {
  42. Collider collider = fv [k].GetComponent<Collider> ();
  43. if (collider != null && collider.gameObject.activeInHierarchy) {
  44. SetFogOfWarAlpha (collider.bounds, fv [k].alpha, fv [k].border);
  45. }
  46. }
  47. needFogOfWarTextureUpdate = true;
  48. }
  49. void UpdateFogOfWarPosition () {
  50. if (!_fogOfWarEnabled)
  51. return;
  52. if (needFogOfWarUpdate) {
  53. needFogOfWarUpdate = false;
  54. UpdateFogOfWarTexture ();
  55. }
  56. if (_fogOfWarAutoClear && miniMapFollow != null) {
  57. Vector3 pos = miniMapFollow.transform.position;
  58. int x = (int)pos.x;
  59. int z = (int)pos.z;
  60. if (x != fogOfWarAutoClearLastPosX || z != fogOfWarAutoClearLastPosZ) {
  61. fogOfWarAutoClearLastPosX = x;
  62. fogOfWarAutoClearLastPosZ = z;
  63. SetFogOfWarAlpha (pos, _fogOfWarAutoClearRadius, 0, 1f);
  64. }
  65. }
  66. if (needFogOfWarTextureUpdate) {
  67. needFogOfWarTextureUpdate = false;
  68. if (fogOfWarTexture != null) {
  69. fogOfWarTexture.SetPixels32(fogOfWarColorBuffer);
  70. fogOfWarTexture.Apply ();
  71. miniMapMaterialRefresh = true;
  72. }
  73. }
  74. }
  75. int VolumeComparer (CompassProFogVolume v1, CompassProFogVolume v2) {
  76. if (v1.order < v2.order) {
  77. return -1;
  78. } else if (v1.order > v2.order) {
  79. return 1;
  80. } else {
  81. return 0;
  82. }
  83. }
  84. /// <summary>
  85. /// Changes the alpha value of the fog of war at world position creating a transition from current alpha value to specified target alpha. It takes into account FogOfWarCenter and FogOfWarSize.
  86. /// Note that only x and z coordinates are used. Y (vertical) coordinate is ignored.
  87. /// </summary>
  88. /// <param name="worldPosition">in world space coordinates.</param>
  89. /// <param name="radius">radius of application in world units.</param>
  90. /// <param name="fogNewAlpha">target alpha value.</param>
  91. /// <param name="border">value that determines the hardness of the border.</param>
  92. public void SetFogOfWarAlpha (Vector3 worldPosition, float radius, float fogNewAlpha, float border) {
  93. if (fogOfWarTexture == null)
  94. return;
  95. float tx = (worldPosition.x - _fogOfWarCenter.x) / _fogOfWarSize.x + 0.5f;
  96. if (tx < 0 || tx > 1f)
  97. return;
  98. float tz = (worldPosition.z - _fogOfWarCenter.z) / _fogOfWarSize.z + 0.5f;
  99. if (tz < 0 || tz > 1f)
  100. return;
  101. int tw = fogOfWarTexture.width;
  102. int th = fogOfWarTexture.height;
  103. int px = Mathf.Clamp ((int)(tx * tw), 0, tw - 1);
  104. int pz = Mathf.Clamp ((int)(tz * th), 0, th - 1);
  105. int colorBufferPos = pz * tw + px;
  106. byte newAlpha8 = (byte)(fogNewAlpha * 255);
  107. float tr = radius / _fogOfWarSize.z;
  108. int delta = (int)(th * tr);
  109. int deltaSqr = delta * delta;
  110. for (int r = pz - delta; r <= pz + delta; r++) {
  111. if (r >= 0 && r < th) {
  112. for (int c = px - delta; c <= px + delta; c++) {
  113. if (c >= 0 && c < tw) {
  114. int distanceSqr = (pz - r) * (pz - r) + (px - c) * (px - c);
  115. if (distanceSqr <= deltaSqr) {
  116. colorBufferPos = r * tw + c;
  117. Color32 colorBuffer = fogOfWarColorBuffer [colorBufferPos];
  118. float t = distanceSqr * border / deltaSqr;
  119. if (t > 1f) {
  120. t = 1f;
  121. }
  122. byte targetAlpha = (byte)(newAlpha8 * (1.0 - t) + colorBuffer.a * t); // Mathf.Lerp (newAlpha8, colorBuffer.a, t);
  123. colorBuffer.a = targetAlpha;
  124. fogOfWarColorBuffer [colorBufferPos] = colorBuffer;
  125. needFogOfWarTextureUpdate = true;
  126. }
  127. }
  128. }
  129. }
  130. }
  131. }
  132. /// <summary>
  133. /// Changes the alpha value of the fog of war within bounds creating a transition from current alpha value to specified target alpha. It takes into account FogOfWarCenter and FogOfWarSize.
  134. /// Note that only x and z coordinates are used. Y (vertical) coordinate is ignored.
  135. /// </summary>
  136. /// <param name="bounds">in world space coordinates.</param>
  137. /// <param name="fogNewAlpha">target alpha value.</param>
  138. /// <param name="border">value that determines the hardness of the border.</param>
  139. public void SetFogOfWarAlpha (Bounds bounds, float fogNewAlpha, float border) {
  140. if (fogOfWarTexture == null)
  141. return;
  142. Vector3 worldPosition = bounds.center;
  143. float tx = (worldPosition.x - _fogOfWarCenter.x) / _fogOfWarSize.x + 0.5f;
  144. if (tx < 0 || tx > 1f)
  145. return;
  146. float tz = (worldPosition.z - _fogOfWarCenter.z) / _fogOfWarSize.z + 0.5f;
  147. if (tz < 0 || tz > 1f)
  148. return;
  149. int tw = fogOfWarTexture.width;
  150. int th = fogOfWarTexture.height;
  151. int px = Mathf.Clamp ((int)(tx * tw), 0, tw - 1);
  152. int pz = Mathf.Clamp ((int)(tz * th), 0, th - 1);
  153. int colorBufferPos = pz * tw + px;
  154. byte newAlpha8 = (byte)(fogNewAlpha * 255);
  155. float trx = bounds.extents.x / _fogOfWarSize.x;
  156. float trz = bounds.extents.z / _fogOfWarSize.z;
  157. int deltax = (int)(tw * trx);
  158. int deltaz = (int)(th * trz);
  159. for (int r = pz - deltaz; r <= pz + deltaz; r++) {
  160. if (r >= 0 && r < th) {
  161. int distancez = pz - r;
  162. if (distancez < 0) distancez = -distancez;
  163. if (distancez > deltaz) continue;
  164. float dz = (deltaz - distancez + 1) / (deltaz * border + 0.0001f);
  165. for (int c = px - deltax; c <= px + deltax; c++) {
  166. if (c >= 0 && c < tw) {
  167. int distancex = px - c;
  168. if (distancex < 0) distancex = -distancex;
  169. if (distancex <= deltax) {
  170. colorBufferPos = r * tw + c;
  171. Color32 colorBuffer = fogOfWarColorBuffer [colorBufferPos];
  172. float dx = (deltax - distancex + 1) / (deltax * border + 0.0001f);
  173. float t = dx * dz;
  174. if (t > 1f) {
  175. t = 1f;
  176. }
  177. byte targetAlpha = (byte)(colorBuffer.a * (1f - t) + newAlpha8 * t); // Mathf.Lerp (colorBuffer.a, newAlpha8, t);
  178. colorBuffer.a = targetAlpha;
  179. fogOfWarColorBuffer [colorBufferPos] = colorBuffer;
  180. needFogOfWarTextureUpdate = true;
  181. }
  182. }
  183. }
  184. }
  185. }
  186. }
  187. /// <summary>
  188. /// Fill fog of war with a value
  189. /// </summary>
  190. public void ResetFogOfWar (float alpha = 1f) {
  191. if (fogOfWarTexture == null)
  192. return;
  193. int h = fogOfWarTexture.height;
  194. int w = fogOfWarTexture.width;
  195. int newLength = h * w;
  196. if (fogOfWarColorBuffer == null || fogOfWarColorBuffer.Length != newLength) {
  197. fogOfWarColorBuffer = new Color32[newLength];
  198. }
  199. byte a8 = (byte)(alpha * 255f);
  200. Color32 opaque = new Color32 (a8, a8, a8, a8);
  201. for (int k = 0; k < newLength; k++) {
  202. fogOfWarColorBuffer [k] = opaque;
  203. }
  204. isDirty = true;
  205. }
  206. /// <summary>
  207. /// Gets the current alpha value of the Fog of War at a given world position
  208. /// </summary>
  209. /// <returns>The fog of war alpha.</returns>
  210. /// <param name="worldPosition">World position.</param>
  211. public float GetFogOfWarAlpha (Vector3 worldPosition) {
  212. if (fogOfWarColorBuffer == null)
  213. return 1f;
  214. float tx = (worldPosition.x - _fogOfWarCenter.x) / _fogOfWarSize.x + 0.5f;
  215. if (tx < 0 || tx > 1f)
  216. return 1f;
  217. float tz = (worldPosition.z - _fogOfWarCenter.z) / _fogOfWarSize.z + 0.5f;
  218. if (tz < 0 || tz > 1f)
  219. return 1f;
  220. int tw = fogOfWarTexture.width;
  221. int th = fogOfWarTexture.height;
  222. int px = (int)(tx * tw);
  223. int pz = (int)(tz * th);
  224. int colorBufferPos = pz * tw + px;
  225. if (colorBufferPos < 0 || colorBufferPos >= fogOfWarColorBuffer.Length)
  226. return 1f;
  227. return fogOfWarColorBuffer [colorBufferPos].a / 255f;
  228. }
  229. #endregion
  230. }
  231. }