using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; /// /// The volumetric fog renderer feature. /// [Tooltip("Adds support to render volumetric fog.")] [DisallowMultipleRendererFeature("Volumetric Fog")] public sealed class VolumetricFogRendererFeature : ScriptableRendererFeature { #region Private Attributes [HideInInspector] [SerializeField] private Shader downsampleDepthShader; [HideInInspector] [SerializeField] private Shader volumetricFogShader; private Material downsampleDepthMaterial; private Material volumetricFogMaterial; private VolumetricFogRenderPass volumetricFogRenderPass; #endregion #region Scriptable Renderer Feature Methods /// /// /// public override void Create() { ValidateResourcesForVolumetricFogRenderPass(true); volumetricFogRenderPass = new VolumetricFogRenderPass(downsampleDepthMaterial, volumetricFogMaterial, VolumetricFogRenderPass.DefaultRenderPassEvent); } /// /// /// /// /// public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { bool isPostProcessEnabled = renderingData.postProcessingEnabled && renderingData.cameraData.postProcessEnabled; bool shouldAddVolumetricFogRenderPass = isPostProcessEnabled && ShouldAddVolumetricFogRenderPass(renderingData.cameraData.cameraType); if (shouldAddVolumetricFogRenderPass) { volumetricFogRenderPass.renderPassEvent = GetRenderPassEvent(); volumetricFogRenderPass.ConfigureInput(ScriptableRenderPassInput.Depth); renderer.EnqueuePass(volumetricFogRenderPass); } } /// /// /// /// protected override void Dispose(bool disposing) { base.Dispose(disposing); volumetricFogRenderPass?.Dispose(); CoreUtils.Destroy(downsampleDepthMaterial); CoreUtils.Destroy(volumetricFogMaterial); } #endregion #region Methods /// /// Validates the resources used by the volumetric fog render pass. /// /// /// private bool ValidateResourcesForVolumetricFogRenderPass(bool forceRefresh) { if (forceRefresh) { #if UNITY_EDITOR downsampleDepthShader = Shader.Find("Hidden/DownsampleDepth"); volumetricFogShader = Shader.Find("Hidden/VolumetricFog"); #endif CoreUtils.Destroy(downsampleDepthMaterial); downsampleDepthMaterial = CoreUtils.CreateEngineMaterial(downsampleDepthShader); CoreUtils.Destroy(volumetricFogMaterial); volumetricFogMaterial = CoreUtils.CreateEngineMaterial(volumetricFogShader); } bool okDepth = downsampleDepthShader != null && downsampleDepthMaterial != null; bool okVolumetric = volumetricFogShader != null && volumetricFogMaterial != null; return okDepth && okVolumetric; } /// /// Gets whether the volumetric fog render pass should be enqueued to the renderer. /// /// /// private bool ShouldAddVolumetricFogRenderPass(CameraType cameraType) { VolumetricFogVolumeComponent fogVolume = VolumeManager.instance.stack.GetComponent(); bool isVolumeOk = fogVolume != null && fogVolume.IsActive(); bool isCameraOk = cameraType != CameraType.Preview && cameraType != CameraType.Reflection; bool areResourcesOk = ValidateResourcesForVolumetricFogRenderPass(false); return isActive && isVolumeOk && isCameraOk && areResourcesOk; } /// /// Returns the render pass event for the volumetric fog. /// /// private RenderPassEvent GetRenderPassEvent() { VolumetricFogVolumeComponent fogVolume = VolumeManager.instance.stack.GetComponent(); return (RenderPassEvent)fogVolume.renderPassEvent.value; } #endregion }