using System.Collections.Generic; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; #if UNITY_2023_3_OR_NEWER using UnityEngine.Rendering.RenderGraphModule; #endif using UnityEngine.Rendering.Universal; #if ENABLE_VR_MODULE && ENABLE_VR using XRSettings = UnityEngine.XR.XRSettings; #endif namespace HorizonBasedAmbientOcclusion.Universal { public class HBAORendererFeature : ScriptableRendererFeature { private class HBAORenderPass : ScriptableRenderPass { public HBAO hbao; #if UNITY_2023_3_OR_NEWER // Holds the data needed for the render pass. private class PassData { public Material Material { get; set; } public RenderTextureDescriptor TargetDescriptor { get; set; } public RenderTextureDescriptor AOTextureDescriptor { get; set; } public TextureHandle CameraDepthTexture { get; set; } public TextureHandle SourceTexture { get; set; } public TextureHandle AOTexture { get; set; } public TextureHandle TempTexture { get; set; } public TextureHandle DestinationTexture { get; set; } public CameraHistoryBuffers HistoryBuffers { get; set; } public RenderTargetIdentifier[] TemporalFilterRenderTargets { get; set; } public Mesh FullscreenTriangle { get; set; } public MaterialPropertyBlock MaterialProperties { get; set; } public bool UseLitAO { get; set; } public bool UseColorBleeding { get; set; } public bool UseBlur { get; set; } public bool UseTemporalFilter { get; set; } public float DirectLightingStrength { get; set; } public bool ShowDebug { get; set; } public bool ShowViewNormals { get; set; } public bool RenderingInSceneView { get; set; } } #endif private static class Pass { public const int AO = 0; public const int AO_Deinterleaved = 1; public const int Deinterleave_Depth = 2; public const int Deinterleave_Normals = 3; public const int Atlas_AO_Deinterleaved = 4; public const int Reinterleave_AO = 5; public const int Blur = 6; public const int Temporal_Filter = 7; public const int Copy = 8; public const int Composite = 9; public const int Debug_ViewNormals = 10; } private static class ShaderProperties { public static int mainTex; public static int inputTex; public static int hbaoTex; public static int tempTex; public static int tempTex2; public static int noiseTex; public static int depthTex; public static int normalsTex; public static int ssaoTex; public static int[] depthSliceTex; public static int[] normalsSliceTex; public static int[] aoSliceTex; public static int[] deinterleaveOffset; public static int atlasOffset; public static int jitter; public static int uvTransform; public static int inputTexelSize; public static int aoTexelSize; public static int deinterleavedAOTexelSize; public static int reinterleavedAOTexelSize; public static int uvToView; //public static int worldToCameraMatrix; public static int targetScale; public static int radius; public static int maxRadiusPixels; public static int negInvRadius2; public static int angleBias; public static int aoMultiplier; public static int intensity; public static int multiBounceInfluence; public static int offscreenSamplesContrib; public static int maxDistance; public static int distanceFalloff; public static int baseColor; public static int colorBleedSaturation; public static int albedoMultiplier; public static int colorBleedBrightnessMask; public static int colorBleedBrightnessMaskRange; public static int blurDeltaUV; public static int blurSharpness; public static int temporalParams; public static int historyBufferRTHandleScale; public static int cameraDepthTexture; public static int screenSpaceOcclusionTexture; public static int screenSpaceOcclusionParam; #if UNITY_2023_3_OR_NEWER public static GlobalKeyword screenSpaceOcclusionKeyword; #endif static ShaderProperties() { mainTex = Shader.PropertyToID("_MainTex"); inputTex = Shader.PropertyToID("_InputTex"); hbaoTex = Shader.PropertyToID("_HBAOTex"); tempTex = Shader.PropertyToID("_TempTex"); tempTex2 = Shader.PropertyToID("_TempTex2"); noiseTex = Shader.PropertyToID("_NoiseTex"); depthTex = Shader.PropertyToID("_DepthTex"); normalsTex = Shader.PropertyToID("_NormalsTex"); ssaoTex = Shader.PropertyToID("_SSAOTex"); depthSliceTex = new int[4 * 4]; normalsSliceTex = new int[4 * 4]; aoSliceTex = new int[4 * 4]; for (int i = 0; i < 4 * 4; i++) { depthSliceTex[i] = Shader.PropertyToID("_DepthSliceTex" + i); normalsSliceTex[i] = Shader.PropertyToID("_NormalsSliceTex" + i); aoSliceTex[i] = Shader.PropertyToID("_AOSliceTex" + i); } deinterleaveOffset = new int[] { Shader.PropertyToID("_Deinterleave_Offset00"), Shader.PropertyToID("_Deinterleave_Offset10"), Shader.PropertyToID("_Deinterleave_Offset01"), Shader.PropertyToID("_Deinterleave_Offset11") }; atlasOffset = Shader.PropertyToID("_AtlasOffset"); jitter = Shader.PropertyToID("_Jitter"); uvTransform = Shader.PropertyToID("_UVTransform"); inputTexelSize = Shader.PropertyToID("_Input_TexelSize"); aoTexelSize = Shader.PropertyToID("_AO_TexelSize"); deinterleavedAOTexelSize = Shader.PropertyToID("_DeinterleavedAO_TexelSize"); reinterleavedAOTexelSize = Shader.PropertyToID("_ReinterleavedAO_TexelSize"); uvToView = Shader.PropertyToID("_UVToView"); //worldToCameraMatrix = Shader.PropertyToID("_WorldToCameraMatrix"); targetScale = Shader.PropertyToID("_TargetScale"); radius = Shader.PropertyToID("_Radius"); maxRadiusPixels = Shader.PropertyToID("_MaxRadiusPixels"); negInvRadius2 = Shader.PropertyToID("_NegInvRadius2"); angleBias = Shader.PropertyToID("_AngleBias"); aoMultiplier = Shader.PropertyToID("_AOmultiplier"); intensity = Shader.PropertyToID("_Intensity"); multiBounceInfluence = Shader.PropertyToID("_MultiBounceInfluence"); offscreenSamplesContrib = Shader.PropertyToID("_OffscreenSamplesContrib"); maxDistance = Shader.PropertyToID("_MaxDistance"); distanceFalloff = Shader.PropertyToID("_DistanceFalloff"); baseColor = Shader.PropertyToID("_BaseColor"); colorBleedSaturation = Shader.PropertyToID("_ColorBleedSaturation"); albedoMultiplier = Shader.PropertyToID("_AlbedoMultiplier"); colorBleedBrightnessMask = Shader.PropertyToID("_ColorBleedBrightnessMask"); colorBleedBrightnessMaskRange = Shader.PropertyToID("_ColorBleedBrightnessMaskRange"); blurDeltaUV = Shader.PropertyToID("_BlurDeltaUV"); blurSharpness = Shader.PropertyToID("_BlurSharpness"); temporalParams = Shader.PropertyToID("_TemporalParams"); historyBufferRTHandleScale = Shader.PropertyToID("_HistoryBuffer_RTHandleScale"); cameraDepthTexture = Shader.PropertyToID("_CameraDepthTexture"); screenSpaceOcclusionTexture = Shader.PropertyToID("_ScreenSpaceOcclusionTexture"); screenSpaceOcclusionParam = Shader.PropertyToID("_AmbientOcclusionParam"); #if UNITY_2023_3_OR_NEWER screenSpaceOcclusionKeyword = GlobalKeyword.Create(ShaderKeywordStrings.ScreenSpaceOcclusion); #endif } public static string GetOrthographicProjectionKeyword(bool orthographic) { return orthographic ? "ORTHOGRAPHIC_PROJECTION" : "__"; } public static string GetQualityKeyword(HBAO.Quality quality) { switch (quality) { case HBAO.Quality.Lowest: return "QUALITY_LOWEST"; case HBAO.Quality.Low: return "QUALITY_LOW"; case HBAO.Quality.Medium: return "QUALITY_MEDIUM"; case HBAO.Quality.High: return "QUALITY_HIGH"; case HBAO.Quality.Highest: return "QUALITY_HIGHEST"; default: return "QUALITY_MEDIUM"; } } public static string GetNoiseKeyword(HBAO.NoiseType noiseType) { switch (noiseType) { case HBAO.NoiseType.InterleavedGradientNoise: return "INTERLEAVED_GRADIENT_NOISE"; case HBAO.NoiseType.Dither: case HBAO.NoiseType.SpatialDistribution: default: return "__"; } } public static string GetDeinterleavingKeyword(HBAO.Deinterleaving deinterleaving) { switch (deinterleaving) { case HBAO.Deinterleaving.x4: return "DEINTERLEAVED"; case HBAO.Deinterleaving.Disabled: default: return "__"; } } public static string GetDebugKeyword(HBAO.DebugMode debugMode) { switch (debugMode) { case HBAO.DebugMode.AOOnly: return "DEBUG_AO"; case HBAO.DebugMode.ColorBleedingOnly: return "DEBUG_COLORBLEEDING"; case HBAO.DebugMode.SplitWithoutAOAndWithAO: return "DEBUG_NOAO_AO"; case HBAO.DebugMode.SplitWithAOAndAOOnly: return "DEBUG_AO_AOONLY"; case HBAO.DebugMode.SplitWithoutAOAndAOOnly: return "DEBUG_NOAO_AOONLY"; case HBAO.DebugMode.Disabled: default: return "__"; } } public static string GetMultibounceKeyword(bool useMultiBounce, bool litAoModeEnabled) { return useMultiBounce && !litAoModeEnabled ? "MULTIBOUNCE" : "__"; } public static string GetOffscreenSamplesContributionKeyword(float offscreenSamplesContribution) { return offscreenSamplesContribution > 0 ? "OFFSCREEN_SAMPLES_CONTRIBUTION" : "__"; } public static string GetPerPixelNormalsKeyword(HBAO.PerPixelNormals perPixelNormals) { switch (perPixelNormals) { case HBAO.PerPixelNormals.Reconstruct4Samples: return "NORMALS_RECONSTRUCT4"; case HBAO.PerPixelNormals.Reconstruct2Samples: return "NORMALS_RECONSTRUCT2"; case HBAO.PerPixelNormals.Camera: default: return "__"; } } public static string GetBlurRadiusKeyword(HBAO.BlurType blurType) { switch (blurType) { case HBAO.BlurType.Narrow: return "BLUR_RADIUS_2"; case HBAO.BlurType.Medium: return "BLUR_RADIUS_3"; case HBAO.BlurType.Wide: return "BLUR_RADIUS_4"; case HBAO.BlurType.ExtraWide: return "BLUR_RADIUS_5"; case HBAO.BlurType.None: default: return "BLUR_RADIUS_3"; } } public static string GetVarianceClippingKeyword(HBAO.VarianceClipping varianceClipping) { switch (varianceClipping) { case HBAO.VarianceClipping._4Tap: return "VARIANCE_CLIPPING_4TAP"; case HBAO.VarianceClipping._8Tap: return "VARIANCE_CLIPPING_8TAP"; case HBAO.VarianceClipping.Disabled: default: return "__"; } } public static string GetColorBleedingKeyword(bool colorBleedingEnabled, bool litAoModeEnabled) { return colorBleedingEnabled && !litAoModeEnabled ? "COLOR_BLEEDING" : "__"; } public static string GetModeKeyword(HBAO.Mode mode) { return mode == HBAO.Mode.LitAO ? "LIT_AO" : "__"; } } private static class MersenneTwister { // Mersenne-Twister random numbers in [0,1). public static float[] Numbers = new float[] { //0.463937f,0.340042f,0.223035f,0.468465f,0.322224f,0.979269f,0.031798f,0.973392f,0.778313f,0.456168f,0.258593f,0.330083f,0.387332f,0.380117f,0.179842f,0.910755f, //0.511623f,0.092933f,0.180794f,0.620153f,0.101348f,0.556342f,0.642479f,0.442008f,0.215115f,0.475218f,0.157357f,0.568868f,0.501241f,0.629229f,0.699218f,0.707733f 0.556725f,0.005520f,0.708315f,0.583199f,0.236644f,0.992380f,0.981091f,0.119804f,0.510866f,0.560499f,0.961497f,0.557862f,0.539955f,0.332871f,0.417807f,0.920779f, 0.730747f,0.076690f,0.008562f,0.660104f,0.428921f,0.511342f,0.587871f,0.906406f,0.437980f,0.620309f,0.062196f,0.119485f,0.235646f,0.795892f,0.044437f,0.617311f }; } private class CameraHistoryBuffers { public Camera camera { get; set; } public BufferedRTHandleSystem historyRTSystem { get; set; } public int frameCount { get; set; } public int lastRenderedFrame { get; set; } } private enum HistoryBufferType { AmbientOcclusion, ColorBleeding } private static readonly Vector2[] s_jitter = new Vector2[4 * 4]; private static readonly float[] s_temporalRotations = { 60.0f, 300.0f, 180.0f, 240.0f, 120.0f, 0.0f }; private static readonly float[] s_temporalOffsets = { 0.0f, 0.5f, 0.25f, 0.75f }; private Material material { get; set; } private RenderTargetIdentifier source { get; set; } private CameraData cameraData { get; set; } private RenderTextureDescriptor sourceDesc { get; set; } private RenderTextureDescriptor aoDesc { get; set; } private RenderTextureDescriptor deinterleavedDepthDesc { get; set; } private RenderTextureDescriptor deinterleavedNormalsDesc { get; set; } private RenderTextureDescriptor deinterleavedAoDesc { get; set; } private RenderTextureDescriptor reinterleavedAoDesc { get; set; } private RenderTextureDescriptor ssaoDesc { get; set; } private RenderTextureFormat colorFormat { get; set; } private RenderTextureFormat ssaoFormat { get; set; } private GraphicsFormat graphicsColorFormat { get; set; } private GraphicsFormat graphicsDepthFormat { get; set; } private GraphicsFormat graphicsNormalsFormat { get; set; } private RenderTextureFormat depthFormat { get; set; } private RenderTextureFormat normalsFormat { get; set; } private bool motionVectorsSupported { get; set; } private Texture2D noiseTex { get; set; } private static bool isLinearColorSpace { get { return QualitySettings.activeColorSpace == ColorSpace.Linear; } } private bool renderingInSceneView { get { return cameraData.camera.cameraType == CameraType.SceneView; } } private Mesh fullscreenTriangle { get { if (m_FullscreenTriangle != null) return m_FullscreenTriangle; m_FullscreenTriangle = new Mesh { name = "Fullscreen Triangle" }; // Because we have to support older platforms (GLES2/3, DX9 etc) we can't do all of // this directly in the vertex shader using vertex ids :( m_FullscreenTriangle.SetVertices(new List { new Vector3(-1f, -1f, 0f), new Vector3(-1f, 3f, 0f), new Vector3( 3f, -1f, 0f) }); m_FullscreenTriangle.SetIndices(new[] { 0, 1, 2 }, MeshTopology.Triangles, 0, false); m_FullscreenTriangle.UploadMeshData(false); return m_FullscreenTriangle; } } private MaterialPropertyBlock materialPropertyBlock { get { if (m_MaterialPropertyBlock != null) return m_MaterialPropertyBlock; m_MaterialPropertyBlock = new MaterialPropertyBlock(); return m_MaterialPropertyBlock; } } private Mesh m_FullscreenTriangle; private MaterialPropertyBlock m_MaterialPropertyBlock; private HBAO.Resolution? m_PreviousResolution; private HBAO.NoiseType? m_PreviousNoiseType; private bool m_PreviousColorBleedingEnabled; #if ENABLE_VR_MODULE && ENABLE_VR private XRSettings.StereoRenderingMode m_PrevStereoRenderingMode; #endif private string[] m_ShaderKeywords; private RenderTargetIdentifier[] m_RtsDepth = new RenderTargetIdentifier[4]; private RenderTargetIdentifier[] m_RtsNormals = new RenderTargetIdentifier[4]; private RenderTargetIdentifier[] m_RtsTemporalFilter = new RenderTargetIdentifier[2]; private List m_CameraHistoryBuffers = new List(); private Vector4[] m_UVToViewPerEye = new Vector4[2]; private float[] m_RadiusPerEye = new float[2]; private ProfilingSampler m_ProfilingSampler = new ProfilingSampler("HBAO"); public void FillSupportedRenderTextureFormats() { colorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.Default; ssaoFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8) ? RenderTextureFormat.R8 : RenderTextureFormat.ARGB32; graphicsColorFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf) ? GraphicsFormat.R16G16B16A16_SFloat : GraphicsFormat.R8G8B8A8_SRGB; graphicsDepthFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RFloat) ? GraphicsFormat.R32_SFloat : GraphicsFormat.R16_SFloat; graphicsNormalsFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGB2101010) ? GraphicsFormat.A2R10G10B10_UNormPack32 : GraphicsFormat.R8G8B8A8_SRGB; depthFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RFloat) ? RenderTextureFormat.RFloat : RenderTextureFormat.RHalf; normalsFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGB2101010) ? RenderTextureFormat.ARGB2101010 : RenderTextureFormat.Default; motionVectorsSupported = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGHalf); } public void Setup(Shader shader, ScriptableRenderer renderer, RenderingData renderingData) { if (material == null) material = CoreUtils.CreateEngineMaterial(shader); //--- FetchVolumeComponent(); var passInput = ScriptableRenderPassInput.Depth; if (hbao.perPixelNormals.value == HBAO.PerPixelNormals.Camera) passInput |= ScriptableRenderPassInput.Normal; #if UNITY_2021_2_OR_NEWER if (hbao.temporalFilterEnabled.value) passInput |= ScriptableRenderPassInput.Motion; #endif ConfigureInput(passInput); #if UNITY_2021_2_OR_NEWER #if !UNITY_2023_3_OR_NEWER ConfigureColorStoreAction(RenderBufferStoreAction.DontCare); #endif // Configures where the render pass should be injected. // Rendering after PrePasses is usually correct except when depth priming is in play: // then we rely on a depth resolve taking place after the PrePasses in order to have it ready for SSAO. // Hence we set the event to RenderPassEvent.AfterRenderingPrePasses + 1 at the earliest. renderPassEvent = hbao.debugMode.value == HBAO.DebugMode.Disabled ? hbao.mode.value == HBAO.Mode.LitAO ? hbao.renderingPath.value == HBAO.RenderingPath.Deferred ? RenderPassEvent.AfterRenderingGbuffer : RenderPassEvent.AfterRenderingPrePasses + 1 : RenderPassEvent.BeforeRenderingTransparents : RenderPassEvent.AfterRenderingTransparents; #else // Configures where the render pass should be injected. // Rendering after PrePasses is usually correct except when depth priming is in play: // then we rely on a depth resolve taking place after the PrePasses in order to have it ready for SSAO. // Hence we set the event to RenderPassEvent.AfterRenderingPrePasses + 1 at the earliest. renderPassEvent = hbao.debugMode.value == HBAO.DebugMode.Disabled ? hbao.mode.value == HBAO.Mode.LitAO ? RenderPassEvent.AfterRenderingPrePasses + 1 : RenderPassEvent.BeforeRenderingTransparents : RenderPassEvent.AfterRenderingTransparents; #endif } #if UNITY_2023_3_OR_NEWER [System.Obsolete] #endif public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { //source = new RenderTargetIdentifier("_CameraColorTexture"); #if UNITY_2022_1_OR_NEWER source = renderingData.cameraData.renderer.cameraColorTargetHandle; #else source = renderingData.cameraData.renderer.cameraColorTarget; #endif cameraData = renderingData.cameraData; /* FetchVolumeComponent(); var passInput = ScriptableRenderPassInput.Depth; if (hbao.perPixelNormals.value == HBAO.PerPixelNormals.Camera) passInput |= ScriptableRenderPassInput.Normal; #if UNITY_2021_2_OR_NEWER if (hbao.temporalFilterEnabled.value) passInput |= ScriptableRenderPassInput.Motion; #endif ConfigureInput(passInput); #if UNITY_2021_2_OR_NEWER ConfigureColorStoreAction(RenderBufferStoreAction.DontCare); // Configures where the render pass should be injected. // Rendering after PrePasses is usually correct except when depth priming is in play: // then we rely on a depth resolve taking place after the PrePasses in order to have it ready for SSAO. // Hence we set the event to RenderPassEvent.AfterRenderingPrePasses + 1 at the earliest. renderPassEvent = hbao.debugMode.value == HBAO.DebugMode.Disabled ? hbao.mode.value == HBAO.Mode.LitAO ? hbao.renderingPath.value == HBAO.RenderingPath.Deferred ? RenderPassEvent.AfterRenderingGbuffer : RenderPassEvent.AfterRenderingPrePasses + 1 : RenderPassEvent.BeforeRenderingTransparents : RenderPassEvent.AfterRenderingTransparents; #else // Configures where the render pass should be injected. // Rendering after PrePasses is usually correct except when depth priming is in play: // then we rely on a depth resolve taking place after the PrePasses in order to have it ready for SSAO. // Hence we set the event to RenderPassEvent.AfterRenderingPrePasses + 1 at the earliest. renderPassEvent = hbao.debugMode.value == HBAO.DebugMode.Disabled ? hbao.mode.value == HBAO.Mode.LitAO ? RenderPassEvent.AfterRenderingPrePasses + 1 : RenderPassEvent.BeforeRenderingTransparents : RenderPassEvent.AfterRenderingTransparents; #endif */ } // This method is called before executing the render pass. // It can be used to configure render targets and their clear state. Also to create temporary render target textures. // When empty this render pass will render to the active camera render target. // You should never call CommandBuffer.SetRenderTarget. Instead call ConfigureTarget and ConfigureClear. // The render pipeline will ensure target setup and clearing happens in an performance manner. #if UNITY_2023_3_OR_NEWER [System.Obsolete] #endif public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) { if (material == null) return; FetchVolumeComponent(); if (!hbao.IsActive()) return; FetchRenderParameters(cameraTextureDescriptor); CheckParameters(); UpdateMaterialProperties(); UpdateShaderKeywords(); } // Here you can implement the rendering logic. // Use ScriptableRenderContext to issue drawing commands or execute command buffers // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline. #if UNITY_2023_3_OR_NEWER [System.Obsolete] #endif public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { if (material == null) { Debug.LogError("HBAO material has not been correctly initialized..."); return; } if (!hbao.IsActive()) return; #if UNITY_2021_2_OR_NEWER var historyBuffers = GetCurrentCameraHistoryBuffers(); historyBuffers?.historyRTSystem.SwapAndSetReferenceSize(aoDesc.width, aoDesc.height); #else var historyBuffers = null as CameraHistoryBuffers; #endif var cmd = CommandBufferPool.Get("HBAO"); if (hbao.mode.value == HBAO.Mode.LitAO) { CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.ScreenSpaceOcclusion, true); cmd.GetTemporaryRT(ShaderProperties.ssaoTex, aoDesc, FilterMode.Bilinear); } else { cmd.GetTemporaryRT(ShaderProperties.inputTex, sourceDesc, FilterMode.Point); // Source copy CopySource(cmd); } // AO cmd.SetGlobalVector(ShaderProperties.temporalParams, historyBuffers != null ? new Vector2(s_temporalRotations[historyBuffers.frameCount % 6] / 360.0f, s_temporalOffsets[historyBuffers.frameCount % 4]) : Vector2.zero); if (hbao.deinterleaving.value == HBAO.Deinterleaving.Disabled) { cmd.GetTemporaryRT(ShaderProperties.hbaoTex, aoDesc, FilterMode.Bilinear); AO(cmd); } else { cmd.GetTemporaryRT(ShaderProperties.hbaoTex, reinterleavedAoDesc, FilterMode.Bilinear); DeinterleavedAO(cmd); } // Blur Blur(cmd); // Temporal Filter TemporalFilter(cmd, historyBuffers); // Composite Composite(cmd); cmd.ReleaseTemporaryRT(ShaderProperties.hbaoTex); if (hbao.mode.value != HBAO.Mode.LitAO) cmd.ReleaseTemporaryRT(ShaderProperties.inputTex); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } #if UNITY_2023_3_OR_NEWER // The RecordRenderGraph function will define the Setup and Rendering functions for our render pass. // In the Setup we will configure resources such as which textures it reads from and what render textures // it writes to. The Rendering delegate will contain the rendering code that will execute in the render // graph execution step. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { if (material == null || !hbao.IsActive()) return; UniversalResourceData resourceData = frameData.Get(); UniversalCameraData universalCameraData = frameData.Get(); FetchRenderParameters(universalCameraData.cameraTargetDescriptor); CheckParameters(); UpdateMaterialPropertiesRG(universalCameraData); UpdateShaderKeywordsRG(universalCameraData); var historyBuffers = GetCurrentCameraHistoryBuffersRG(universalCameraData); historyBuffers?.historyRTSystem.SwapAndSetReferenceSize(aoDesc.width, aoDesc.height); using (var builder = renderGraph.AddUnsafePass("HBAO Pass", out var passData, m_ProfilingSampler)) { // Shader keyword changes are considered as global state modifications builder.AllowGlobalStateModification(true); builder.AllowPassCulling(false); TextureHandle cameraDepthTexture = hbao.renderingPath.value == HBAO.RenderingPath.Deferred ? resourceData.activeDepthTexture : resourceData.cameraDepthTexture; TextureHandle cameraNormalsTexture = resourceData.cameraNormalsTexture; TextureHandle motionVectorsTexture = resourceData.motionVectorColor; // source texture is the active color buffer TextureHandle sourceTexture = resourceData.activeColorTexture; // descriptor that match the size and format of the pipeline color buffer. RenderTextureDescriptor targetDesc = universalCameraData.cameraTargetDescriptor; targetDesc.depthBufferBits = 0; // we don't need the depth buffer targetDesc.msaaSamples = 1; bool passUsesCameraNormals = hbao.perPixelNormals.value == HBAO.PerPixelNormals.Camera; bool passUsesMotionVectors = hbao.temporalFilterEnabled.value; bool passUsesLitAO = hbao.mode.value == HBAO.Mode.LitAO; bool passUsesBlur = hbao.blurType.value != HBAO.BlurType.None; bool passUsesTemporalFilter = hbao.temporalFilterEnabled.value; bool passUsesColorBleeding = hbao.colorBleedingEnabled.value; bool passShowDebug = hbao.debugMode.value != HBAO.DebugMode.Disabled; // fill up the passData with the data needed by the pass passData.Material = material; passData.TargetDescriptor = targetDesc; passData.AOTextureDescriptor = aoDesc; passData.CameraDepthTexture = cameraDepthTexture; passData.SourceTexture = sourceTexture; passData.AOTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, aoDesc, "_HBAO_AOTexture0", false, FilterMode.Bilinear); passData.TempTexture = passUsesBlur ? UniversalRenderer.CreateRenderGraphTexture(renderGraph, aoDesc, "_HBAO_AOTexture1", false, FilterMode.Bilinear) : TextureHandle.nullHandle; passData.DestinationTexture = passUsesLitAO && !passShowDebug ? UniversalRenderer.CreateRenderGraphTexture(renderGraph, ssaoDesc, "_ScreenSpaceOcclusionTexture", false, FilterMode.Bilinear) : UniversalRenderer.CreateRenderGraphTexture(renderGraph, targetDesc, "_ScreenSpaceOcclusionTexture", false, FilterMode.Bilinear); passData.HistoryBuffers = historyBuffers; passData.TemporalFilterRenderTargets = m_RtsTemporalFilter; passData.FullscreenTriangle = fullscreenTriangle; passData.MaterialProperties = materialPropertyBlock; passData.UseLitAO = passUsesLitAO; passData.UseColorBleeding = passUsesColorBleeding; passData.UseBlur = passUsesBlur; passData.UseTemporalFilter = passUsesTemporalFilter; passData.DirectLightingStrength = hbao.directLightingStrength.value; passData.ShowDebug = passShowDebug; passData.ShowViewNormals = hbao.debugMode.value == HBAO.DebugMode.ViewNormals; passData.RenderingInSceneView = universalCameraData.camera.cameraType == CameraType.SceneView; // declare the textures used in this pass builder.UseTexture(cameraDepthTexture, AccessFlags.Read); if (passUsesCameraNormals) builder.UseTexture(cameraNormalsTexture, AccessFlags.Read); if (passUsesMotionVectors) builder.UseTexture(motionVectorsTexture, AccessFlags.Read); builder.UseTexture(passData.SourceTexture, passUsesLitAO && !passShowDebug ? AccessFlags.Read : AccessFlags.ReadWrite); builder.UseTexture(passData.AOTexture, AccessFlags.ReadWrite); if (passData.TempTexture.IsValid()) builder.UseTexture(passData.TempTexture, AccessFlags.ReadWrite); builder.UseTexture(passData.DestinationTexture, passUsesLitAO && !passShowDebug ? AccessFlags.Write : AccessFlags.ReadWrite); // for litAO make SSAO texture global after this pass if (passUsesLitAO && !passShowDebug) { //resourceData.ssaoTexture = passData.DestinationTexture; builder.SetGlobalTextureAfterPass(passData.DestinationTexture, ShaderProperties.screenSpaceOcclusionTexture); } builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => ExecutePass(data, context)); } } // ExecutePass is the render function for each of the blit render graph recordings. This is good // practice to avoid using variables outside of the lambda it is called from. // It is static to avoid using member variables which could cause unintended behaviour. private static void ExecutePass(PassData data, UnsafeGraphContext rgContext) { var cmd = CommandBufferHelpers.GetNativeCommandBuffer(rgContext.cmd); //var mpb = rgContext.renderGraphPool.GetTempMaterialPropertyBlock(); // allocate GC, replaced by custom solution below var mpb = data.MaterialProperties; mpb.SetTexture(ShaderProperties.cameraDepthTexture, data.CameraDepthTexture); // is it really required? if (!data.UseLitAO || data.ShowDebug) BlitFullscreenTriangle(cmd, data.SourceTexture, data.DestinationTexture, data.Material, data.FullscreenTriangle, Pass.Copy, mpb); // AO mpb.SetVector(ShaderProperties.temporalParams, data.HistoryBuffers != null ? new Vector2(s_temporalRotations[data.HistoryBuffers.frameCount % 6] / 360.0f, s_temporalOffsets[data.HistoryBuffers.frameCount % 4]) : Vector2.zero); BlitFullscreenTriangleWithClear(cmd, data.SourceTexture, data.AOTexture, data.Material, new Color(0, 0, 0, 1), data.FullscreenTriangle, Pass.AO, mpb); // blur if (data.UseBlur) { float width = data.AOTextureDescriptor.width; float height = data.AOTextureDescriptor.height; if (data.TargetDescriptor.useDynamicScale) { width *= ScalableBufferManager.widthScaleFactor; height *= ScalableBufferManager.heightScaleFactor; } mpb.SetVector(ShaderProperties.blurDeltaUV, new Vector2(1f / width, 0)); BlitFullscreenTriangle(cmd, data.AOTexture, data.TempTexture, data.Material, data.FullscreenTriangle, Pass.Blur, mpb); mpb.SetVector(ShaderProperties.blurDeltaUV, new Vector2(0, 1f / height)); BlitFullscreenTriangle(cmd, data.TempTexture, data.AOTexture, data.Material, data.FullscreenTriangle, Pass.Blur, mpb); } mpb.SetTexture(ShaderProperties.hbaoTex, data.AOTexture); // temporal filter if (data.UseTemporalFilter && !data.RenderingInSceneView && data.HistoryBuffers != null) { mpb.SetVector(ShaderProperties.historyBufferRTHandleScale, data.HistoryBuffers.historyRTSystem.rtHandleProperties.rtHandleScale); if (data.HistoryBuffers.frameCount == 0) { // buffers were just allocated this frame, clear them (previous frame RT) RenderTargetIdentifier aoRenderTargetIdentifier = new RenderTargetIdentifier(data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 1), 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.SetRenderTarget(aoRenderTargetIdentifier, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); cmd.ClearRenderTarget(false, true, Color.white); if (data.UseColorBleeding) { RenderTargetIdentifier cbRenderTargetIdentifier = new RenderTargetIdentifier(data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.ColorBleeding, 1), 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.SetRenderTarget(cbRenderTargetIdentifier, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); cmd.ClearRenderTarget(false, true, new Color(0, 0, 0, 1)); } } var viewportRect = new Rect(Vector2.zero, data.HistoryBuffers.historyRTSystem.rtHandleProperties.currentViewportSize); if (data.UseColorBleeding) { // For Color Bleeding we have 2 history buffers to fill so there are 2 render targets. // AO is still contained in Color Bleeding history buffer (alpha channel) so that we // can use it as a render texture for the composite pass. var currentFrameAORT = data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 0); var currentFrameCBRT = data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.ColorBleeding, 0); var previousFrameAORT = data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 1); var previousFrameCBRT = data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.ColorBleeding, 1); data.TemporalFilterRenderTargets[0] = currentFrameAORT; data.TemporalFilterRenderTargets[1] = currentFrameCBRT; //cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); mpb.SetTexture(ShaderProperties.tempTex, previousFrameCBRT); BlitFullscreenTriangle(cmd, previousFrameAORT, data.TemporalFilterRenderTargets, viewportRect, data.Material, data.FullscreenTriangle, Pass.Temporal_Filter, mpb); //cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix); mpb.SetTexture(ShaderProperties.hbaoTex, currentFrameCBRT); } else { // AO history buffer contains ao in aplha channel so we can just use history as // a render texture for the composite pass. var currentFrameRT = data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 0); var previousFrameRT = data.HistoryBuffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 1); BlitFullscreenTriangle(cmd, previousFrameRT, currentFrameRT, viewportRect, data.Material, data.FullscreenTriangle, Pass.Temporal_Filter, mpb); mpb.SetTexture(ShaderProperties.hbaoTex, currentFrameRT); } // increment buffers frameCount for next frame, track last buffer use data.HistoryBuffers.frameCount++; data.HistoryBuffers.lastRenderedFrame = Time.frameCount; } else mpb.SetVector(ShaderProperties.historyBufferRTHandleScale, Vector4.one); // composite if (data.UseLitAO && !data.ShowDebug) { BlitFullscreenTriangle(cmd, data.SourceTexture, data.DestinationTexture, data.Material, data.FullscreenTriangle, Pass.Composite, mpb); // set global ambient occlusion keyword and param so that it is used by lit shaders cmd.SetKeyword(ShaderProperties.screenSpaceOcclusionKeyword, true); cmd.SetGlobalVector(ShaderProperties.screenSpaceOcclusionParam, new Vector4(1f, 0f, 0f, data.DirectLightingStrength)); } else BlitFullscreenTriangle(cmd, data.DestinationTexture, data.SourceTexture, data.Material, data.FullscreenTriangle, data.ShowViewNormals ? Pass.Debug_ViewNormals : Pass.Composite, mpb); } #endif /// Cleanup any allocated resources that were created during the execution of this render pass. public override void FrameCleanup(CommandBuffer cmd) { if (hbao.mode.value == HBAO.Mode.LitAO) { cmd.ReleaseTemporaryRT(ShaderProperties.ssaoTex); // TODO: should not be called with RenderGraph rendering #if UNITY_2023_3_OR_NEWER cmd.SetKeyword(ShaderProperties.screenSpaceOcclusionKeyword, false); #else CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.ScreenSpaceOcclusion, false); #endif } // we release any camera history buffers that has not rendered for more than 1 frames for (var i = m_CameraHistoryBuffers.Count - 1; i >= 0; i--) { var buffers = m_CameraHistoryBuffers[i]; if (Time.frameCount - buffers.lastRenderedFrame > 1) { ReleaseCameraHistoryBuffers(ref buffers); } } } public void Cleanup() { for (var i = m_CameraHistoryBuffers.Count - 1; i >= 0; i--) { var buffers = m_CameraHistoryBuffers[i]; ReleaseCameraHistoryBuffers(ref buffers); } CoreUtils.Destroy(material); CoreUtils.Destroy(noiseTex); } private void FetchVolumeComponent() { if (hbao == null) hbao = VolumeManager.instance.stack.GetComponent(); } private void FetchRenderParameters(RenderTextureDescriptor cameraTextureDesc) { cameraTextureDesc.msaaSamples = 1; cameraTextureDesc.depthBufferBits = 0; sourceDesc = cameraTextureDesc; var width = cameraTextureDesc.width; var height = cameraTextureDesc.height; var downsamplingFactor = hbao.resolution.value == HBAO.Resolution.Full ? 1 : hbao.deinterleaving.value == HBAO.Deinterleaving.Disabled ? 2 : 1; if (downsamplingFactor > 1) { width = (width + width % 2) / downsamplingFactor; height = (height + height % 2) / downsamplingFactor; } aoDesc = GetStereoCompatibleDescriptor(width, height, format: colorFormat, readWrite: RenderTextureReadWrite.Linear); ssaoDesc = GetStereoCompatibleDescriptor(width, height, format: ssaoFormat, readWrite: RenderTextureReadWrite.Linear); if (hbao.deinterleaving.value != HBAO.Deinterleaving.Disabled) { var reinterleavedWidth = cameraTextureDesc.width + (cameraTextureDesc.width % 4 == 0 ? 0 : 4 - (cameraTextureDesc.width % 4)); var reinterleavedHeight = cameraTextureDesc.height + (cameraTextureDesc.height % 4 == 0 ? 0 : 4 - (cameraTextureDesc.height % 4)); var deinterleavedWidth = reinterleavedWidth / 4; var deinterleavedHeight = reinterleavedHeight / 4; deinterleavedDepthDesc = GetStereoCompatibleDescriptor(deinterleavedWidth, deinterleavedHeight, format: depthFormat, readWrite: RenderTextureReadWrite.Linear); deinterleavedNormalsDesc = GetStereoCompatibleDescriptor(deinterleavedWidth, deinterleavedHeight, format: normalsFormat, readWrite: RenderTextureReadWrite.Linear); deinterleavedAoDesc = GetStereoCompatibleDescriptor(deinterleavedWidth, deinterleavedHeight, format: colorFormat, readWrite: RenderTextureReadWrite.Linear); reinterleavedAoDesc = GetStereoCompatibleDescriptor(reinterleavedWidth, reinterleavedHeight, format: colorFormat, readWrite: RenderTextureReadWrite.Linear); } } private RTHandle HistoryBufferAllocator(RTHandleSystem rtHandleSystem, int frameIndex) { var texDimension = TextureDimension.Tex2D; var sliceCount = 1; #if ENABLE_VR_MODULE && ENABLE_VR if (XRSettings.enabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassInstanced) { texDimension = TextureDimension.Tex2DArray; sliceCount = 2; } #endif return rtHandleSystem.Alloc(Vector2.one, colorFormat: graphicsColorFormat, useDynamicScale: true, name: "HBAO_HistoryBuffer_" + frameIndex, dimension: texDimension, slices: sliceCount); //return rtHandleSystem.Alloc(scaleFactor: Vector2.one, slices: TextureXR.slices, colorFormat: graphicsColorFormat, dimension: TextureXR.dimension, useDynamicScale: true, name: "HBAO_HistoryBuffer_" + frameIndex); } private void AllocCameraHistoryBuffers(ref CameraHistoryBuffers buffers) { buffers = new CameraHistoryBuffers(); buffers.camera = cameraData.camera; buffers.frameCount = 0; buffers.historyRTSystem = new BufferedRTHandleSystem(); // https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@12.0/manual/rthandle-system-using.html buffers.historyRTSystem.AllocBuffer((int)HistoryBufferType.AmbientOcclusion, HistoryBufferAllocator, 2); if (hbao.colorBleedingEnabled.value) buffers.historyRTSystem.AllocBuffer((int)HistoryBufferType.ColorBleeding, HistoryBufferAllocator, 2); m_CameraHistoryBuffers.Add(buffers); } #if UNITY_2023_3_OR_NEWER private void AllocCameraHistoryBuffersRG(UniversalCameraData cameraData, ref CameraHistoryBuffers buffers) { buffers = new CameraHistoryBuffers(); buffers.camera = cameraData.camera; buffers.frameCount = 0; buffers.historyRTSystem = new BufferedRTHandleSystem(); // https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@12.0/manual/rthandle-system-using.html buffers.historyRTSystem.AllocBuffer((int)HistoryBufferType.AmbientOcclusion, HistoryBufferAllocator, 2); if (hbao.colorBleedingEnabled.value) buffers.historyRTSystem.AllocBuffer((int)HistoryBufferType.ColorBleeding, HistoryBufferAllocator, 2); m_CameraHistoryBuffers.Add(buffers); } #endif private void ReleaseCameraHistoryBuffers(ref CameraHistoryBuffers buffers) { buffers.historyRTSystem.ReleaseAll(); buffers.historyRTSystem.Dispose(); m_CameraHistoryBuffers.Remove(buffers); buffers = null; } private CameraHistoryBuffers GetCurrentCameraHistoryBuffers() { CameraHistoryBuffers buffers = null; if (hbao.temporalFilterEnabled.value && !renderingInSceneView) { for (var i = 0; i < m_CameraHistoryBuffers.Count; i++) { if (m_CameraHistoryBuffers[i].camera == cameraData.camera) { buffers = m_CameraHistoryBuffers[i]; break; } } if ((m_PreviousColorBleedingEnabled != hbao.colorBleedingEnabled.value || #if ENABLE_VR_MODULE && ENABLE_VR m_PrevStereoRenderingMode != XRSettings.stereoRenderingMode || #endif m_PreviousResolution != hbao.resolution.value) && buffers != null) { ReleaseCameraHistoryBuffers(ref buffers); m_PreviousColorBleedingEnabled = hbao.colorBleedingEnabled.value; m_PreviousResolution = hbao.resolution.value; #if ENABLE_VR_MODULE && ENABLE_VR m_PrevStereoRenderingMode = XRSettings.stereoRenderingMode; #endif } if (buffers == null) AllocCameraHistoryBuffers(ref buffers); } return buffers; } #if UNITY_2023_3_OR_NEWER private CameraHistoryBuffers GetCurrentCameraHistoryBuffersRG(UniversalCameraData cameraData) { CameraHistoryBuffers buffers = null; if (hbao.temporalFilterEnabled.value && !(cameraData.cameraType == CameraType.SceneView)) { for (var i = 0; i < m_CameraHistoryBuffers.Count; i++) { if (m_CameraHistoryBuffers[i].camera == cameraData.camera) { buffers = m_CameraHistoryBuffers[i]; break; } } if ((m_PreviousColorBleedingEnabled != hbao.colorBleedingEnabled.value || #if ENABLE_VR_MODULE && ENABLE_VR m_PrevStereoRenderingMode != XRSettings.stereoRenderingMode || #endif m_PreviousResolution != hbao.resolution.value) && buffers != null) { ReleaseCameraHistoryBuffers(ref buffers); m_PreviousColorBleedingEnabled = hbao.colorBleedingEnabled.value; m_PreviousResolution = hbao.resolution.value; #if ENABLE_VR_MODULE && ENABLE_VR m_PrevStereoRenderingMode = XRSettings.stereoRenderingMode; #endif } if (buffers == null) AllocCameraHistoryBuffersRG(cameraData, ref buffers); } return buffers; } #endif private void CopySource(CommandBuffer cmd) { BlitFullscreenTriangle(cmd, source, ShaderProperties.inputTex, material, fullscreenTriangle, Pass.Copy); } private void AO(CommandBuffer cmd) { BlitFullscreenTriangleWithClear(cmd, hbao.mode.value == HBAO.Mode.LitAO ? source : ShaderProperties.inputTex, ShaderProperties.hbaoTex, material, new Color(0, 0, 0, 1), fullscreenTriangle, Pass.AO); } private void DeinterleavedAO(CommandBuffer cmd) { // Deinterleave depth & normals (4x4) //cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); for (int i = 0; i < 4; i++) { m_RtsDepth[0] = ShaderProperties.depthSliceTex[(i << 2) + 0]; m_RtsDepth[1] = ShaderProperties.depthSliceTex[(i << 2) + 1]; m_RtsDepth[2] = ShaderProperties.depthSliceTex[(i << 2) + 2]; m_RtsDepth[3] = ShaderProperties.depthSliceTex[(i << 2) + 3]; m_RtsNormals[0] = ShaderProperties.normalsSliceTex[(i << 2) + 0]; m_RtsNormals[1] = ShaderProperties.normalsSliceTex[(i << 2) + 1]; m_RtsNormals[2] = ShaderProperties.normalsSliceTex[(i << 2) + 2]; m_RtsNormals[3] = ShaderProperties.normalsSliceTex[(i << 2) + 3]; int offsetX = (i & 1) << 1; int offsetY = (i >> 1) << 1; cmd.SetGlobalVector(ShaderProperties.deinterleaveOffset[0], new Vector2(offsetX + 0, offsetY + 0)); cmd.SetGlobalVector(ShaderProperties.deinterleaveOffset[1], new Vector2(offsetX + 1, offsetY + 0)); cmd.SetGlobalVector(ShaderProperties.deinterleaveOffset[2], new Vector2(offsetX + 0, offsetY + 1)); cmd.SetGlobalVector(ShaderProperties.deinterleaveOffset[3], new Vector2(offsetX + 1, offsetY + 1)); for (int j = 0; j < 4; j++) { cmd.GetTemporaryRT(ShaderProperties.depthSliceTex[j + 4 * i], deinterleavedDepthDesc, FilterMode.Point); cmd.GetTemporaryRT(ShaderProperties.normalsSliceTex[j + 4 * i], deinterleavedNormalsDesc, FilterMode.Point); } BlitFullscreenTriangle(cmd, BuiltinRenderTextureType.CameraTarget, m_RtsDepth, material, fullscreenTriangle, Pass.Deinterleave_Depth); // outputs 4 render textures BlitFullscreenTriangle(cmd, BuiltinRenderTextureType.CameraTarget, m_RtsNormals, material, fullscreenTriangle, Pass.Deinterleave_Normals); // outputs 4 render textures } //cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix); // AO on each layer for (int i = 0; i < 4 * 4; i++) { cmd.SetGlobalTexture(ShaderProperties.depthTex, ShaderProperties.depthSliceTex[i]); cmd.SetGlobalTexture(ShaderProperties.normalsTex, ShaderProperties.normalsSliceTex[i]); cmd.SetGlobalVector(ShaderProperties.jitter, s_jitter[i]); cmd.GetTemporaryRT(ShaderProperties.aoSliceTex[i], deinterleavedAoDesc, FilterMode.Point); BlitFullscreenTriangleWithClear(cmd, hbao.mode.value == HBAO.Mode.LitAO ? source : ShaderProperties.inputTex, ShaderProperties.aoSliceTex[i], material, new Color(0, 0, 0, 1), fullscreenTriangle, Pass.AO_Deinterleaved); // ao cmd.ReleaseTemporaryRT(ShaderProperties.depthSliceTex[i]); cmd.ReleaseTemporaryRT(ShaderProperties.normalsSliceTex[i]); } // Atlas Deinterleaved AO, 4x4 cmd.GetTemporaryRT(ShaderProperties.tempTex, reinterleavedAoDesc, FilterMode.Point); for (int i = 0; i < 4 * 4; i++) { cmd.SetGlobalVector(ShaderProperties.atlasOffset, new Vector2(((i & 1) + (((i & 7) >> 2) << 1)) * deinterleavedAoDesc.width, (((i & 3) >> 1) + ((i >> 3) << 1)) * deinterleavedAoDesc.height)); BlitFullscreenTriangle(cmd, ShaderProperties.aoSliceTex[i], ShaderProperties.tempTex, material, fullscreenTriangle, Pass.Atlas_AO_Deinterleaved); // atlassing cmd.ReleaseTemporaryRT(ShaderProperties.aoSliceTex[i]); } // Reinterleave AO BlitFullscreenTriangle(cmd, ShaderProperties.tempTex, ShaderProperties.hbaoTex, material, fullscreenTriangle, Pass.Reinterleave_AO); // reinterleave cmd.ReleaseTemporaryRT(ShaderProperties.tempTex); } private void Blur(CommandBuffer cmd) { if (hbao.blurType.value != HBAO.BlurType.None) { float width = aoDesc.width; float height = aoDesc.height; if (sourceDesc.useDynamicScale) { width *= ScalableBufferManager.widthScaleFactor; height *= ScalableBufferManager.heightScaleFactor; } cmd.GetTemporaryRT(ShaderProperties.tempTex, aoDesc, FilterMode.Bilinear); cmd.SetGlobalVector(ShaderProperties.blurDeltaUV, new Vector2(1f / width, 0)); BlitFullscreenTriangle(cmd, ShaderProperties.hbaoTex, ShaderProperties.tempTex, material, fullscreenTriangle, Pass.Blur); cmd.SetGlobalVector(ShaderProperties.blurDeltaUV, new Vector2(0, 1f / height)); BlitFullscreenTriangle(cmd, ShaderProperties.tempTex, ShaderProperties.hbaoTex, material, fullscreenTriangle, Pass.Blur); cmd.ReleaseTemporaryRT(ShaderProperties.tempTex); } } private void TemporalFilter(CommandBuffer cmd, CameraHistoryBuffers buffers) { if (hbao.temporalFilterEnabled.value && !renderingInSceneView && buffers != null) { cmd.SetGlobalVector(ShaderProperties.historyBufferRTHandleScale, buffers.historyRTSystem.rtHandleProperties.rtHandleScale); if (buffers.frameCount == 0) { // buffers were just allocated this frame, clear them (previous frame RT) cmd.SetRenderTarget(buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 1), 0, CubemapFace.Unknown, -1); cmd.ClearRenderTarget(false, true, Color.white); if (hbao.colorBleedingEnabled.value) { cmd.SetRenderTarget(buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.ColorBleeding, 1), 0, CubemapFace.Unknown, -1); cmd.ClearRenderTarget(false, true, new Color(0, 0, 0, 1)); } } var viewportRect = new Rect(Vector2.zero, buffers.historyRTSystem.rtHandleProperties.currentViewportSize); if (hbao.colorBleedingEnabled.value) { // For Color Bleeding we have 2 history buffers to fill so there are 2 render targets. // AO is still contained in Color Bleeding history buffer (alpha channel) so that we // can use it as a render texture for the composite pass. var currentFrameAORT = buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 0); var currentFrameCBRT = buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.ColorBleeding, 0); var previousFrameAORT = buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 1); var previousFrameCBRT = buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.ColorBleeding, 1); var rts = new RenderTargetIdentifier[] { currentFrameAORT, currentFrameCBRT }; //cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); cmd.SetGlobalTexture(ShaderProperties.tempTex, previousFrameCBRT); BlitFullscreenTriangle(cmd, previousFrameAORT, rts, viewportRect, material, fullscreenTriangle, Pass.Temporal_Filter); //cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix); cmd.SetGlobalTexture(ShaderProperties.hbaoTex, currentFrameCBRT); } else { // AO history buffer contains ao in aplha channel so we can just use history as // a render texture for the composite pass. var currentFrameRT = buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 0); var previousFrameRT = buffers.historyRTSystem.GetFrameRT((int)HistoryBufferType.AmbientOcclusion, 1); BlitFullscreenTriangle(cmd, previousFrameRT, currentFrameRT, viewportRect, material, fullscreenTriangle, Pass.Temporal_Filter); cmd.SetGlobalTexture(ShaderProperties.hbaoTex, currentFrameRT); } // increment buffers frameCount for next frame, track last buffer use buffers.frameCount++; buffers.lastRenderedFrame = Time.frameCount; } else cmd.SetGlobalVector(ShaderProperties.historyBufferRTHandleScale, Vector4.one); } private void Composite(CommandBuffer cmd) { BlitFullscreenTriangle(cmd, hbao.mode.value == HBAO.Mode.LitAO ? source : ShaderProperties.inputTex, hbao.mode.value == HBAO.Mode.LitAO && hbao.debugMode.value == HBAO.DebugMode.Disabled ? ShaderProperties.ssaoTex : source, material, fullscreenTriangle, hbao.debugMode.value == HBAO.DebugMode.ViewNormals ? Pass.Debug_ViewNormals : Pass.Composite ); if (hbao.mode.value == HBAO.Mode.LitAO) { cmd.SetGlobalTexture("_ScreenSpaceOcclusionTexture", ShaderProperties.ssaoTex); cmd.SetGlobalVector("_AmbientOcclusionParam", new Vector4(1f, 0f, 0f, hbao.directLightingStrength.value)); } } private void UpdateMaterialProperties() { var sourceWidth = cameraData.cameraTargetDescriptor.width; var sourceHeight = cameraData.cameraTargetDescriptor.height; #if ENABLE_VR_MODULE && ENABLE_VR int eyeCount = XRSettings.enabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassInstanced && !renderingInSceneView ? 2 : 1; #else int eyeCount = 1; #endif for (int viewIndex = 0; viewIndex < eyeCount; viewIndex++) { var projMatrix = cameraData.GetProjectionMatrix(viewIndex); float invTanHalfFOVxAR = projMatrix.m00; // m00 => 1.0f / (tanHalfFOV * aspectRatio) float invTanHalfFOV = projMatrix.m11; // m11 => 1.0f / tanHalfFOV m_UVToViewPerEye[viewIndex] = new Vector4(2.0f / invTanHalfFOVxAR, -2.0f / invTanHalfFOV, -1.0f / invTanHalfFOVxAR, 1.0f / invTanHalfFOV); m_RadiusPerEye[viewIndex] = hbao.radius.value * 0.5f * (sourceHeight / (hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1) / (2.0f / invTanHalfFOV)); } //float tanHalfFovY = Mathf.Tan(0.5f * cameraData.camera.fieldOfView * Mathf.Deg2Rad); //float invFocalLenX = 1.0f / (1.0f / tanHalfFovY * (sourceHeight / (float)sourceWidth)); //float invFocalLenY = 1.0f / (1.0f / tanHalfFovY); float maxRadInPixels = Mathf.Max(16, hbao.maxRadiusPixels.value * Mathf.Sqrt(sourceWidth * sourceHeight / (1080.0f * 1920.0f))); maxRadInPixels /= hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1; var targetScale = hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? new Vector4(reinterleavedAoDesc.width / (float)sourceWidth, reinterleavedAoDesc.height / (float)sourceHeight, 1.0f / (reinterleavedAoDesc.width / (float)sourceWidth), 1.0f / (reinterleavedAoDesc.height / (float)sourceHeight)) : hbao.resolution.value == HBAO.Resolution.Half /*&& (settings.perPixelNormals.value == HBAO.PerPixelNormals.Reconstruct2Samples || settings.perPixelNormals.value == HBAO.PerPixelNormals.Reconstruct4Samples)*/ ? new Vector4((sourceWidth + 0.5f) / sourceWidth, (sourceHeight + 0.5f) / sourceHeight, 1f, 1f) : Vector4.one; material.SetTexture(ShaderProperties.noiseTex, noiseTex); material.SetVector(ShaderProperties.inputTexelSize, new Vector4(1f / sourceWidth, 1f / sourceHeight, sourceWidth, sourceHeight)); if (sourceDesc.useDynamicScale) material.SetVector(ShaderProperties.aoTexelSize, new Vector4(1f / (aoDesc.width * ScalableBufferManager.widthScaleFactor), 1f / (aoDesc.height * ScalableBufferManager.heightScaleFactor), aoDesc.width * ScalableBufferManager.widthScaleFactor, aoDesc.height * ScalableBufferManager.heightScaleFactor)); else material.SetVector(ShaderProperties.aoTexelSize, new Vector4(1f / aoDesc.width, 1f / aoDesc.height, aoDesc.width, aoDesc.height)); material.SetVector(ShaderProperties.deinterleavedAOTexelSize, new Vector4(1.0f / deinterleavedAoDesc.width, 1.0f / deinterleavedAoDesc.height, deinterleavedAoDesc.width, deinterleavedAoDesc.height)); material.SetVector(ShaderProperties.reinterleavedAOTexelSize, new Vector4(1f / reinterleavedAoDesc.width, 1f / reinterleavedAoDesc.height, reinterleavedAoDesc.width, reinterleavedAoDesc.height)); material.SetVector(ShaderProperties.targetScale, targetScale); //material.SetVector(ShaderProperties.uvToView, new Vector4(2.0f * invFocalLenX, -2.0f * invFocalLenY, -1.0f * invFocalLenX, 1.0f * invFocalLenY)); material.SetVectorArray(ShaderProperties.uvToView, m_UVToViewPerEye); //material.SetMatrix(ShaderProperties.worldToCameraMatrix, cameraData.camera.worldToCameraMatrix); //material.SetFloat(ShaderProperties.radius, hbao.radius.value * 0.5f * ((sourceHeight / (hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1)) / (tanHalfFovY * 2.0f))); //material.SetFloat(ShaderProperties.radius, hbao.radius.value * 0.5f * ((sourceHeight / (hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1)) / (invFocalLenY * 2.0f))); material.SetFloatArray(ShaderProperties.radius, m_RadiusPerEye); material.SetFloat(ShaderProperties.maxRadiusPixels, maxRadInPixels); material.SetFloat(ShaderProperties.negInvRadius2, -1.0f / (hbao.radius.value * hbao.radius.value)); material.SetFloat(ShaderProperties.angleBias, hbao.bias.value); material.SetFloat(ShaderProperties.aoMultiplier, 2.0f * (1.0f / (1.0f - hbao.bias.value))); material.SetFloat(ShaderProperties.intensity, isLinearColorSpace ? hbao.intensity.value : hbao.intensity.value * 0.454545454545455f); material.SetFloat(ShaderProperties.multiBounceInfluence, hbao.multiBounceInfluence.value); material.SetFloat(ShaderProperties.offscreenSamplesContrib, hbao.offscreenSamplesContribution.value); material.SetFloat(ShaderProperties.maxDistance, hbao.maxDistance.value); material.SetFloat(ShaderProperties.distanceFalloff, hbao.distanceFalloff.value); material.SetColor(ShaderProperties.baseColor, hbao.baseColor.value); material.SetFloat(ShaderProperties.blurSharpness, hbao.sharpness.value); material.SetFloat(ShaderProperties.colorBleedSaturation, hbao.saturation.value); material.SetFloat(ShaderProperties.colorBleedBrightnessMask, hbao.brightnessMask.value); material.SetVector(ShaderProperties.colorBleedBrightnessMaskRange, AdjustBrightnessMaskToGammaSpace(new Vector2(Mathf.Pow(hbao.brightnessMaskRange.value.x, 3), Mathf.Pow(hbao.brightnessMaskRange.value.y, 3)))); } #if UNITY_2023_3_OR_NEWER private void UpdateMaterialPropertiesRG(UniversalCameraData cameraData) { var sourceWidth = cameraData.cameraTargetDescriptor.width; var sourceHeight = cameraData.cameraTargetDescriptor.height; #if ENABLE_VR_MODULE && ENABLE_VR int eyeCount = XRSettings.enabled && XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassInstanced && !(cameraData.cameraType == CameraType.SceneView) ? 2 : 1; #else int eyeCount = 1; #endif for (int viewIndex = 0; viewIndex < eyeCount; viewIndex++) { var projMatrix = cameraData.GetProjectionMatrix(viewIndex); float invTanHalfFOVxAR = projMatrix.m00; // m00 => 1.0f / (tanHalfFOV * aspectRatio) float invTanHalfFOV = projMatrix.m11; // m11 => 1.0f / tanHalfFOV m_UVToViewPerEye[viewIndex] = new Vector4(2.0f / invTanHalfFOVxAR, -2.0f / invTanHalfFOV, -1.0f / invTanHalfFOVxAR, 1.0f / invTanHalfFOV); m_RadiusPerEye[viewIndex] = hbao.radius.value * 0.5f * (sourceHeight / (hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1) / (2.0f / invTanHalfFOV)); } //float tanHalfFovY = Mathf.Tan(0.5f * cameraData.camera.fieldOfView * Mathf.Deg2Rad); //float invFocalLenX = 1.0f / (1.0f / tanHalfFovY * (sourceHeight / (float)sourceWidth)); //float invFocalLenY = 1.0f / (1.0f / tanHalfFovY); float maxRadInPixels = Mathf.Max(16, hbao.maxRadiusPixels.value * Mathf.Sqrt(sourceWidth * sourceHeight / (1080.0f * 1920.0f))); maxRadInPixels /= hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1; var targetScale = hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? new Vector4(reinterleavedAoDesc.width / (float)sourceWidth, reinterleavedAoDesc.height / (float)sourceHeight, 1.0f / (reinterleavedAoDesc.width / (float)sourceWidth), 1.0f / (reinterleavedAoDesc.height / (float)sourceHeight)) : hbao.resolution.value == HBAO.Resolution.Half /*&& (settings.perPixelNormals.value == HBAO.PerPixelNormals.Reconstruct2Samples || settings.perPixelNormals.value == HBAO.PerPixelNormals.Reconstruct4Samples)*/ ? new Vector4((sourceWidth + 0.5f) / sourceWidth, (sourceHeight + 0.5f) / sourceHeight, 1f, 1f) : Vector4.one; material.SetTexture(ShaderProperties.noiseTex, noiseTex); material.SetVector(ShaderProperties.inputTexelSize, new Vector4(1f / sourceWidth, 1f / sourceHeight, sourceWidth, sourceHeight)); if (sourceDesc.useDynamicScale) material.SetVector(ShaderProperties.aoTexelSize, new Vector4(1f / (aoDesc.width * ScalableBufferManager.widthScaleFactor), 1f / (aoDesc.height * ScalableBufferManager.heightScaleFactor), aoDesc.width * ScalableBufferManager.widthScaleFactor, aoDesc.height * ScalableBufferManager.heightScaleFactor)); else material.SetVector(ShaderProperties.aoTexelSize, new Vector4(1f / aoDesc.width, 1f / aoDesc.height, aoDesc.width, aoDesc.height)); material.SetVector(ShaderProperties.deinterleavedAOTexelSize, new Vector4(1.0f / deinterleavedAoDesc.width, 1.0f / deinterleavedAoDesc.height, deinterleavedAoDesc.width, deinterleavedAoDesc.height)); material.SetVector(ShaderProperties.reinterleavedAOTexelSize, new Vector4(1f / reinterleavedAoDesc.width, 1f / reinterleavedAoDesc.height, reinterleavedAoDesc.width, reinterleavedAoDesc.height)); material.SetVector(ShaderProperties.targetScale, targetScale); //material.SetVector(ShaderProperties.uvToView, new Vector4(2.0f * invFocalLenX, -2.0f * invFocalLenY, -1.0f * invFocalLenX, 1.0f * invFocalLenY)); material.SetVectorArray(ShaderProperties.uvToView, m_UVToViewPerEye); //material.SetMatrix(ShaderProperties.worldToCameraMatrix, cameraData.camera.worldToCameraMatrix); //material.SetFloat(ShaderProperties.radius, hbao.radius.value * 0.5f * ((sourceHeight / (hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1)) / (tanHalfFovY * 2.0f))); //material.SetFloat(ShaderProperties.radius, hbao.radius.value * 0.5f * ((sourceHeight / (hbao.deinterleaving.value == HBAO.Deinterleaving.x4 ? 4 : 1)) / (invFocalLenY * 2.0f))); material.SetFloatArray(ShaderProperties.radius, m_RadiusPerEye); material.SetFloat(ShaderProperties.maxRadiusPixels, maxRadInPixels); material.SetFloat(ShaderProperties.negInvRadius2, -1.0f / (hbao.radius.value * hbao.radius.value)); material.SetFloat(ShaderProperties.angleBias, hbao.bias.value); material.SetFloat(ShaderProperties.aoMultiplier, 2.0f * (1.0f / (1.0f - hbao.bias.value))); material.SetFloat(ShaderProperties.intensity, isLinearColorSpace ? hbao.intensity.value : hbao.intensity.value * 0.454545454545455f); material.SetFloat(ShaderProperties.multiBounceInfluence, hbao.multiBounceInfluence.value); material.SetFloat(ShaderProperties.offscreenSamplesContrib, hbao.offscreenSamplesContribution.value); material.SetFloat(ShaderProperties.maxDistance, hbao.maxDistance.value); material.SetFloat(ShaderProperties.distanceFalloff, hbao.distanceFalloff.value); material.SetColor(ShaderProperties.baseColor, hbao.baseColor.value); material.SetFloat(ShaderProperties.blurSharpness, hbao.sharpness.value); material.SetFloat(ShaderProperties.colorBleedSaturation, hbao.saturation.value); material.SetFloat(ShaderProperties.colorBleedBrightnessMask, hbao.brightnessMask.value); material.SetVector(ShaderProperties.colorBleedBrightnessMaskRange, AdjustBrightnessMaskToGammaSpace(new Vector2(Mathf.Pow(hbao.brightnessMaskRange.value.x, 3), Mathf.Pow(hbao.brightnessMaskRange.value.y, 3)))); } #endif private void UpdateShaderKeywords() { if (m_ShaderKeywords == null || m_ShaderKeywords.Length != 12) m_ShaderKeywords = new string[12]; m_ShaderKeywords[0] = ShaderProperties.GetOrthographicProjectionKeyword(cameraData.camera.orthographic); m_ShaderKeywords[1] = ShaderProperties.GetQualityKeyword(hbao.quality.value); m_ShaderKeywords[2] = ShaderProperties.GetNoiseKeyword(hbao.noiseType.value); m_ShaderKeywords[3] = ShaderProperties.GetDeinterleavingKeyword(hbao.deinterleaving.value); m_ShaderKeywords[4] = ShaderProperties.GetDebugKeyword(hbao.debugMode.value); m_ShaderKeywords[5] = ShaderProperties.GetMultibounceKeyword(hbao.useMultiBounce.value, hbao.mode.value == HBAO.Mode.LitAO); m_ShaderKeywords[6] = ShaderProperties.GetOffscreenSamplesContributionKeyword(hbao.offscreenSamplesContribution.value); m_ShaderKeywords[7] = ShaderProperties.GetPerPixelNormalsKeyword(hbao.perPixelNormals.value); m_ShaderKeywords[8] = ShaderProperties.GetBlurRadiusKeyword(hbao.blurType.value); m_ShaderKeywords[9] = ShaderProperties.GetVarianceClippingKeyword(hbao.varianceClipping.value); m_ShaderKeywords[10] = ShaderProperties.GetColorBleedingKeyword(hbao.colorBleedingEnabled.value, hbao.mode.value == HBAO.Mode.LitAO); m_ShaderKeywords[11] = ShaderProperties.GetModeKeyword(hbao.mode.value); material.shaderKeywords = m_ShaderKeywords; } #if UNITY_2023_3_OR_NEWER private void UpdateShaderKeywordsRG(UniversalCameraData cameraData) { if (m_ShaderKeywords == null || m_ShaderKeywords.Length != 12) m_ShaderKeywords = new string[12]; m_ShaderKeywords[0] = ShaderProperties.GetOrthographicProjectionKeyword(cameraData.camera.orthographic); m_ShaderKeywords[1] = ShaderProperties.GetQualityKeyword(hbao.quality.value); m_ShaderKeywords[2] = ShaderProperties.GetNoiseKeyword(hbao.noiseType.value); m_ShaderKeywords[3] = ShaderProperties.GetDeinterleavingKeyword(hbao.deinterleaving.value); m_ShaderKeywords[4] = ShaderProperties.GetDebugKeyword(hbao.debugMode.value); m_ShaderKeywords[5] = ShaderProperties.GetMultibounceKeyword(hbao.useMultiBounce.value, hbao.mode.value == HBAO.Mode.LitAO); m_ShaderKeywords[6] = ShaderProperties.GetOffscreenSamplesContributionKeyword(hbao.offscreenSamplesContribution.value); m_ShaderKeywords[7] = ShaderProperties.GetPerPixelNormalsKeyword(hbao.perPixelNormals.value); m_ShaderKeywords[8] = ShaderProperties.GetBlurRadiusKeyword(hbao.blurType.value); m_ShaderKeywords[9] = ShaderProperties.GetVarianceClippingKeyword(hbao.varianceClipping.value); m_ShaderKeywords[10] = ShaderProperties.GetColorBleedingKeyword(hbao.colorBleedingEnabled.value, hbao.mode.value == HBAO.Mode.LitAO); m_ShaderKeywords[11] = ShaderProperties.GetModeKeyword(hbao.mode.value); material.shaderKeywords = m_ShaderKeywords; } #endif private void CheckParameters() { if (hbao.deinterleaving.value != HBAO.Deinterleaving.Disabled && SystemInfo.supportedRenderTargetCount < 4) hbao.SetDeinterleaving(HBAO.Deinterleaving.Disabled); if (hbao.temporalFilterEnabled.value && !motionVectorsSupported) hbao.EnableTemporalFilter(false); if (hbao.colorBleedingEnabled.value && hbao.temporalFilterEnabled.value && SystemInfo.supportedRenderTargetCount < 2) hbao.EnableTemporalFilter(false); if (hbao.colorBleedingEnabled.value && hbao.mode.value == HBAO.Mode.LitAO) hbao.EnableColorBleeding(false); // Noise texture if (noiseTex == null || m_PreviousNoiseType != hbao.noiseType.value) { CoreUtils.Destroy(noiseTex); CreateNoiseTexture(); m_PreviousNoiseType = hbao.noiseType.value; } } private RenderTextureDescriptor GetStereoCompatibleDescriptor(int width, int height, RenderTextureFormat format = RenderTextureFormat.Default, int depthBufferBits = 0, RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default) { // Inherit the VR setup from the camera descriptor var desc = sourceDesc; desc.depthBufferBits = depthBufferBits; desc.msaaSamples = 1; desc.width = width; desc.height = height; desc.colorFormat = format; if (readWrite == RenderTextureReadWrite.sRGB) desc.sRGB = true; else if (readWrite == RenderTextureReadWrite.Linear) desc.sRGB = false; else if (readWrite == RenderTextureReadWrite.Default) desc.sRGB = isLinearColorSpace; return desc; } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, Mesh fullscreenTriangle, int passIndex = 0) { cmd.SetGlobalTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destination, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTexture source, RenderTargetIdentifier destination, Material material, Mesh fullscreenTriangle, int passIndex, MaterialPropertyBlock properties) { properties.SetTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex, properties); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Rect viewportRect, Material material, Mesh fullscreenTriangle, int passIndex = 0) { cmd.SetGlobalTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destination, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.SetViewport(viewportRect); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTexture source, RenderTargetIdentifier destination, Rect viewportRect, Material material, Mesh fullscreenTriangle, int passIndex, MaterialPropertyBlock properties) { properties.SetTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); cmd.SetViewport(viewportRect); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex, properties); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier[] destinations, Material material, Mesh fullscreenTriangle, int passIndex = 0) { cmd.SetGlobalTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destinations, destinations[0], 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTexture source, RenderTargetIdentifier[] destinations, Material material, Mesh fullscreenTriangle, int passIndex, MaterialPropertyBlock properties) { properties.SetTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destinations, destinations[0], 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex, properties); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier[] destinations, Rect viewportRect, Material material, Mesh fullscreenTriangle, int passIndex = 0) { cmd.SetGlobalTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destinations, destinations[0], 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.SetViewport(viewportRect); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex); } private static void BlitFullscreenTriangle(CommandBuffer cmd, RenderTexture source, RenderTargetIdentifier[] destinations, Rect viewportRect, Material material, Mesh fullscreenTriangle, int passIndex, MaterialPropertyBlock properties) { properties.SetTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destinations, destinations[0], 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.SetViewport(viewportRect); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex, properties); } private static void BlitFullscreenTriangleWithClear(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, Color clearColor, Mesh fullscreenTriangle, int passIndex = 0) { cmd.SetGlobalTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(destination, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices); cmd.ClearRenderTarget(false, true, clearColor); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex); } private static void BlitFullscreenTriangleWithClear(CommandBuffer cmd, RenderTexture source, RenderTargetIdentifier destination, Material material, Color clearColor, Mesh fullscreenTriangle, int passIndex, MaterialPropertyBlock properties) { properties.SetTexture(ShaderProperties.mainTex, source); cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store); cmd.ClearRenderTarget(false, true, clearColor); cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, material, 0, passIndex, properties); } private Vector2 AdjustBrightnessMaskToGammaSpace(Vector2 v) { return isLinearColorSpace ? v : ToGammaSpace(v); } private float ToGammaSpace(float v) { return Mathf.Pow(v, 0.454545454545455f); } private Vector2 ToGammaSpace(Vector2 v) { return new Vector2(ToGammaSpace(v.x), ToGammaSpace(v.y)); } private void CreateNoiseTexture() { noiseTex = new Texture2D(4, 4, SystemInfo.SupportsTextureFormat(TextureFormat.RGHalf) ? TextureFormat.RGHalf : TextureFormat.RGB24, false, true); noiseTex.filterMode = FilterMode.Point; noiseTex.wrapMode = TextureWrapMode.Repeat; int z = 0; for (int x = 0; x < 4; ++x) { for (int y = 0; y < 4; ++y) { float r1 = hbao.noiseType.value != HBAO.NoiseType.Dither ? 0.25f * (0.0625f * ((x + y & 3) << 2) + (x & 3)) : MersenneTwister.Numbers[z++]; float r2 = hbao.noiseType.value != HBAO.NoiseType.Dither ? 0.25f * ((y - x) & 3) : MersenneTwister.Numbers[z++]; Color color = new Color(r1, r2, 0); noiseTex.SetPixel(x, y, color); } } noiseTex.Apply(); for (int i = 0, j = 0; i < s_jitter.Length; ++i) { float r1 = MersenneTwister.Numbers[j++]; float r2 = MersenneTwister.Numbers[j++]; s_jitter[i] = new Vector2(r1, r2); } } } [SerializeField, HideInInspector] private Shader shader; private HBAORenderPass m_HBAORenderPass; void OnDisable() { m_HBAORenderPass?.Cleanup(); } public override void Create() { if (!isActive) { m_HBAORenderPass?.Cleanup(); m_HBAORenderPass = null; return; } name = "HBAO"; m_HBAORenderPass = new HBAORenderPass(); m_HBAORenderPass.FillSupportedRenderTextureFormats(); } protected override void Dispose(bool disposing) { m_HBAORenderPass?.Cleanup(); m_HBAORenderPass = null; } // Here you can inject one or multiple render passes in the renderer. // This method is called when setting up the renderer once per-camera. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { shader = Shader.Find("Hidden/Universal Render Pipeline/HBAO"); if (shader == null) { Debug.LogWarning("HBAO shader was not found. Please ensure it compiles correctly"); return; } if (renderingData.cameraData.postProcessEnabled) { m_HBAORenderPass.Setup(shader, renderer, renderingData); renderer.EnqueuePass(m_HBAORenderPass); } } } }