#if MODERN_SSAO
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.Universal
{
///
/// Screen Space Ambient Occlusion (SSAO) history for temporal filtering.
/// Uses double buffering so the previous frame can be sampled while the current frame is written.
/// The history stores packed depth (RG), AO (B), and a normalized accumulated frame count (A) in an RGBA8 texture.
///
public sealed class SSAOHistory : CameraHistoryItem
{
private int[] m_AccumulationTextureIds = new int[2];
private int[] m_AccumulationVersions = new int[2];
private static readonly string[] m_AccumulationNames = new[]
{
"SSAOAccumulationTex0",
"SSAOAccumulationTex1"
};
private RenderTextureDescriptor m_Descriptor;
private Hash128 m_DescKey;
///
/// Called internally on instance creation.
/// Sets up RTHandle ids.
///
/// BufferedRTHandleSystem of the owning camera.
/// Unique id given to SSAOHistory by the owning camera.
public override void OnCreate(BufferedRTHandleSystem owner, uint typeId)
{
base.OnCreate(owner, typeId);
m_AccumulationTextureIds[0] = MakeId(0);
m_AccumulationTextureIds[1] = MakeId(1);
}
///
/// Release SSAO accumulation textures.
///
public override void Reset()
{
for (int i = 0; i < m_AccumulationTextureIds.Length; i++)
{
ReleaseHistoryFrameRT(m_AccumulationTextureIds[i]);
m_AccumulationVersions[i] = -1;
}
m_Descriptor.width = 0;
m_Descriptor.height = 0;
m_Descriptor.graphicsFormat = GraphicsFormat.None;
m_DescKey = Hash128.Compute(0);
}
///
/// Get the SSAO history write target for the current frame.
///
/// Eye index for XR multi-pass.
/// Current frame RTHandle for SSAO history writes.
public RTHandle GetCurrentTexture(int eyeIndex = 0)
{
if ((uint)eyeIndex >= m_AccumulationTextureIds.Length)
return null;
return GetCurrentFrameRT(m_AccumulationTextureIds[eyeIndex]);
}
///
/// Get the SSAO history read target from the previous frame.
///
/// Eye index for XR multi-pass.
/// Previous frame RTHandle for SSAO history reads.
public RTHandle GetPreviousTexture(int eyeIndex = 0)
{
if ((uint)eyeIndex >= m_AccumulationTextureIds.Length)
return null;
return GetPreviousFrameRT(m_AccumulationTextureIds[eyeIndex]);
}
///
/// Get SSAO accumulation texture.
///
/// Eye index for XR multi-pass.
/// Current frame RTHandle for SSAO accumulation texture.
public RTHandle GetAccumulationTexture(int eyeIndex = 0)
{
return GetCurrentTexture(eyeIndex);
}
///
/// Get SSAO accumulation texture version.
/// Tracks which frame the accumulation was last updated.
///
/// Eye index for XR multi-pass.
/// Accumulation texture version.
public int GetAccumulationVersion(int eyeIndex = 0)
{
return m_AccumulationVersions[eyeIndex];
}
///
/// Set SSAO accumulation texture version.
///
/// Eye index for XR multi-pass.
/// Version to set (typically Time.frameCount).
internal void SetAccumulationVersion(int eyeIndex, int version)
{
m_AccumulationVersions[eyeIndex] = version;
}
// Check if the SSAO accumulation texture is valid.
private bool IsValid()
{
return GetCurrentTexture(0) != null;
}
// True if the desc changed, graphicsFormat etc.
private bool IsDirty(ref RenderTextureDescriptor desc)
{
return m_DescKey != Hash128.Compute(ref desc);
}
private void Alloc(ref RenderTextureDescriptor desc, bool xrMultipassEnabled)
{
AllocHistoryFrameRT(m_AccumulationTextureIds[0], 2, ref desc, m_AccumulationNames[0]);
if (xrMultipassEnabled)
AllocHistoryFrameRT(m_AccumulationTextureIds[1], 2, ref desc, m_AccumulationNames[1]);
m_Descriptor = desc;
m_DescKey = Hash128.Compute(ref desc);
}
///
/// Create SSAO history descriptor from camera descriptor.
///
/// Camera render texture descriptor.
/// Whether SSAO is running at half resolution.
/// Whether the resource requires enableRandomWrite.
/// SSAO history render texture descriptor.
internal static RenderTextureDescriptor GetHistoryDescriptor(ref RenderTextureDescriptor cameraDesc, bool downsample, bool enableRandomWrite)
{
int downsampleDivider = downsample ? 2 : 1;
RenderTextureDescriptor ssaoDesc = cameraDesc;
ssaoDesc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
ssaoDesc.depthStencilFormat = GraphicsFormat.None;
ssaoDesc.msaaSamples = 1;
ssaoDesc.width /= downsampleDivider;
ssaoDesc.height /= downsampleDivider;
ssaoDesc.enableRandomWrite = enableRandomWrite;
return ssaoDesc;
}
///
/// Update the SSAO history texture allocation.
///
/// Camera data providing the render texture descriptor.
/// Whether SSAO is running at half resolution.
/// Whether the resource requires enableRandomWrite.
/// Whether XR multi-pass is enabled.
/// True if the RTHandles were reallocated.
internal bool Update(UniversalCameraData cameraData, bool downsample, bool enableRandomWrite, bool xrMultipassEnabled = false)
{
ref RenderTextureDescriptor cameraDesc = ref cameraData.cameraTargetDescriptor;
if (cameraDesc.width > 0 && cameraDesc.height > 0 && cameraDesc.graphicsFormat != GraphicsFormat.None)
{
var ssaoDesc = GetHistoryDescriptor(ref cameraDesc, downsample, enableRandomWrite);
Camera camera = cameraData.camera;
bool isPreview = camera.cameraType == CameraType.Preview;
bool isRenderRequest = camera.isProcessingRenderRequest;
if (!isPreview && !isRenderRequest && IsDirty(ref ssaoDesc))
Reset();
if (!IsValid())
{
Alloc(ref ssaoDesc, xrMultipassEnabled);
return true;
}
}
return false;
}
}
}
#endif