#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