FogVoidManager.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace VolumetricFogAndMist2 {
  4. [ExecuteInEditMode]
  5. [DefaultExecutionOrder(100)]
  6. public class FogVoidManager : MonoBehaviour, IVolumetricFogManager {
  7. public static bool usingVoids;
  8. public string managerName {
  9. get {
  10. return "Fog Void Manager";
  11. }
  12. }
  13. public const int MAX_FOG_VOID = 8;
  14. [Header("Void Search Settings")]
  15. public Transform trackingCenter;
  16. [Tooltip("Fog voids are sorted by camera distance every certain time interval to ensure the nearest 8 voids are used.")]
  17. public float distanceSortTimeInterval = 3f;
  18. readonly static List<FogVoid> fogVoids = new List<FogVoid>();
  19. Vector4[] fogVoidPositions;
  20. Vector4[] fogVoidSizes;
  21. Matrix4x4[] fogVoidMatrices;
  22. float distanceSortLastTime;
  23. static bool requireRefresh;
  24. int lastFogVoidCount;
  25. private void OnEnable() {
  26. if (trackingCenter == null) {
  27. Camera cam = null;
  28. Tools.CheckCamera(ref cam);
  29. if (cam != null) {
  30. trackingCenter = cam.transform;
  31. }
  32. }
  33. if (fogVoidPositions == null || fogVoidPositions.Length != MAX_FOG_VOID) {
  34. fogVoidPositions = new Vector4[MAX_FOG_VOID];
  35. }
  36. if (fogVoidSizes == null || fogVoidSizes.Length != MAX_FOG_VOID) {
  37. fogVoidSizes = new Vector4[MAX_FOG_VOID];
  38. }
  39. if (fogVoidMatrices == null || fogVoidMatrices.Length != MAX_FOG_VOID) {
  40. fogVoidMatrices = new Matrix4x4[MAX_FOG_VOID];
  41. }
  42. requireRefresh = true;
  43. }
  44. void LateUpdate() {
  45. if (!usingVoids) return;
  46. usingVoids = false;
  47. int fogVoidsCount = fogVoids.Count;
  48. if (fogVoidsCount != lastFogVoidCount) {
  49. lastFogVoidCount = fogVoidsCount;
  50. requireRefresh = true;
  51. }
  52. if (requireRefresh) {
  53. requireRefresh = false;
  54. TrackFogVoids(true);
  55. } else {
  56. if (fogVoidsCount == 0) return;
  57. TrackFogVoids();
  58. }
  59. SubmitFogVoidData();
  60. }
  61. void SubmitFogVoidData() {
  62. bool allowRotation = VolumetricFogManager.allowFogVoidRotation;
  63. int count = 0;
  64. int fogVoidsCount = fogVoids.Count;
  65. for (int i = 0; count < MAX_FOG_VOID && i < fogVoidsCount; i++) {
  66. FogVoid fogVoid = fogVoids[i];
  67. if (fogVoid == null || !fogVoid.isActiveAndEnabled) continue;
  68. Transform t = fogVoid.transform;
  69. Vector3 pos = t.position;
  70. Vector3 scale = t.lossyScale;
  71. if (scale.x < 0.01f) scale.x = 0.01f;
  72. if (scale.y < 0.01f) scale.y = 0.01f;
  73. if (scale.z < 0.01f) scale.z = 0.01f;
  74. scale.x *= 0.5f;
  75. scale.y *= 0.5f;
  76. scale.z *= 0.5f;
  77. fogVoidPositions[count].x = pos.x;
  78. fogVoidPositions[count].y = pos.y;
  79. fogVoidPositions[count].z = pos.z;
  80. fogVoidPositions[count].w = 10f * (1f - fogVoid.falloff) * (1f - fogVoid.falloff);
  81. if (allowRotation) {
  82. fogVoidMatrices[count] = Matrix4x4.TRS(pos, t.rotation, scale).inverse;
  83. } else {
  84. float width = scale.x;
  85. float height = scale.y;
  86. float depth = scale.z;
  87. fogVoidSizes[count].x = 1f / (0.0001f + width * width);
  88. fogVoidSizes[count].y = 1f / (0.0001f + height * height);
  89. fogVoidSizes[count].z = 1f / (0.0001f + depth * depth);
  90. }
  91. fogVoidSizes[count].w = fogVoid.roundness;
  92. count++;
  93. }
  94. Shader.SetGlobalInt(ShaderParams.VoidCount, count);
  95. if (count > 0) {
  96. Shader.SetGlobalVectorArray(ShaderParams.VoidPositions, fogVoidPositions);
  97. if (allowRotation) {
  98. Shader.SetGlobalMatrixArray(ShaderParams.VoidMatrices, fogVoidMatrices);
  99. }
  100. Shader.SetGlobalVectorArray(ShaderParams.VoidSizes, fogVoidSizes);
  101. }
  102. }
  103. public static void RegisterFogVoid(FogVoid fogVoid) {
  104. if (fogVoid != null) {
  105. fogVoids.Add(fogVoid);
  106. requireRefresh = true;
  107. }
  108. }
  109. public static void UnregisterFogVoid(FogVoid fogVoid) {
  110. if (fogVoid != null && fogVoids.Contains(fogVoid)) {
  111. fogVoids.Remove(fogVoid);
  112. requireRefresh = true;
  113. }
  114. }
  115. /// <summary>
  116. /// Look for nearest voids
  117. /// </summary>
  118. public void TrackFogVoids(bool forceImmediateUpdate = false) {
  119. // Look for new voids?
  120. if (fogVoids != null && fogVoids.Count > 0 && (forceImmediateUpdate || !Application.isPlaying || (distanceSortTimeInterval > 0 && Time.time - distanceSortLastTime > distanceSortTimeInterval))) {
  121. if (trackingCenter != null) {
  122. distanceSortLastTime = Time.time;
  123. fogVoids.Sort(fogVoidDistanceComparer);
  124. }
  125. }
  126. }
  127. int fogVoidDistanceComparer(FogVoid v1, FogVoid v2) {
  128. float dist1 = (v1.transform.position - trackingCenter.position).sqrMagnitude;
  129. float dist2 = (v2.transform.position - trackingCenter.position).sqrMagnitude;
  130. if (dist1 < dist2) return -1;
  131. if (dist1 > dist2) return 1;
  132. return 0;
  133. }
  134. public void Refresh() {
  135. requireRefresh = true;
  136. }
  137. }
  138. }