using System; #if UNITY_EDITOR using ShaderKeywordFilter = UnityEditor.ShaderKeywordFilter; #endif namespace UnityEngine.Rendering.Universal { [Serializable] internal class ScreenSpaceAmbientOcclusionSettings { // Parameters [SerializeField] internal AOMethodOptions AOMethod = AOMethodOptions.BlueNoise; [SerializeField] internal bool Downsample = false; [SerializeField] internal bool AfterOpaque = false; [SerializeField] internal DepthSource Source = DepthSource.DepthNormals; [SerializeField] internal NormalQuality NormalSamples = NormalQuality.Medium; [SerializeField] internal float Intensity = 3.0f; [SerializeField] internal float DirectLightingStrength = 0.25f; [SerializeField] internal float Radius = 0.035f; [SerializeField] internal AOSampleOption Samples = AOSampleOption.Medium; [SerializeField] internal BlurQualityOptions BlurQuality = BlurQualityOptions.High; [SerializeField] internal float Falloff = 100f; // Legacy. Kept to migrate users over to use Samples instead. [SerializeField] internal int SampleCount = -1; // Enums internal enum DepthSource { Depth = 0, DepthNormals = 1 } internal enum NormalQuality { Low, Medium, High } internal enum AOSampleOption { High, // 12 Samples Medium, // 8 Samples Low, // 4 Samples } internal enum AOMethodOptions { BlueNoise, InterleavedGradient, } internal enum BlurQualityOptions { High, // Bilateral Medium, // Gaussian Low, // Kawase } } [Serializable] [SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))] [Categorization.CategoryInfo(Name = "R: SSAO Shader", Order = 1000)] [Categorization.ElementInfo(Order = 0), HideInInspector] class ScreenSpaceAmbientOcclusionPersistentResources : IRenderPipelineResources { [SerializeField] [ResourcePath("Shaders/Utils/ScreenSpaceAmbientOcclusion.shader")] Shader m_Shader; public Shader Shader { get => m_Shader; set => this.SetValueAndNotify(ref m_Shader, value); } public bool isAvailableInPlayerBuild => true; [SerializeField][HideInInspector] private int m_Version = 0; /// Current version of the resource container. Used only for upgrading a project. public int version => m_Version; } [Serializable] [SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))] [Categorization.CategoryInfo(Name = "R: SSAO Noise Textures", Order = 1000)] [Categorization.ElementInfo(Order = 0), HideInInspector] class ScreenSpaceAmbientOcclusionDynamicResources : IRenderPipelineResources { [SerializeField] [ResourceFormattedPaths("Textures/BlueNoise256/LDR_LLL1_{0}.png", 0, 7)] Texture2D[] m_BlueNoise256Textures; public Texture2D[] BlueNoise256Textures { get => m_BlueNoise256Textures; set => this.SetValueAndNotify(ref m_BlueNoise256Textures, value); } public bool isAvailableInPlayerBuild => true; [SerializeField][HideInInspector] private int m_Version = 0; /// Current version of the resource container. Used only for upgrading a project. public int version => m_Version; } /// /// The class for the SSAO renderer feature. /// [SupportedOnRenderer(typeof(UniversalRendererData))] [DisallowMultipleRendererFeature("Screen Space Ambient Occlusion")] [Tooltip("The Ambient Occlusion effect darkens creases, holes, intersections and surfaces that are close to each other.")] [URPHelpURL("post-processing-ssao")] public class ScreenSpaceAmbientOcclusion : ScriptableRendererFeature { // Serialized Fields [SerializeField] private ScreenSpaceAmbientOcclusionSettings m_Settings = new ScreenSpaceAmbientOcclusionSettings(); // Private Fields private Material m_Material; private ScreenSpaceAmbientOcclusionPass m_SSAOPass = null; private Shader m_Shader; private Texture2D[] m_BlueNoise256Textures; // Internal / Constants internal ref ScreenSpaceAmbientOcclusionSettings settings => ref m_Settings; internal const string k_AOInterleavedGradientKeyword = "_INTERLEAVED_GRADIENT"; internal const string k_AOBlueNoiseKeyword = "_BLUE_NOISE"; internal const string k_OrthographicCameraKeyword = "_ORTHOGRAPHIC"; internal const string k_SourceDepthLowKeyword = "_SOURCE_DEPTH_LOW"; internal const string k_SourceDepthMediumKeyword = "_SOURCE_DEPTH_MEDIUM"; internal const string k_SourceDepthHighKeyword = "_SOURCE_DEPTH_HIGH"; internal const string k_SourceDepthNormalsKeyword = "_SOURCE_DEPTH_NORMALS"; internal const string k_SampleCountLowKeyword = "_SAMPLE_COUNT_LOW"; internal const string k_SampleCountMediumKeyword = "_SAMPLE_COUNT_MEDIUM"; internal const string k_SampleCountHighKeyword = "_SAMPLE_COUNT_HIGH"; /// public override void Create() { // Create the pass... if (m_SSAOPass == null) m_SSAOPass = new ScreenSpaceAmbientOcclusionPass(); // Check for previous version of SSAO if (m_Settings.SampleCount > 0) { m_Settings.AOMethod = ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.InterleavedGradient; if (m_Settings.SampleCount > 11) m_Settings.Samples = ScreenSpaceAmbientOcclusionSettings.AOSampleOption.High; else if (m_Settings.SampleCount > 8) m_Settings.Samples = ScreenSpaceAmbientOcclusionSettings.AOSampleOption.Medium; else m_Settings.Samples = ScreenSpaceAmbientOcclusionSettings.AOSampleOption.Low; m_Settings.SampleCount = -1; } } /// public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (UniversalRenderer.IsOffscreenDepthTexture(ref renderingData.cameraData)) return; if (!TryPrepareResources()) return; bool shouldAdd = m_SSAOPass.Setup(ref m_Settings, ref renderer, ref m_Material, ref m_BlueNoise256Textures); if (shouldAdd) renderer.EnqueuePass(m_SSAOPass); } /// protected override void Dispose(bool disposing) { m_SSAOPass?.Dispose(); m_SSAOPass = null; CoreUtils.Destroy(m_Material); } bool TryPrepareResources() { if (m_Shader == null) { if (!GraphicsSettings.TryGetRenderPipelineSettings(out var ssaoPersistentResources)) { Debug.LogErrorFormat( $"Couldn't find the required resources for the {nameof(ScreenSpaceAmbientOcclusion)} render feature. If this exception appears in the Player, make sure at least one {nameof(ScreenSpaceAmbientOcclusion)} render feature is enabled or adjust your stripping settings."); return false; } m_Shader = ssaoPersistentResources.Shader; } if (m_Settings.AOMethod == ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.BlueNoise && (m_BlueNoise256Textures == null || m_BlueNoise256Textures.Length == 0)) { if (!GraphicsSettings.TryGetRenderPipelineSettings(out var ssaoDynamicResources)) { Debug.LogErrorFormat($"Couldn't load {nameof(ScreenSpaceAmbientOcclusionDynamicResources.BlueNoise256Textures)}. If this exception appears in the Player, please check the SSAO options for {nameof(ScreenSpaceAmbientOcclusion)} or adjust your stripping settings"); return false; } m_BlueNoise256Textures = ssaoDynamicResources.BlueNoise256Textures; } if (m_Material == null && m_Shader != null) m_Material = CoreUtils.CreateEngineMaterial(m_Shader); if (m_Material == null) { Debug.LogError($"{GetType().Name}.AddRenderPasses(): Missing material. {name} render pass will not be added."); return false; } return true; } } }