using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Runtime.InteropServices; using System; using UnityEngine.Rendering; namespace Enviro { [Serializable] public class EnviroFogSettings { /// Volumetrics Settings public bool volumetrics = true; public enum Quality { Low, Medium, High } public int steps = 32; public Quality quality; [Range(0f,2f)] public float scattering; public AnimationCurve scatteringMultiplier = new AnimationCurve(new Keyframe(0, 1), new Keyframe(1, 1)); [Range(0f,1f)] public float extinction; [Range(0f,1f)] public float anistropy; public float maxRange = 1000f; public float maxRangePointSpot = 100f; [Range(0f,1f)] public float noiseIntensity; [Range(0f,0.01f)] public float noiseScale; public Vector3 windDirection; public Texture3D noise; public Texture2D ditheringTex; //Height Fog Settings public bool fog = true; public enum FogQualityMode { Normal, Simple } public FogQualityMode fogQualityMode; public Vector3 floatingPointOriginMod; public float globalFogHeight = 0f; [Range(0.0f,1f)] public float fogDensity = 0.02f; // This is the global density factor, which can be thought of as the fog layer's thickness. [Range(0.001f, 0.1f)] public float fogHeightFalloff = 0.2f; // Height density factor, controls how the density increases as height decreases. Smaller values make the transition larger. public float fogHeight = 0.0f; [Range(0.0f, 1f)] public float fogDensity2 = 0.02f; [Range(0.001f, 0.1f)] public float fogHeightFalloff2 = 0.2f; public float fogHeight2; [Range(0.0f,1.0f)] public float fogMaxOpacity = 1.0f; [Range(0.01f,5000.0f)] public float startDistance = 0.0f; [Range(0.0f,1.0f)] public float fogColorBlend = 0.5f; public Color fogColorMod = Color.white; public bool blockScattering = false; [GradientUsage(true)] public Gradient ambientColorGradient; #if ENVIRO_HDRP //HDRP Fog public bool controlHDRPFog; public float fogAttenuationDistance = 400f; public float baseHeight = 0f; public float maxHeight = 50f; [GradientUsage(true)] public Gradient fogColorTint; //HDRP Volumetrics public bool controlHDRPVolumetrics; [GradientUsage(true)] public Gradient volumetricsColorTint; [Range(0f,1f)] public float ambientDimmer = 1f; [Range(0f,10f)] public float directLightMultiplier = 1f; [Range(0f,1f)] public float directLightShadowdimmer = 1f; #endif //Unity Fog public bool unityFog = false; public FogMode unityFogMode = FogMode.Exponential; public float unityFogDensity = 0.002f; public float unityFogStartDistance = 0f; public float unityFogEndDistance = 1000f; [GradientUsage(true)] public Gradient unityFogColor = new Gradient(); } [Serializable] public class EnviroFogModule : EnviroModule { //Settings public EnviroFogSettings Settings; public EnviroFogModule preset; public bool showFogControls; public bool showVolumetricsControls; #if ENVIRO_HDRP public bool showHDRPFogControls; #endif public bool showUnityFogControls; //Fog Zones and Lights public List fogLights = new List(); private Light myLight; public float customFogDensityModifer = 1f; //Materials public Material fogMat; public Material volumetricsMat; public Material blurMat; public Material blurMat2; // Textures public RenderTexture volumetricsRenderTexture; #if ENVIRO_URP && UNITY_6000_0_OR_NEWER public UnityEngine.Rendering.RenderGraphModule.TextureHandle volumetricsRenderTextureHandle; public UnityEngine.Rendering.RTHandle volumetricsRenderTextureRT; Material blitThroughMat; #endif //Point Lights struct PointLightParams { public Vector3 pos; public float range; public Vector3 color; float padding; } PointLightParams[] m_PointLightParams; ComputeBuffer m_PointLightParamsCB; //Spot Lights struct SpotLightParams { public Vector3 pos; public float range; public Vector3 color; public Vector3 lightDirection; public float lightCosHalfAngle; float padding; } SpotLightParams[] m_SpotLightParams; ComputeBuffer m_SpotLightParamsCB; #if ENVIRO_HDRP public UnityEngine.Rendering.HighDefinition.Fog fogHDRP; #endif private EnviroVolumetricFogLight directionaLight; private EnviroVolumetricFogLight additionalLight; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Update Functions ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override void Enable() { if(EnviroManager.instance == null) return; #if !ENVIRO_HDRP if(EnviroManager.instance.Objects.directionalLight != null) { if(EnviroManager.instance.Objects.directionalLight.gameObject.GetComponent() == null) directionaLight = EnviroManager.instance.Objects.directionalLight.gameObject.AddComponent(); } if(EnviroManager.instance.Objects.additionalDirectionalLight != null) { if(EnviroManager.instance.Objects.additionalDirectionalLight.gameObject.GetComponent() == null) additionalLight = EnviroManager.instance.Objects.additionalDirectionalLight.gameObject.AddComponent(); } #endif } public override void Disable() { if(EnviroManager.instance == null) return; CleanupHeightFog(); CleanupVolumetrics(); if(EnviroManager.instance.Objects.directionalLight != null) { if(EnviroManager.instance.Objects.directionalLight.gameObject.GetComponent() != null) DestroyImmediate(EnviroManager.instance.Objects.directionalLight.gameObject.GetComponent()); } if(EnviroManager.instance.Objects.additionalDirectionalLight != null) { if(EnviroManager.instance.Objects.additionalDirectionalLight.gameObject.GetComponent() != null) DestroyImmediate(EnviroManager.instance.Objects.additionalDirectionalLight.gameObject.GetComponent()); } } // Update Method public override void UpdateModule () { if(!active) return; if(EnviroManager.instance == null) return; #if ENVIRO_HDRP UpdateFogHDRP (); #else UpdateUnityFog (); #endif if(additionalLight != null && directionaLight != null) { if(EnviroManager.instance.isNight) { additionalLight.enabled = true; directionaLight.enabled = false; } else { directionaLight.enabled = true; additionalLight.enabled = false; } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Public general functions ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public bool AddLight (EnviroVolumetricFogLight light) { fogLights.Add(light); return true; } public void RemoveLight (EnviroVolumetricFogLight light) { if(fogLights.Contains(light)) fogLights.Remove(light); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// HDRP ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if ENVIRO_HDRP private void UpdateFogHDRP () { if(EnviroManager.instance.volumeHDRP != null && EnviroManager.instance.volumeProfileHDRP != null) { if(fogHDRP == null) { UnityEngine.Rendering.HighDefinition.Fog TempFog; if (EnviroManager.instance.volumeProfileHDRP.TryGet(out TempFog)) { fogHDRP = TempFog; } else { EnviroManager.instance.volumeProfileHDRP.Add(); if (EnviroManager.instance.volumeProfileHDRP.TryGet(out TempFog)) { fogHDRP = TempFog; } } } else { if(Settings.controlHDRPFog) { fogHDRP.active = true; fogHDRP.enabled.overrideState = true; fogHDRP.enabled.value = Settings.controlHDRPFog; fogHDRP.meanFreePath.overrideState = true; fogHDRP.meanFreePath.value = Settings.fogAttenuationDistance; fogHDRP.baseHeight.overrideState = true; fogHDRP.baseHeight.value = Settings.baseHeight; fogHDRP.maximumHeight.overrideState = true; fogHDRP.maximumHeight.value = Settings.maxHeight; fogHDRP.tint.overrideState = true; fogHDRP.tint.value = Settings.fogColorTint.Evaluate(EnviroManager.instance.solarTime); } else { fogHDRP.active = false; } if(Settings.controlHDRPVolumetrics) { fogHDRP.enableVolumetricFog.overrideState = true; fogHDRP.enableVolumetricFog.value = true; fogHDRP.albedo.overrideState = true; fogHDRP.albedo.value = Settings.volumetricsColorTint.Evaluate(EnviroManager.instance.solarTime); fogHDRP.globalLightProbeDimmer.overrideState = true; fogHDRP.globalLightProbeDimmer.value = Settings.ambientDimmer; if(EnviroManager.instance.Lighting != null && EnviroManager.instance.Lighting.directionalLightHDRP != null) { EnviroManager.instance.Lighting.directionalLightHDRP.volumetricDimmer = Settings.directLightMultiplier; EnviroManager.instance.Lighting.directionalLightHDRP.volumetricShadowDimmer = Settings.directLightShadowdimmer; } if(EnviroManager.instance.Lighting != null && EnviroManager.instance.Lighting.additionalLightHDRP != null) { EnviroManager.instance.Lighting.additionalLightHDRP.volumetricDimmer = Settings.directLightMultiplier; EnviroManager.instance.Lighting.additionalLightHDRP.volumetricShadowDimmer = Settings.directLightShadowdimmer; } } else { fogHDRP.enableVolumetricFog.value = false; } } } } #endif private void UpdateUnityFog () { RenderSettings.fog = Settings.unityFog; RenderSettings.fogMode = Settings.unityFogMode; if(Settings.unityFogMode == FogMode.Linear) { RenderSettings.fogStartDistance = Settings.unityFogStartDistance; RenderSettings.fogEndDistance = Settings.unityFogEndDistance; } else { RenderSettings.fogDensity = Settings.unityFogDensity; } RenderSettings.fogColor = Settings.unityFogColor.Evaluate(EnviroManager.instance.solarTime) * (Settings.fogColorMod * EnviroManager.instance.solarTime); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Height Fog ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void UpdateFogShader (Camera cam) { if(Settings.fogQualityMode == EnviroFogSettings.FogQualityMode.Simple) { Shader.EnableKeyword("ENVIRO_SIMPLEFOG"); Shader.SetGlobalVector("_EnviroFogParameters", new Vector4(0f, Settings.fogHeightFalloff, Settings.fogDensity * 0.01f * customFogDensityModifer, Settings.fogHeight + Settings.globalFogHeight)); } else { Shader.DisableKeyword("ENVIRO_SIMPLEFOG"); Shader.SetGlobalVector("_EnviroFogParameters", new Vector4(0f, Settings.fogHeightFalloff, Settings.fogDensity * 0.01f * customFogDensityModifer, Settings.fogHeight + Settings.globalFogHeight)); Shader.SetGlobalVector("_EnviroFogParameters2", new Vector4(0f, Settings.fogHeightFalloff2, Settings.fogDensity2 * 0.01f * customFogDensityModifer, Settings.fogHeight2 + Settings.globalFogHeight)); } Shader.SetGlobalVector("_EnviroFogParameters3",new Vector4(1.0f - Settings.fogMaxOpacity,Settings.startDistance,Settings.blockScattering ? 0f : 1f,Settings.fogColorBlend)); Shader.SetGlobalColor("_EnviroFogColor", Settings.ambientColorGradient.Evaluate(EnviroManager.instance.solarTime) * (Settings.fogColorMod * EnviroManager.instance.solarTime)); if (EnviroManager.instance.Objects.worldAnchor != null) Settings.floatingPointOriginMod = EnviroManager.instance.Objects.worldAnchor.transform.position; else Settings.floatingPointOriginMod = Vector3.zero; Shader.SetGlobalVector("_EnviroCameraPos",cam.transform.position - Settings.floatingPointOriginMod); Shader.SetGlobalVector("_EnviroWorldOffset",Settings.floatingPointOriginMod); } public void RenderHeightFog(Camera cam, RenderTexture source, RenderTexture destination) { UnityEngine.Profiling.Profiler.BeginSample("Enviro Fog Rendering"); if(fogMat == null) fogMat = new Material(Shader.Find("Hidden/EnviroHeightFog")); UpdateFogShader(cam); fogMat.SetTexture("_MainTex",source); Graphics.Blit(source, destination, fogMat); UnityEngine.Profiling.Profiler.EndSample(); } #if ENVIRO_URP #if UNITY_6000_0_OR_NEWER public void RenderHeightFogURP(EnviroURPRenderGraph renderer, UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.Universal.UniversalResourceData resourceData, UnityEngine.Rendering.Universal.UniversalCameraData cameraData, UnityEngine.Rendering.RenderGraphModule.TextureHandle src, UnityEngine.Rendering.RenderGraphModule.TextureHandle target) { if(fogMat == null) fogMat = new Material(Shader.Find("Hidden/EnviroHeightFogURP")); UpdateFogShader(cameraData.camera); fogMat.EnableKeyword("ENVIROURP"); if(volumetricsRenderTextureHandle.IsValid()) { renderer.Blit("Fog", renderGraph, fogMat, src, target, 0, volumetricsRenderTextureHandle,"_EnviroVolumetricFogTex"); } else { renderer.Blit("Fog", renderGraph, fogMat, src, target, 0); } } #endif public void RenderHeightFogURP(Camera cam,EnviroURPRenderPass pass,UnityEngine.Rendering.CommandBuffer cmd, RenderTexture source, UnityEngine.Rendering.RenderTargetIdentifier destination) { if(fogMat == null) fogMat = new Material(Shader.Find("Hidden/EnviroHeightFog")); UpdateFogShader(cam); fogMat.EnableKeyword("ENVIROURP"); pass.CustomBlit(cmd,cam.cameraToWorldMatrix,source,destination,fogMat); } #endif #if ENVIRO_HDRP public void RenderHeightFogHDRP(Camera cam,UnityEngine.Rendering.CommandBuffer cmd, UnityEngine.Rendering.RTHandle source, UnityEngine.Rendering.RTHandle destination) { if(fogMat == null) fogMat = new Material(Shader.Find("Hidden/EnviroHeightFogHDRP")); UpdateFogShader(cam); fogMat.SetTexture("_MainTex",source); cmd.Blit(source, destination, fogMat); } #endif private void CleanupHeightFog() { if(EnviroManager.instance == null) return; if(fogMat != null) DestroyImmediate(fogMat); if(EnviroManager.instance.removeZoneParamsCB != null) EnviroHelper.ReleaseComputeBuffer(ref EnviroManager.instance.removeZoneParamsCB); if(EnviroManager.instance.clearZoneCB != null) EnviroHelper.ReleaseComputeBuffer(ref EnviroManager.instance.clearZoneCB); if(EnviroManager.instance.clearCBPoint != null) EnviroHelper.ReleaseComputeBuffer(ref EnviroManager.instance.clearCBPoint); if(EnviroManager.instance.clearCBSpot != null) EnviroHelper.ReleaseComputeBuffer(ref EnviroManager.instance.clearCBSpot); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Volumetrics ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void RenderVolumetrics(Camera camera, RenderTexture source) { UnityEngine.Profiling.Profiler.BeginSample("Enviro Volumetrics Rendering"); if(Settings.volumetrics == false || camera.cameraType == CameraType.Reflection) { Shader.DisableKeyword("ENVIRO_VOLUMELIGHT"); return; } else { Shader.EnableKeyword("ENVIRO_VOLUMELIGHT"); } if(volumetricsMat == null) volumetricsMat = new Material(Shader.Find("Hidden/Volumetrics")); if(blurMat == null) blurMat = new Material(Shader.Find("Hidden/EnviroBlur")); CreateVolumetricsBuffers(); SetUpPointLightBuffers(); SetUpSpotLightBuffers(); UpdateVolumetricsShader(volumetricsMat); //if(cloudsTex != null) // volumetricsMat.SetTexture("_CloudsTex", cloudsTex); RenderTextureDescriptor desc = source.descriptor; desc.msaaSamples = 1; if(volumetricsRenderTexture == null || volumetricsRenderTexture.width != desc.width || volumetricsRenderTexture.height != desc.height) { if(volumetricsRenderTexture != null) DestroyImmediate(volumetricsRenderTexture); volumetricsRenderTexture = new RenderTexture(desc); } if(Settings.quality == EnviroFogSettings.Quality.High) { RenderTexture target = RenderTexture.GetTemporary(desc); volumetricsMat.SetTexture("_MainTex",source); Graphics.Blit(source,target,volumetricsMat); RenderTexture temp = RenderTexture.GetTemporary(desc); // horizontal bilateral blur at full res blurMat.SetTexture("_MainTex",target); Graphics.Blit(target, temp, blurMat, 0); // vertical bilateral blur at full res blurMat.SetTexture("_MainTex",temp); Graphics.Blit(temp, target, blurMat, 1); Graphics.Blit(target, volumetricsRenderTexture); RenderTexture.ReleaseTemporary(temp); RenderTexture.ReleaseTemporary(target); } else if(Settings.quality == EnviroFogSettings.Quality.Medium) { desc.width = source.width / 2; desc.height = source.height / 2; RenderTexture target = RenderTexture.GetTemporary(desc); RenderTexture depth = RenderTexture.GetTemporary(desc); depth.filterMode = FilterMode.Point; volumetricsMat.SetTexture("_MainTex",source); Graphics.Blit(source,target,volumetricsMat); blurMat.SetTexture("_MainTex",source); Graphics.Blit(source, depth, blurMat, 4); blurMat.SetTexture("_HalfResDepthBuffer", depth); blurMat.SetTexture("_HalfResColor", target); RenderTexture temp = RenderTexture.GetTemporary(desc); // horizontal bilateral blur at half res blurMat.SetTexture("_MainTex",target); Graphics.Blit(target, temp, blurMat, 2); // vertical bilateral blur at half res blurMat.SetTexture("_MainTex",temp); Graphics.Blit(temp, target, blurMat, 3); // upscale to full res blurMat.SetTexture("_MainTex",target); Graphics.Blit(target, volumetricsRenderTexture, blurMat, 5); RenderTexture.ReleaseTemporary(temp); RenderTexture.ReleaseTemporary(target); RenderTexture.ReleaseTemporary(depth); } else if (Settings.quality == EnviroFogSettings.Quality.Low) { desc.width = source.width / 2; desc.height = source.height / 2; RenderTexture depthHalf = RenderTexture.GetTemporary(desc); depthHalf.filterMode = FilterMode.Point; desc.width = source.width / 4; desc.height = source.height / 4; RenderTexture target = RenderTexture.GetTemporary(desc); RenderTexture depthQuarter = RenderTexture.GetTemporary(desc); depthQuarter.filterMode = FilterMode.Point; volumetricsMat.SetTexture("_MainTex",source); Graphics.Blit(source,target,volumetricsMat); blurMat.SetTexture("_MainTex",source); Graphics.Blit(source, depthHalf, blurMat,4); Graphics.Blit(source, depthQuarter, blurMat,6); blurMat.SetTexture("_HalfResDepthBuffer", depthHalf); blurMat.SetTexture("_QuarterResDepthBuffer", depthQuarter); //blurMat.SetTexture("_HalfResColor", target); blurMat.SetTexture("_QuarterResColor", target); RenderTexture temp = RenderTexture.GetTemporary(desc); // horizontal bilateral blur at half res blurMat.SetTexture("_MainTex",target); Graphics.Blit(target, temp, blurMat, 8); // vertical bilateral blur at half res blurMat.SetTexture("_MainTex",temp); Graphics.Blit(temp, target, blurMat, 9); // upscale to full res blurMat.SetTexture("_MainTex",target); Graphics.Blit(target, volumetricsRenderTexture, blurMat, 7); RenderTexture.ReleaseTemporary(temp); RenderTexture.ReleaseTemporary(target); RenderTexture.ReleaseTemporary(depthHalf); RenderTexture.ReleaseTemporary(depthQuarter); } Shader.SetGlobalTexture("_EnviroVolumetricFogTex", volumetricsRenderTexture); UnityEngine.Profiling.Profiler.EndSample(); } #if ENVIRO_URP public void RenderVolumetricsURP(Camera camera, EnviroURPRenderPass pass, UnityEngine.Rendering.CommandBuffer cmd, RenderTexture source) { if(Settings.volumetrics == false || camera.cameraType == CameraType.Reflection) { Shader.DisableKeyword("ENVIRO_VOLUMELIGHT"); return; } else { Shader.EnableKeyword("ENVIRO_VOLUMELIGHT"); } //Shader.EnableKeyword("ENVIRO_VOLUMELIGHT"); if(volumetricsMat == null) volumetricsMat = new Material(Shader.Find("Hidden/VolumetricsURP")); if(blurMat == null) blurMat = new Material(Shader.Find("Hidden/EnviroBlur")); CreateVolumetricsBuffers(); SetUpPointLightBuffers(); SetUpSpotLightBuffers(); UpdateVolumetricsShader(volumetricsMat); volumetricsMat.EnableKeyword("ENVIROURP"); blurMat.EnableKeyword("ENVIROURP"); RenderTextureDescriptor desc = source.descriptor; desc.colorFormat = RenderTextureFormat.ARGBHalf; desc.msaaSamples = 1; desc.depthBufferBits = 0; if(volumetricsRenderTexture == null || volumetricsRenderTexture.width != desc.width || volumetricsRenderTexture.height != desc.height) { if(volumetricsRenderTexture != null) DestroyImmediate(volumetricsRenderTexture); volumetricsRenderTexture = new RenderTexture(desc); } if(Settings.quality == EnviroFogSettings.Quality.High) { RenderTexture target = RenderTexture.GetTemporary(desc); pass.CustomBlit(cmd,camera.cameraToWorldMatrix,source,target,volumetricsMat); RenderTexture temp = RenderTexture.GetTemporary(desc); // horizontal bilateral blur at full res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,target,temp,blurMat,0); // vertical bilateral blur at full res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,temp,target,blurMat,1); //Graphics.Blit(target, volumetricsRenderTexture); pass.CustomBlit(cmd,camera.cameraToWorldMatrix,target,volumetricsRenderTexture); RenderTexture.ReleaseTemporary(temp); RenderTexture.ReleaseTemporary(target); } else if(Settings.quality == EnviroFogSettings.Quality.Medium) { desc.width = source.width / 2; desc.height = source.height / 2; RenderTexture target = RenderTexture.GetTemporary(desc); RenderTexture depth = RenderTexture.GetTemporary(desc); depth.filterMode = FilterMode.Point; pass.CustomBlit(cmd,camera.cameraToWorldMatrix,source,target,volumetricsMat); pass.CustomBlit(cmd,camera.cameraToWorldMatrix,source,depth,blurMat,4); blurMat.SetTexture("_HalfResDepthBuffer", depth); blurMat.SetTexture("_HalfResColor", target); RenderTexture temp = RenderTexture.GetTemporary(desc); // horizontal bilateral blur at half res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,target,temp,blurMat,2); // vertical bilateral blur at half res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,temp,target,blurMat,3); // upscale to full res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,target,volumetricsRenderTexture,blurMat,5); RenderTexture.ReleaseTemporary(temp); RenderTexture.ReleaseTemporary(target); RenderTexture.ReleaseTemporary(depth); } else if (Settings.quality == EnviroFogSettings.Quality.Low) { desc.width = source.width / 2; desc.height = source.height / 2; RenderTexture depthHalf = RenderTexture.GetTemporary(desc); depthHalf.filterMode = FilterMode.Point; desc.width = source.width / 4; desc.height = source.height / 4; RenderTexture target = RenderTexture.GetTemporary(desc); RenderTexture depthQuarter = RenderTexture.GetTemporary(desc); depthQuarter.filterMode = FilterMode.Point; pass.CustomBlit(cmd,camera.cameraToWorldMatrix,source,target,volumetricsMat); pass.CustomBlit(cmd,camera.cameraToWorldMatrix,source,depthHalf,blurMat,4); pass.CustomBlit(cmd,camera.cameraToWorldMatrix,source,depthQuarter,blurMat,6); blurMat.SetTexture("_HalfResDepthBuffer", depthHalf); blurMat.SetTexture("_QuarterResDepthBuffer", depthQuarter); //blurMat.SetTexture("_HalfResColor", target); blurMat.SetTexture("_QuarterResColor", target); RenderTexture temp = RenderTexture.GetTemporary(desc); // horizontal bilateral blur at half res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,target,temp,blurMat,8); // vertical bilateral blur at half res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,temp,target,blurMat,9); // upscale to full res pass.CustomBlit(cmd,camera.cameraToWorldMatrix,target,volumetricsRenderTexture,blurMat,7); RenderTexture.ReleaseTemporary(temp); RenderTexture.ReleaseTemporary(target); RenderTexture.ReleaseTemporary(depthHalf); RenderTexture.ReleaseTemporary(depthQuarter); } Shader.SetGlobalTexture("_EnviroVolumetricFogTex", volumetricsRenderTexture); } #if UNITY_6000_0_OR_NEWER //URP New Render Graph public void RenderVolumetricsURP(EnviroURPRenderGraph renderer, UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.Universal.UniversalResourceData resourceData, UnityEngine.Rendering.Universal.UniversalCameraData cameraData, UnityEngine.Rendering.RenderGraphModule.TextureHandle src) { if(Settings.volumetrics == false || cameraData.cameraType == CameraType.Reflection) { Shader.DisableKeyword("ENVIRO_VOLUMELIGHT"); return; } else { Shader.EnableKeyword("ENVIRO_VOLUMELIGHT"); } if(volumetricsMat == null) volumetricsMat = new Material(Shader.Find("Hidden/VolumetricsURP")); volumetricsMat.EnableKeyword("ENVIROURP17"); if(blurMat == null) blurMat = new Material(Shader.Find("Hidden/EnviroBlurURP")); if(blurMat2 == null) blurMat2 = new Material(Shader.Find("Hidden/EnviroBlurURP")); CreateVolumetricsBuffers(); SetUpPointLightBuffers(); SetUpSpotLightBuffers(); UpdateVolumetricsShader(volumetricsMat); volumetricsMat.EnableKeyword("ENVIROURP"); blurMat.EnableKeyword("ENVIROURP17"); blurMat2.EnableKeyword("ENVIROURP17"); //if(cloudsTex != null) // volumetricsMat.SetTexture("_CloudsTex", cloudsTex); UnityEngine.Rendering.RenderGraphModule.TextureDesc desc = src.GetDescriptor(renderGraph); desc.colorFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R16G16B16A16_SFloat; desc.msaaSamples = UnityEngine.Rendering.MSAASamples.None; desc.depthBufferBits = 0; RenderTextureDescriptor renderTextureDescriptor = new RenderTextureDescriptor(desc.width,desc.height,RenderTextureFormat.ARGBHalf,0); renderTextureDescriptor.dimension = desc.dimension; renderTextureDescriptor.volumeDepth = desc.slices; UnityEngine.Rendering.Universal.RenderingUtils.ReAllocateHandleIfNeeded(ref volumetricsRenderTextureRT, renderTextureDescriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "Enviro Volumetrics Mask" ); //volumetricsRenderTextureHandle = renderGraph.CreateTexture(desc); volumetricsRenderTextureHandle = renderGraph.ImportTexture(volumetricsRenderTextureRT); if(Settings.quality == EnviroFogSettings.Quality.High) { UnityEngine.Rendering.RenderGraphModule.TextureHandle target = renderGraph.CreateTexture(desc); renderer.Blit("Render Volumetrics Mask", renderGraph,volumetricsMat,src,target,0); UnityEngine.Rendering.RenderGraphModule.TextureHandle temp = renderGraph.CreateTexture(desc); // We somehow need two materials otherwise it does not set the correct main tex. Must be rendergraph bug?! renderer.Blit("Horizontal Blur", renderGraph,blurMat,target,temp,0); renderer.Blit("Vertical Blur", renderGraph,blurMat2,temp,target,1); if(blitThroughMat == null) blitThroughMat = new Material(Shader.Find("Hidden/EnviroBlitThroughURP17")); renderer.Blit("Volumetrics Final Blit", renderGraph,blitThroughMat,target,volumetricsRenderTextureHandle,0); } else if(Settings.quality == EnviroFogSettings.Quality.Medium) { desc.width = src.GetDescriptor(renderGraph).width / 2; desc.height = src.GetDescriptor(renderGraph).height / 2; UnityEngine.Rendering.RenderGraphModule.TextureHandle target = renderGraph.CreateTexture(desc); UnityEngine.Rendering.RenderGraphModule.TextureDesc descPointFilter = desc; descPointFilter.filterMode = FilterMode.Point; descPointFilter.colorFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat; UnityEngine.Rendering.RenderGraphModule.TextureHandle depth = renderGraph.CreateTexture(descPointFilter); renderer.Blit("Render Volumetrics Mask", renderGraph,volumetricsMat,src,target,0); renderer.Blit("depth blur",renderGraph,blurMat,src,depth,4); UnityEngine.Rendering.RenderGraphModule.TextureHandle temp = renderGraph.CreateTexture(desc); // horizontal bilateral blur at half res renderer.Blit("horizontal bilateral blur", renderGraph,blurMat,target,temp,2, depth, "_HalfResDepthBuffer");//, target , "_HalfResColor"); // vertical bilateral blur at half res renderer.Blit("vertical bilateral blur", renderGraph,blurMat2,temp,target,3, depth,"_HalfResDepthBuffer");//, target , "_HalfResColor"); // upscale to full res renderer.Blit("upscale", renderGraph,blurMat,target,volumetricsRenderTextureHandle,5, depth,"_HalfResDepthBuffer", target, "_HalfResColor");//, target , "_HalfResColor"); } else if (Settings.quality == EnviroFogSettings.Quality.Low) { desc.width = src.GetDescriptor(renderGraph).width / 2; desc.height = src.GetDescriptor(renderGraph).height / 2; UnityEngine.Rendering.RenderGraphModule.TextureDesc depthHalfdesc = desc; depthHalfdesc.colorFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat; depthHalfdesc.filterMode = FilterMode.Point; UnityEngine.Rendering.RenderGraphModule.TextureHandle depthHalf = renderGraph.CreateTexture(depthHalfdesc); desc.width = src.GetDescriptor(renderGraph).width / 4; desc.height = src.GetDescriptor(renderGraph).height / 4; UnityEngine.Rendering.RenderGraphModule.TextureHandle target = renderGraph.CreateTexture(desc); UnityEngine.Rendering.RenderGraphModule.TextureDesc depthQuarterdesc = desc; depthQuarterdesc.colorFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat; depthQuarterdesc.filterMode = FilterMode.Point; UnityEngine.Rendering.RenderGraphModule.TextureHandle depthQuarter = renderGraph.CreateTexture(depthQuarterdesc); renderer.Blit("Render Volumetrics Mask", renderGraph,volumetricsMat,src,target,0); renderer.Blit("depth blur", renderGraph,blurMat,src,depthHalf,4); renderer.Blit("depth blur", renderGraph,blurMat,src,depthQuarter,6, depthHalf, "_HalfResDepthBuffer"); UnityEngine.Rendering.RenderGraphModule.TextureHandle temp = renderGraph.CreateTexture(desc); // horizontal bilateral blur at half res renderer.Blit("horizontal bilateral blur", renderGraph,blurMat,target,temp,8,depthQuarter, "_QuarterResDepthBuffer", target , "_QuarterResColor"); // vertical bilateral blur at half res renderer.Blit("horizontal bilateral blur", renderGraph,blurMat2,temp,target,9,depthQuarter, "_QuarterResDepthBuffer"); // upscale to full res renderer.Blit("upscale", renderGraph,blurMat,target,volumetricsRenderTextureHandle,7,depthQuarter,"_QuarterResDepthBuffer", target , "_QuarterResColor"); } if(Settings.volumetrics == true || cameraData.cameraType != CameraType.Reflection && volumetricsRenderTextureRT != null) { Shader.SetGlobalTexture("_EnviroVolumetricFogTex", volumetricsRenderTextureRT); } } #endif #endif private void UpdateVolumetricsShader(Material mat) { if(EnviroManager.instance.Lighting != null) { myLight = EnviroHelper.GetDirectionalLight(); } else { if(myLight == null) myLight = EnviroHelper.GetDirectionalLight(); } mat.SetInt("_Steps", Settings.steps); if(myLight == null) { mat.SetVector("_DirLightDir", new Vector4(0f, 0f, 0f, 1.0f / 2.0f)); Shader.SetGlobalColor("_EnviroDirLightColor", Color.white * 1.0f); } else { mat.SetVector("_DirLightDir", new Vector4(myLight.transform.forward.x, myLight.transform.forward.y, myLight.transform.forward.z, 1.0f / (myLight.range * myLight.range))); Shader.SetGlobalColor("_EnviroDirLightColor", myLight.color * myLight.intensity); } mat.SetFloat("_MaxRayLength", Settings.maxRange); mat.SetFloat("_MaxRayLengthLights", Settings.maxRangePointSpot); mat.SetVector("_WindDirection", new Vector4(Settings.windDirection.x, Settings.windDirection.y,Settings.windDirection.z)); mat.SetVector("_NoiseData", new Vector4(Settings.noiseScale, Settings.noiseIntensity)); mat.SetVector("_MieG", new Vector4(Settings.anistropy, 1 + (Settings.anistropy * Settings.anistropy), 2 * Settings.anistropy, 1.0f / (4.0f * Mathf.PI))); mat.SetVector("_VolumetricLight", new Vector4(Settings.scattering * Settings.scatteringMultiplier.Evaluate(EnviroManager.instance.solarTime), Settings.extinction, 1f, 0f));// - SkyboxExtinctionCoef)); mat.SetTexture("_NoiseTexture",Settings.noise); mat.SetTexture("_DitherTexture",Settings.ditheringTex); mat.SetVector("_Randomness", new Vector4(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value)); } private void CreateVolumetricsBuffers() { int pointLightCount = 0, spotLightCount = 0; for(int i = 0; i < fogLights.Count; i++) { Enviro.EnviroVolumetricFogLight fogLight = fogLights[i]; if (fogLight == null) continue; bool isOn = fogLight.isOn; switch(fogLight.light.type) { case LightType.Point: if (isOn) pointLightCount++; break; case LightType.Spot: if (isOn) spotLightCount++; break; } } EnviroHelper.CreateBuffer(ref m_PointLightParamsCB, pointLightCount, Marshal.SizeOf(typeof(PointLightParams))); EnviroHelper.CreateBuffer(ref m_SpotLightParamsCB, spotLightCount, Marshal.SizeOf(typeof(SpotLightParams))); EnviroHelper.CreateBuffer(ref EnviroManager.instance.clearCBPoint, 1, Marshal.SizeOf(typeof(PointLightParams))); EnviroHelper.CreateBuffer(ref EnviroManager.instance.clearCBSpot, 1, Marshal.SizeOf(typeof(SpotLightParams))); } private void CleanupVolumetrics() { if(volumetricsMat != null) DestroyImmediate(volumetricsMat); if(blurMat != null) DestroyImmediate(blurMat); if(volumetricsRenderTexture != null) DestroyImmediate(volumetricsRenderTexture); EnviroHelper.ReleaseComputeBuffer(ref m_PointLightParamsCB); EnviroHelper.ReleaseComputeBuffer(ref m_SpotLightParamsCB); EnviroHelper.ReleaseComputeBuffer(ref EnviroManager.instance.clearCBSpot); EnviroHelper.ReleaseComputeBuffer(ref EnviroManager.instance.clearCBPoint); } void SetUpPointLightBuffers() { int count = m_PointLightParamsCB == null ? 0 : m_PointLightParamsCB.count; volumetricsMat.SetFloat("_PointLightsCount", count); if (count == 0) { // Can't not set the buffer volumetricsMat.SetBuffer("_PointLights", EnviroManager.instance.clearCBPoint); return; } if (m_PointLightParams == null || m_PointLightParams.Length != count) m_PointLightParams = new PointLightParams[count]; int lightID = 0; for (int i = 0; i < fogLights.Count; i++) { Enviro.EnviroVolumetricFogLight fl = fogLights[i]; if (fl == null || fl.light.type != LightType.Point || !fl.isOn) continue; Light light = fl.light; m_PointLightParams[lightID].pos = light.transform.position; float range = light.range * fl.range; m_PointLightParams[lightID].range = 1.0f / (range * range); m_PointLightParams[lightID].color = new Vector3(light.color.r, light.color.g, light.color.b) * light.intensity * fl.intensity; lightID++; } // TODO: try a constant buffer with setfloats instead for perf m_PointLightParamsCB.SetData(m_PointLightParams); volumetricsMat.SetBuffer("_PointLights", m_PointLightParamsCB); } void SetUpSpotLightBuffers() { int count = m_SpotLightParamsCB == null ? 0 : m_SpotLightParamsCB.count; volumetricsMat.SetFloat("_SpotLightsCount", count); if (count == 0) { // Can't not set the buffer volumetricsMat.SetBuffer("_SpotLights", EnviroManager.instance.clearCBSpot); return; } if (m_SpotLightParams == null || m_SpotLightParams.Length != count) m_SpotLightParams = new SpotLightParams[count]; int lightID = 0; for (int i = 0; i < fogLights.Count; i++) { Enviro.EnviroVolumetricFogLight fl = fogLights[i]; if (fl == null || fl.light.type != LightType.Spot || !fl.isOn) continue; Light light = fl.light; m_SpotLightParams[lightID].pos = light.transform.position; float range = light.range * fl.range; m_SpotLightParams[lightID].range = 1.0f / (range * range); m_SpotLightParams[lightID].color = new Vector3(light.color.r, light.color.g, light.color.b) * light.intensity * fl.intensity; m_SpotLightParams[lightID].lightDirection = light.transform.forward; m_SpotLightParams[lightID].lightCosHalfAngle = Mathf.Cos(light.spotAngle * 0.5f * Mathf.Deg2Rad); lightID++; } m_SpotLightParamsCB.SetData(m_SpotLightParams); volumetricsMat.SetBuffer("_SpotLights", m_SpotLightParamsCB); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Save and Load ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void LoadModuleValues () { if(preset != null) { Settings = JsonUtility.FromJson(JsonUtility.ToJson(preset.Settings)); } else { Debug.Log("Please assign a saved module to load from!"); } } public void SaveModuleValues () { #if UNITY_EDITOR EnviroFogModule t = ScriptableObject.CreateInstance(); t.name = "Fog Module"; t.Settings = JsonUtility.FromJson(JsonUtility.ToJson(Settings)); string assetPathAndName = UnityEditor.AssetDatabase.GenerateUniqueAssetPath(EnviroHelper.assetPath + "/New " + t.name + ".asset"); UnityEditor.AssetDatabase.CreateAsset(t, assetPathAndName); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); #endif } public void SaveModuleValues (EnviroFogModule module) { module.Settings = JsonUtility.FromJson(JsonUtility.ToJson(Settings)); #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(module); UnityEditor.AssetDatabase.SaveAssets(); #endif } } }