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
}
}
///
/// 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();
[SerializeField]
[HideInInspector]
[Reload("Textures/BlueNoise256/LDR_LLL1_{0}.png", 0, 7)]
internal Texture2D[] m_BlueNoise256Textures;
[SerializeField]
[HideInInspector]
[Reload("Shaders/Utils/ScreenSpaceAmbientOcclusion.shader")]
private Shader m_Shader;
// Private Fields
private Material m_Material;
private ScreenSpaceAmbientOcclusionPass m_SSAOPass = null;
// 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()
{
#if UNITY_EDITOR
ResourceReloader.TryReloadAllNullIn(this, UniversalRenderPipelineAsset.packagePath);
#endif
// 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 (!GetMaterials())
{
Debug.LogErrorFormat("{0}.AddRenderPasses(): Missing material. {1} render pass will not be added.", GetType().Name, name);
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);
}
private bool GetMaterials()
{
if (m_Material == null && m_Shader != null)
m_Material = CoreUtils.CreateEngineMaterial(m_Shader);
return m_Material != null;
}
}
}