VolumetricFog.Terrain.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //------------------------------------------------------------------------------------------------------------------
  2. // Volumetric Fog & Mist 2
  3. // Created by Kronnect
  4. //------------------------------------------------------------------------------------------------------------------
  5. using UnityEngine;
  6. using UnityEngine.Rendering;
  7. using UnityEngine.Rendering.Universal;
  8. namespace VolumetricFogAndMist2 {
  9. public partial class VolumetricFog : MonoBehaviour {
  10. const string SURFACE_CAM_NAME = "SurfaceCam";
  11. public enum HeightmapCaptureResolution {
  12. _64 = 64,
  13. _128 = 128,
  14. _256 = 256,
  15. _512 = 512,
  16. _1024 = 1024
  17. }
  18. RenderTexture rt;
  19. Camera surfaceCam;
  20. Matrix4x4 camMatrix;
  21. Vector3 lastCamPos;
  22. LayerMask lastTerrainLayerMask;
  23. void DisposeSurfaceCapture() {
  24. if (rt != null) {
  25. rt.Release();
  26. DestroyImmediate(rt);
  27. }
  28. }
  29. void CheckSurfaceCapture() {
  30. if (surfaceCam == null) {
  31. Transform childCam = transform.Find(SURFACE_CAM_NAME);
  32. if (childCam != null) {
  33. surfaceCam = childCam.GetComponent<Camera>();
  34. if (surfaceCam == null) {
  35. DestroyImmediate(childCam.gameObject);
  36. }
  37. }
  38. }
  39. }
  40. void SurfaceCaptureSupportCheck() {
  41. if (!activeProfile.terrainFit) {
  42. DisposeSurfaceCapture();
  43. return;
  44. }
  45. Transform childCam = null;
  46. if (surfaceCam == null) {
  47. childCam = transform.Find(SURFACE_CAM_NAME);
  48. if (childCam != null) {
  49. surfaceCam = childCam.GetComponent<Camera>();
  50. }
  51. }
  52. bool needsSurfaceCapture = forceTerrainCaptureUpdate;
  53. if (surfaceCam == null) {
  54. if (childCam != null) {
  55. DestroyImmediate(childCam.gameObject);
  56. }
  57. if (surfaceCam == null) {
  58. GameObject camObj = new GameObject(SURFACE_CAM_NAME, typeof(Camera));
  59. camObj.transform.SetParent(transform, false);
  60. surfaceCam = camObj.GetComponent<Camera>();
  61. surfaceCam.depthTextureMode = DepthTextureMode.None;
  62. surfaceCam.clearFlags = CameraClearFlags.Depth;
  63. surfaceCam.allowHDR = false;
  64. surfaceCam.allowMSAA = false;
  65. }
  66. needsSurfaceCapture = true;
  67. surfaceCam.stereoTargetEye = StereoTargetEyeMask.None;
  68. surfaceCam.orthographic = true;
  69. surfaceCam.nearClipPlane = 1f;
  70. }
  71. surfaceCam.enabled = false;
  72. if (rt != null && rt.width != (int)activeProfile.terrainFitResolution) {
  73. if (surfaceCam.targetTexture == rt) {
  74. surfaceCam.targetTexture = null;
  75. }
  76. rt.Release();
  77. DestroyImmediate(rt);
  78. }
  79. if (rt == null) {
  80. rt = new RenderTexture((int)activeProfile.terrainFitResolution, (int)activeProfile.terrainFitResolution, 24, RenderTextureFormat.Depth);
  81. rt.antiAliasing = 1;
  82. needsSurfaceCapture = true;
  83. }
  84. int thisLayer = 1 << gameObject.layer;
  85. if ((activeProfile.terrainLayerMask & thisLayer) != 0) {
  86. activeProfile.terrainLayerMask &= ~thisLayer; // exclude fog layer
  87. }
  88. surfaceCam.cullingMask = activeProfile.terrainLayerMask;
  89. surfaceCam.targetTexture = rt;
  90. if (activeProfile.terrainLayerMask != lastTerrainLayerMask) {
  91. lastTerrainLayerMask = activeProfile.terrainLayerMask;
  92. needsSurfaceCapture = true;
  93. }
  94. if (activeProfile.terrainFit && needsSurfaceCapture) {
  95. // Ensure depth cam only renders depth and is correctly assigned to custom renderer
  96. UniversalAdditionalCameraData camData = surfaceCam.GetComponent<UniversalAdditionalCameraData>();
  97. if (camData == null) {
  98. camData = surfaceCam.gameObject.AddComponent<UniversalAdditionalCameraData>();
  99. }
  100. if (camData != null) {
  101. camData.dithering = false;
  102. camData.renderPostProcessing = false;
  103. camData.renderShadows = false;
  104. camData.requiresColorTexture = false;
  105. camData.requiresDepthTexture = false;
  106. camData.stopNaN = false;
  107. #if UNITY_2021_3_OR_NEWER
  108. CheckAndAssignDepthRenderer(camData);
  109. #endif
  110. }
  111. PerformHeightmapCapture();
  112. }
  113. }
  114. #if UNITY_2021_3_OR_NEWER
  115. UniversalRendererData depthRendererData;
  116. void CheckAndAssignDepthRenderer(UniversalAdditionalCameraData camData) {
  117. UniversalRenderPipelineAsset pipe = (UniversalRenderPipelineAsset)GraphicsSettings.currentRenderPipeline;
  118. if (pipe == null) return;
  119. if (depthRendererData == null) {
  120. depthRendererData = Resources.Load<UniversalRendererData>("Shaders/VolumetricFogDepthRenderer");
  121. if (depthRendererData == null) {
  122. Debug.LogError("Volumetric Fog Depth Renderer asset not found.");
  123. return;
  124. }
  125. depthRendererData.postProcessData = null;
  126. }
  127. int depthRendererIndex = -1;
  128. for (int k = 0; k < pipe.m_RendererDataList.Length; k++) {
  129. if (pipe.m_RendererDataList[k] == depthRendererData) {
  130. depthRendererIndex = k;
  131. break;
  132. }
  133. }
  134. if (depthRendererIndex < 0) {
  135. depthRendererIndex = pipe.m_RendererDataList.Length;
  136. System.Array.Resize<ScriptableRendererData>(ref pipe.m_RendererDataList, depthRendererIndex + 1);
  137. pipe.m_RendererDataList[depthRendererIndex] = depthRendererData;
  138. #if UNITY_EDITOR
  139. UnityEditor.EditorUtility.SetDirty(pipe);
  140. #endif
  141. }
  142. camData.SetRenderer(depthRendererIndex);
  143. }
  144. #endif
  145. /// <summary>
  146. /// Updates terrain heightmap on this volumetric fog
  147. /// </summary>
  148. public void PerformHeightmapCapture() {
  149. if (surfaceCam != null) {
  150. surfaceCam.Render();
  151. surfaceCam.enabled = false;
  152. if (!fogMat.IsKeywordEnabled(ShaderParams.SKW_SURFACE)) {
  153. fogMat.EnableKeyword(ShaderParams.SKW_SURFACE);
  154. }
  155. forceTerrainCaptureUpdate = false;
  156. }
  157. }
  158. void SetupCameraCaptureMatrix() {
  159. Vector3 camPos = transform.position + new Vector3(0, transform.lossyScale.y * 0.51f, 0);
  160. surfaceCam.farClipPlane = 10000;
  161. surfaceCam.transform.position = camPos;
  162. surfaceCam.transform.eulerAngles = new Vector3(90, 0, 0);
  163. Vector3 size = transform.lossyScale;
  164. surfaceCam.orthographicSize = Mathf.Max(size.x * 0.5f, size.z * 0.5f);
  165. ComputeSufaceTransform(surfaceCam.projectionMatrix, surfaceCam.worldToCameraMatrix);
  166. fogMat.SetMatrix(ShaderParams.SurfaceCaptureMatrix, camMatrix);
  167. fogMat.SetTexture(ShaderParams.SurfaceDepthTexture, surfaceCam.targetTexture);
  168. fogMat.SetVector(ShaderParams.SurfaceData, new Vector4(camPos.y, activeProfile.terrainFogHeight, activeProfile.terrainFogMinAltitude, activeProfile.terrainFogMaxAltitude));
  169. }
  170. void SurfaceCaptureUpdate() {
  171. if (surfaceCam == null) return;
  172. SetupCameraCaptureMatrix();
  173. if (!surfaceCam.enabled && lastCamPos != surfaceCam.transform.position) {
  174. lastCamPos = surfaceCam.transform.position;
  175. PerformHeightmapCapture();
  176. requireUpdateMaterial = true;
  177. }
  178. }
  179. static Matrix4x4 identityMatrix = Matrix4x4.identity;
  180. void ComputeSufaceTransform(Matrix4x4 proj, Matrix4x4 view) {
  181. // Currently CullResults ComputeDirectionalShadowMatricesAndCullingPrimitives doesn't
  182. // apply z reversal to projection matrix. We need to do it manually here.
  183. if (SystemInfo.usesReversedZBuffer) {
  184. proj.m20 = -proj.m20;
  185. proj.m21 = -proj.m21;
  186. proj.m22 = -proj.m22;
  187. proj.m23 = -proj.m23;
  188. }
  189. Matrix4x4 worldToShadow = proj * view;
  190. var textureScaleAndBias = identityMatrix;
  191. textureScaleAndBias.m00 = 0.5f;
  192. textureScaleAndBias.m11 = 0.5f;
  193. textureScaleAndBias.m22 = 0.5f;
  194. textureScaleAndBias.m03 = 0.5f;
  195. textureScaleAndBias.m23 = 0.5f;
  196. textureScaleAndBias.m13 = 0.5f;
  197. // Apply texture scale and offset to save a MAD in shader.
  198. camMatrix = textureScaleAndBias * worldToShadow;
  199. }
  200. }
  201. }