PointLightManager.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace VolumetricFogAndMist2 {
  5. [ExecuteInEditMode]
  6. [DefaultExecutionOrder(100)]
  7. public class PointLightManager : MonoBehaviour, IVolumetricFogManager {
  8. public static bool usingPointLights;
  9. public string managerName {
  10. get {
  11. return "Point Light Manager";
  12. }
  13. }
  14. public const int MAX_POINT_LIGHTS = 16;
  15. [Header("Point Light Search Settings")]
  16. [Tooltip("Point lights are sorted by distance to tracking center object")]
  17. public Transform trackingCenter;
  18. [Tooltip("Point lights are sorted by camera distance every certain time interval to ensure the nearest 16 point lights are used.")]
  19. public float distanceSortTimeInterval = 3f;
  20. [Tooltip("Ignore point lights behind camera")]
  21. public bool excludeLightsBehind = true;
  22. [Header("Common Settings")]
  23. [Tooltip("Global inscattering multiplier for point lights")]
  24. public float inscattering = 1f;
  25. [Tooltip("Global intensity multiplier for point lights")]
  26. public float intensity = 1f;
  27. [Tooltip("Reduces light intensity near point lights")]
  28. public float insideAtten;
  29. readonly static List<FogPointLight> pointLights = new List<FogPointLight>();
  30. static bool requireRefresh;
  31. int lastPointLightsCount;
  32. Vector4[] pointLightColorBuffer;
  33. Vector4[] pointLightPositionBuffer;
  34. float distanceSortLastTime;
  35. private void OnEnable() {
  36. if (trackingCenter == null) {
  37. Camera cam = null;
  38. Tools.CheckCamera(ref cam);
  39. if (cam != null) {
  40. trackingCenter = cam.transform;
  41. }
  42. }
  43. if (pointLightColorBuffer == null || pointLightColorBuffer.Length != MAX_POINT_LIGHTS) {
  44. pointLightColorBuffer = new Vector4[MAX_POINT_LIGHTS];
  45. }
  46. if (pointLightPositionBuffer == null || pointLightPositionBuffer.Length != MAX_POINT_LIGHTS) {
  47. pointLightPositionBuffer = new Vector4[MAX_POINT_LIGHTS];
  48. }
  49. requireRefresh = true;
  50. }
  51. private void LateUpdate() {
  52. if (!usingPointLights) return;
  53. usingPointLights = false;
  54. int pointLightsCount = pointLights.Count;
  55. if (lastPointLightsCount != pointLightsCount) {
  56. lastPointLightsCount = pointLightsCount;
  57. requireRefresh = true;
  58. }
  59. if (requireRefresh) {
  60. requireRefresh = false;
  61. TrackPointLights(true);
  62. } else {
  63. if (pointLightsCount == 0) return;
  64. TrackPointLights();
  65. }
  66. SubmitPointLightData();
  67. }
  68. void SubmitPointLightData() {
  69. int count = 0;
  70. bool appIsRunning = Application.isPlaying;
  71. Vector3 trackingCenterPosition;
  72. Vector3 trackingCenterForward;
  73. bool isExcludingLightsBehind = excludeLightsBehind && appIsRunning;
  74. if (isExcludingLightsBehind && trackingCenter != null) {
  75. trackingCenterPosition = trackingCenter.position;
  76. trackingCenterForward = trackingCenter.forward;
  77. } else {
  78. trackingCenterPosition = trackingCenterForward = Vector3.zero;
  79. isExcludingLightsBehind = false;
  80. }
  81. int pointLightsCount = pointLights.Count;
  82. for (int i = 0; count < MAX_POINT_LIGHTS && i < pointLightsCount; i++) {
  83. FogPointLight fogPointLight = pointLights[i];
  84. if (fogPointLight == null || !fogPointLight.isActiveAndEnabled) continue;
  85. Light light = pointLights[i].pointLight;
  86. if (light == null || !light.isActiveAndEnabled || light.type != LightType.Point) continue;
  87. Vector3 pos = light.transform.position;
  88. float range = light.range;
  89. range *= fogPointLight.inscattering * inscattering / 25f; // note: 25 comes from Unity point light attenuation equation
  90. // if point light is behind camera and beyond the range, ignore it
  91. if (isExcludingLightsBehind) {
  92. Vector3 toLight = pos - trackingCenterPosition;
  93. float dot = Vector3.Dot(trackingCenterForward, pos - trackingCenterPosition);
  94. if (dot < 0 && toLight.sqrMagnitude > range * range) {
  95. continue;
  96. }
  97. }
  98. // add light to the buffer if intensity is enough
  99. float multiplier = light.intensity * fogPointLight.intensity * intensity;
  100. if (range > 0 && multiplier > 0) {
  101. pointLightPositionBuffer[count].x = pos.x;
  102. pointLightPositionBuffer[count].y = pos.y;
  103. pointLightPositionBuffer[count].z = pos.z;
  104. pointLightPositionBuffer[count].w = 0;
  105. Color color = light.color;
  106. pointLightColorBuffer[count].x = color.r * multiplier;
  107. pointLightColorBuffer[count].y = color.g * multiplier;
  108. pointLightColorBuffer[count].z = color.b * multiplier;
  109. pointLightColorBuffer[count].w = range;
  110. count++;
  111. }
  112. }
  113. Shader.SetGlobalInt(ShaderParams.PointLightCount, count);
  114. if (count > 0) {
  115. Shader.SetGlobalVectorArray(ShaderParams.PointLightColors, pointLightColorBuffer);
  116. Shader.SetGlobalVectorArray(ShaderParams.PointLightPositions, pointLightPositionBuffer);
  117. Shader.SetGlobalFloat(ShaderParams.PointLightInsideAtten, insideAtten);
  118. }
  119. }
  120. public static void RegisterPointLight(FogPointLight fogPointLight) {
  121. if (fogPointLight != null) {
  122. pointLights.Add(fogPointLight);
  123. requireRefresh = true;
  124. }
  125. }
  126. public static void UnregisterPointLight(FogPointLight fogPointLight) {
  127. if (fogPointLight != null && pointLights.Contains(fogPointLight)) {
  128. pointLights.Remove(fogPointLight);
  129. requireRefresh = true;
  130. }
  131. }
  132. /// <summary>
  133. /// Look for nearest point lights
  134. /// </summary>
  135. public void TrackPointLights(bool forceImmediateUpdate = false) {
  136. // Look for new lights?
  137. if (pointLights != null && pointLights.Count > 0 && (forceImmediateUpdate || !Application.isPlaying || (distanceSortTimeInterval > 0 && Time.time - distanceSortLastTime > distanceSortTimeInterval))) {
  138. if (trackingCenter != null) {
  139. distanceSortLastTime = Time.time;
  140. pointLights.Sort(pointLightsDistanceComparer);
  141. }
  142. }
  143. }
  144. int pointLightsDistanceComparer(FogPointLight l1, FogPointLight l2) {
  145. float dist1 = (l1.transform.position - trackingCenter.position).sqrMagnitude;
  146. float dist2 = (l2.transform.position - trackingCenter.position).sqrMagnitude;
  147. if (dist1 < dist2) return -1;
  148. if (dist1 > dist2) return 1;
  149. return 0;
  150. }
  151. public void Refresh() {
  152. requireRefresh = true;
  153. }
  154. }
  155. }