VolumetricFogManager.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. //#define FOG_VOID_ROTATION
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. namespace VolumetricFogAndMist2 {
  5. [ExecuteInEditMode]
  6. [HelpURL("https://kronnect.com/guides/volumetric-fog-urp-adding-volumetric-fog-mist-to-your-scene/#ftoc-heading-1")]
  7. public class VolumetricFogManager : MonoBehaviour, IVolumetricFogManager {
  8. public string managerName {
  9. get {
  10. return "Volumetric Fog Manager";
  11. }
  12. }
  13. static PointLightManager _pointLightManager;
  14. static FogVoidManager _fogVoidManager;
  15. static VolumetricFogManager _instance;
  16. [Tooltip("Directional light used as the Sun")]
  17. public Light sun;
  18. [Tooltip("Directional light used as the Moon")]
  19. public Light moon;
  20. [Tooltip("Flip depth texture. Use only as a workaround to a bug in URP if the depth shows inverted in GameView. Alternatively you can enable MSAA or HDR instead of using this option.")]
  21. public bool flipDepthTexture;
  22. [Tooltip("Enable this option to choose this manager when others could be loaded from sub-scenes")]
  23. public bool mainManager;
  24. [Tooltip("Optionally specify which transparent layers must be included in the depth prepass. Use only to avoid fog clipping with certain transparent objects.")]
  25. public LayerMask includeTransparent;
  26. [Tooltip("Cull mode for the transparent depth prepass")]
  27. public CullMode transparentCullMode = CullMode.Back;
  28. [Tooltip("Optionally specify which semi-transparent (materials using alpha clipping or cut-off) must be included in the depth prepass. Use only to avoid fog clipping with certain transparent objects.")]
  29. public LayerMask includeSemiTransparent;
  30. [Tooltip("Optionally determines the alpha cut off for semitransparent objects")]
  31. [Range(0, 1)]
  32. public float alphaCutOff;
  33. [Tooltip("Light scattering effect through fog")]
  34. [Range(0, 1)]
  35. public float scattering;
  36. [Tooltip("Threshold applied to input brightness")]
  37. public float scatteringThreshold;
  38. [Tooltip("Brightness multiplier applied to input")]
  39. public float scatteringIntensity;
  40. [Tooltip("Absorption or brightness decay inside the fog")]
  41. [Range(0, 1)]
  42. public float scatteringAbsorption = 0.35f;
  43. public Color scatteringTint = Color.white;
  44. [Tooltip("Uses higher resolution intermediate buffers and edge-aware upsampling filter")]
  45. public bool scatteringHighQuality;
  46. [Range(1, 8)]
  47. public float downscaling = 1;
  48. [Tooltip("Depth-based detection threshold for the upscaling reconstruction filter")]
  49. public float downscalingEdgeDepthThreshold = 0.05f;
  50. [Range(0, 6)]
  51. public int blurPasses;
  52. [Range(1, 8)]
  53. public float blurDownscaling = 1;
  54. [Range(0.1f, 4)]
  55. public float blurSpread = 1f;
  56. [Tooltip("Uses 16-bit RGBA floating point pixel format for rendering & blur fog volumes. If disabled, 8-bit RGBA pixel format will be used which can improve performance on certain devices. Note that if you use bloom or other HDR-based effects, you should enable this HDR option as well.")]
  57. public bool blurHDR = true;
  58. [Tooltip("Enable to use an edge-aware blur.")]
  59. public bool blurEdgePreserve = true;
  60. [Tooltip("Ignores blur when fog color intensity is below this value.")]
  61. public float blurEdgeDepthThreshold = 0.008f;
  62. [Range(0, 0.2f)]
  63. public float ditherStrength;
  64. // used to keep shader option in sync with scripting side
  65. #if FOG_VOID_ROTATION
  66. public static bool allowFogVoidRotation => true;
  67. #else
  68. public static bool allowFogVoidRotation => false;
  69. #endif
  70. const string SKW_FLIP_DEPTH_TEXTURE = "VF2_FLIP_DEPTH_TEXTURE";
  71. public const uint FOG_VOLUMES_RENDERING_LAYER = 1 << 49;
  72. public static VolumetricFogManager instance {
  73. get {
  74. if (_instance == null) {
  75. _instance = Tools.CheckMainManager();
  76. }
  77. return _instance;
  78. }
  79. }
  80. public static VolumetricFogManager GetManagerIfExists() {
  81. if (_instance != null && _instance.gameObject == null) _instance = null;
  82. if (_instance == null) {
  83. VolumetricFogManager[] managers = FindObjectsOfType<VolumetricFogManager>(true);
  84. int count = managers.Length;
  85. // look for main manager
  86. for (int k = 0; k < count; k++) {
  87. VolumetricFogManager manager = managers[k];
  88. if (manager.mainManager) {
  89. _instance = manager;
  90. return _instance;
  91. }
  92. }
  93. if (count > 0) {
  94. _instance = managers[0];
  95. }
  96. }
  97. return _instance;
  98. }
  99. public static PointLightManager pointLightManager {
  100. get {
  101. Tools.CheckManager(ref _pointLightManager);
  102. return _pointLightManager;
  103. }
  104. }
  105. public static FogVoidManager fogVoidManager {
  106. get {
  107. Tools.CheckManager(ref _fogVoidManager);
  108. return _fogVoidManager;
  109. }
  110. }
  111. void OnEnable() {
  112. // Forces other managers to be found
  113. _pointLightManager = null;
  114. _fogVoidManager = null;
  115. // Ensures no other fog manager exist
  116. VolumetricFogManager[] managers = FindObjectsOfType<VolumetricFogManager>(true);
  117. if (managers.Length > 1) {
  118. bool isThisTheMainManager = mainManager;
  119. for (int k = 0; k < managers.Length; k++) {
  120. if (!managers[k].mainManager) DestroyImmediate(managers[k].gameObject);
  121. }
  122. if (!isThisTheMainManager) return;
  123. }
  124. if (_instance == null) _instance = this;
  125. SetupLights();
  126. SetupDepthPrePass();
  127. Tools.CheckManager(ref _pointLightManager);
  128. Tools.CheckManager(ref _fogVoidManager);
  129. }
  130. void OnValidate() {
  131. downscalingEdgeDepthThreshold = Mathf.Max(0.0001f, downscalingEdgeDepthThreshold);
  132. blurEdgeDepthThreshold = Mathf.Max(0.0001f, blurEdgeDepthThreshold);
  133. scatteringThreshold = Mathf.Max(0, scatteringThreshold);
  134. scatteringIntensity = Mathf.Max(0, scatteringIntensity);
  135. SetupDepthPrePass();
  136. }
  137. void SetupLights() {
  138. Light[] lights = FindObjectsOfType<Light>();
  139. for (int k = 0; k < lights.Length; k++) {
  140. Light l = lights[k];
  141. if (l.type == LightType.Directional) {
  142. if (sun == null) {
  143. sun = l;
  144. }
  145. return;
  146. }
  147. }
  148. }
  149. void SetupDepthPrePass() {
  150. Shader.SetGlobalInt(SKW_FLIP_DEPTH_TEXTURE, flipDepthTexture ? 1 : 0);
  151. DepthRenderPrePassFeature.DepthRenderPass.SetupLayerMasks(includeTransparent, includeSemiTransparent);
  152. }
  153. /// <summary>
  154. /// Creates a new fog volume
  155. /// </summary>
  156. public static GameObject CreateFogVolume(string name) {
  157. GameObject go = Resources.Load<GameObject>("Prefabs/FogVolume2D");
  158. go = Instantiate(go);
  159. go.name = name;
  160. return go;
  161. }
  162. /// <summary>
  163. /// Creates a new fog void
  164. /// </summary>
  165. public static GameObject CreateFogVoid(string name) {
  166. return new GameObject(name, typeof(FogVoid));
  167. }
  168. /// <summary>
  169. /// Creates a new fog sub-volume
  170. /// </summary>
  171. public static GameObject CreateFogSubVolume(string name) {
  172. GameObject go = Resources.Load<GameObject>("Prefabs/FogSubVolume");
  173. go = Instantiate(go);
  174. go.name = name;
  175. return go;
  176. }
  177. }
  178. }