532 lines
29 KiB
C#
532 lines
29 KiB
C#
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
|
|
namespace UnityEngine.Rendering.Universal
|
|
{
|
|
// The Screen Space Ambient Occlusion (SSAO) Pass
|
|
internal class ScreenSpaceAmbientOcclusionPass : ScriptableRenderPass
|
|
{
|
|
// Private Variables
|
|
private readonly bool m_SupportsR8RenderTextureFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8);
|
|
private int m_BlueNoiseTextureIndex = 0;
|
|
private Material m_Material;
|
|
private Texture2D[] m_BlueNoiseTextures;
|
|
private Vector4[] m_CameraTopLeftCorner = new Vector4[2];
|
|
private Vector4[] m_CameraXExtent = new Vector4[2];
|
|
private Vector4[] m_CameraYExtent = new Vector4[2];
|
|
private Vector4[] m_CameraZExtent = new Vector4[2];
|
|
private BlurTypes m_BlurType = BlurTypes.Bilateral;
|
|
private Matrix4x4[] m_CameraViewProjections = new Matrix4x4[2];
|
|
private ProfilingSampler m_ProfilingSampler = ProfilingSampler.Get(URPProfileId.SSAO);
|
|
private RenderTextureDescriptor m_AOPassDescriptor;
|
|
private ScreenSpaceAmbientOcclusionSettings m_CurrentSettings;
|
|
|
|
// Constants
|
|
private const string k_SSAOTextureName = "_ScreenSpaceOcclusionTexture";
|
|
private const string k_AmbientOcclusionParamName = "_AmbientOcclusionParam";
|
|
|
|
// Statics
|
|
internal static readonly int s_AmbientOcclusionParamID = Shader.PropertyToID(k_AmbientOcclusionParamName);
|
|
private static readonly int s_SSAOParamsID = Shader.PropertyToID("_SSAOParams");
|
|
private static readonly int s_SSAOBlueNoiseParamsID = Shader.PropertyToID("_SSAOBlueNoiseParams");
|
|
private static readonly int s_BlueNoiseTextureID = Shader.PropertyToID("_BlueNoiseTexture");
|
|
private static readonly int s_SSAOFinalTextureID = Shader.PropertyToID(k_SSAOTextureName);
|
|
private static readonly int s_CameraViewXExtentID = Shader.PropertyToID("_CameraViewXExtent");
|
|
private static readonly int s_CameraViewYExtentID = Shader.PropertyToID("_CameraViewYExtent");
|
|
private static readonly int s_CameraViewZExtentID = Shader.PropertyToID("_CameraViewZExtent");
|
|
private static readonly int s_ProjectionParams2ID = Shader.PropertyToID("_ProjectionParams2");
|
|
private static readonly int s_CameraViewProjectionsID = Shader.PropertyToID("_CameraViewProjections");
|
|
private static readonly int s_CameraViewTopLeftCornerID = Shader.PropertyToID("_CameraViewTopLeftCorner");
|
|
private static readonly int s_CameraNormalsTextureID = Shader.PropertyToID("_CameraNormalsTexture");
|
|
|
|
// Enums
|
|
private enum BlurTypes
|
|
{
|
|
Bilateral,
|
|
Gaussian,
|
|
Kawase,
|
|
}
|
|
|
|
private enum ShaderPasses
|
|
{
|
|
AmbientOcclusion = 0,
|
|
|
|
BilateralBlurHorizontal = 1,
|
|
BilateralBlurVertical = 2,
|
|
BilateralBlurFinal = 3,
|
|
BilateralAfterOpaque = 4,
|
|
|
|
GaussianBlurHorizontal = 5,
|
|
GaussianBlurVertical = 6,
|
|
GaussianAfterOpaque = 7,
|
|
|
|
KawaseBlur = 8,
|
|
KawaseAfterOpaque = 9,
|
|
}
|
|
|
|
// Structs
|
|
private readonly struct SSAOMaterialParams
|
|
{
|
|
internal readonly bool orthographicCamera;
|
|
internal readonly bool aoBlueNoise;
|
|
internal readonly bool aoInterleavedGradient;
|
|
internal readonly bool sampleCountHigh;
|
|
internal readonly bool sampleCountMedium;
|
|
internal readonly bool sampleCountLow;
|
|
internal readonly bool sourceDepthNormals;
|
|
internal readonly bool sourceDepthHigh;
|
|
internal readonly bool sourceDepthMedium;
|
|
internal readonly bool sourceDepthLow;
|
|
internal readonly Vector4 ssaoParams;
|
|
|
|
internal SSAOMaterialParams(ScreenSpaceAmbientOcclusionSettings settings, bool isOrthographic)
|
|
{
|
|
bool isUsingDepthNormals = settings.Source == ScreenSpaceAmbientOcclusionSettings.DepthSource.DepthNormals;
|
|
float radiusMultiplier = settings.AOMethod == ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.BlueNoise ? 1.5f : 1;
|
|
orthographicCamera = isOrthographic;
|
|
aoBlueNoise = settings.AOMethod == ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.BlueNoise;
|
|
aoInterleavedGradient = settings.AOMethod == ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.InterleavedGradient;
|
|
sampleCountHigh = settings.Samples == ScreenSpaceAmbientOcclusionSettings.AOSampleOption.High;
|
|
sampleCountMedium = settings.Samples == ScreenSpaceAmbientOcclusionSettings.AOSampleOption.Medium;
|
|
sampleCountLow = settings.Samples == ScreenSpaceAmbientOcclusionSettings.AOSampleOption.Low;
|
|
sourceDepthNormals = settings.Source == ScreenSpaceAmbientOcclusionSettings.DepthSource.DepthNormals;
|
|
sourceDepthHigh = !isUsingDepthNormals && settings.NormalSamples == ScreenSpaceAmbientOcclusionSettings.NormalQuality.High;
|
|
sourceDepthMedium = !isUsingDepthNormals && settings.NormalSamples == ScreenSpaceAmbientOcclusionSettings.NormalQuality.Medium;
|
|
sourceDepthLow = !isUsingDepthNormals && settings.NormalSamples == ScreenSpaceAmbientOcclusionSettings.NormalQuality.Low;
|
|
ssaoParams = new Vector4(
|
|
settings.Intensity, // Intensity
|
|
settings.Radius * radiusMultiplier, // Radius
|
|
1.0f / (settings.Downsample ? 2 : 1), // Downsampling
|
|
settings.Falloff // Falloff
|
|
);
|
|
}
|
|
|
|
internal bool Equals(in SSAOMaterialParams other)
|
|
{
|
|
return orthographicCamera == other.orthographicCamera
|
|
&& aoBlueNoise == other.aoBlueNoise
|
|
&& aoInterleavedGradient == other.aoInterleavedGradient
|
|
&& sampleCountHigh == other.sampleCountHigh
|
|
&& sampleCountMedium == other.sampleCountMedium
|
|
&& sampleCountLow == other.sampleCountLow
|
|
&& sourceDepthNormals == other.sourceDepthNormals
|
|
&& sourceDepthHigh == other.sourceDepthHigh
|
|
&& sourceDepthMedium == other.sourceDepthMedium
|
|
&& sourceDepthLow == other.sourceDepthLow
|
|
&& ssaoParams == other.ssaoParams
|
|
;
|
|
}
|
|
}
|
|
private SSAOMaterialParams m_SSAOParamsPrev = new SSAOMaterialParams();
|
|
|
|
internal ScreenSpaceAmbientOcclusionPass()
|
|
{
|
|
m_CurrentSettings = new ScreenSpaceAmbientOcclusionSettings();
|
|
}
|
|
|
|
internal bool Setup(ScreenSpaceAmbientOcclusionSettings featureSettings, ScriptableRenderer renderer, Material material, Texture2D[] blueNoiseTextures)
|
|
{
|
|
m_BlueNoiseTextures = blueNoiseTextures;
|
|
m_Material = material;
|
|
m_CurrentSettings = featureSettings;
|
|
|
|
// RenderPass Event + Source Settings (Depth / Depth&Normals
|
|
if (renderer is UniversalRenderer { usesDeferredLighting: true })
|
|
{
|
|
renderPassEvent = m_CurrentSettings.AfterOpaque ? RenderPassEvent.AfterRenderingOpaques : RenderPassEvent.AfterRenderingPrePasses;
|
|
|
|
m_CurrentSettings.Source = ScreenSpaceAmbientOcclusionSettings.DepthSource.DepthNormals;
|
|
}
|
|
else
|
|
{
|
|
// 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 = m_CurrentSettings.AfterOpaque ? RenderPassEvent.BeforeRenderingTransparents : RenderPassEvent.AfterRenderingPrePasses + 1;
|
|
}
|
|
|
|
// Ask for a Depth or Depth + Normals textures
|
|
switch (m_CurrentSettings.Source)
|
|
{
|
|
case ScreenSpaceAmbientOcclusionSettings.DepthSource.Depth:
|
|
ConfigureInput(ScriptableRenderPassInput.Depth);
|
|
break;
|
|
case ScreenSpaceAmbientOcclusionSettings.DepthSource.DepthNormals:
|
|
ConfigureInput(ScriptableRenderPassInput.Depth | ScriptableRenderPassInput.Normal); // need depthNormal prepass for forward-only geometry
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
// Blur settings
|
|
switch (m_CurrentSettings.BlurQuality)
|
|
{
|
|
case ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.High:
|
|
m_BlurType = BlurTypes.Bilateral;
|
|
break;
|
|
case ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.Medium:
|
|
m_BlurType = BlurTypes.Gaussian;
|
|
break;
|
|
case ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.Low:
|
|
m_BlurType = BlurTypes.Kawase;
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
return m_Material != null
|
|
&& m_CurrentSettings.Intensity > 0.0f
|
|
&& m_CurrentSettings.Radius > 0.0f
|
|
&& m_CurrentSettings.Falloff > 0.0f;
|
|
}
|
|
|
|
private void SetupKeywordsAndParameters(ref ScreenSpaceAmbientOcclusionSettings settings, ref UniversalCameraData cameraData)
|
|
{
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
int eyeCount = cameraData.xr.enabled && cameraData.xr.singlePassEnabled ? 2 : 1;
|
|
#else
|
|
int eyeCount = 1;
|
|
#endif
|
|
|
|
for (int eyeIndex = 0; eyeIndex < eyeCount; eyeIndex++)
|
|
{
|
|
Matrix4x4 view = cameraData.GetViewMatrix(eyeIndex);
|
|
Matrix4x4 proj = cameraData.GetProjectionMatrix(eyeIndex);
|
|
m_CameraViewProjections[eyeIndex] = proj * view;
|
|
|
|
// camera view space without translation, used by SSAO.hlsl ReconstructViewPos() to calculate view vector.
|
|
Matrix4x4 cview = view;
|
|
cview.SetColumn(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
|
|
Matrix4x4 cviewProj = proj * cview;
|
|
Matrix4x4 cviewProjInv = cviewProj.inverse;
|
|
|
|
Vector4 topLeftCorner = cviewProjInv.MultiplyPoint(new Vector4(-1, 1, -1, 1));
|
|
Vector4 topRightCorner = cviewProjInv.MultiplyPoint(new Vector4(1, 1, -1, 1));
|
|
Vector4 bottomLeftCorner = cviewProjInv.MultiplyPoint(new Vector4(-1, -1, -1, 1));
|
|
Vector4 farCentre = cviewProjInv.MultiplyPoint(new Vector4(0, 0, 1, 1));
|
|
m_CameraTopLeftCorner[eyeIndex] = topLeftCorner;
|
|
m_CameraXExtent[eyeIndex] = topRightCorner - topLeftCorner;
|
|
m_CameraYExtent[eyeIndex] = bottomLeftCorner - topLeftCorner;
|
|
m_CameraZExtent[eyeIndex] = farCentre;
|
|
}
|
|
|
|
m_Material.SetVector(s_ProjectionParams2ID, new Vector4(1.0f / cameraData.camera.nearClipPlane, 0.0f, 0.0f, 0.0f));
|
|
m_Material.SetMatrixArray(s_CameraViewProjectionsID, m_CameraViewProjections);
|
|
m_Material.SetVectorArray(s_CameraViewTopLeftCornerID, m_CameraTopLeftCorner);
|
|
m_Material.SetVectorArray(s_CameraViewXExtentID, m_CameraXExtent);
|
|
m_Material.SetVectorArray(s_CameraViewYExtentID, m_CameraYExtent);
|
|
m_Material.SetVectorArray(s_CameraViewZExtentID, m_CameraZExtent);
|
|
|
|
if (settings.AOMethod == ScreenSpaceAmbientOcclusionSettings.AOMethodOptions.BlueNoise)
|
|
{
|
|
m_BlueNoiseTextureIndex = (m_BlueNoiseTextureIndex + 1) % m_BlueNoiseTextures.Length;
|
|
Texture2D noiseTexture = m_BlueNoiseTextures[m_BlueNoiseTextureIndex];
|
|
Vector4 blueNoiseParams = new Vector4(
|
|
cameraData.pixelWidth / (float)m_BlueNoiseTextures[m_BlueNoiseTextureIndex].width, // X Scale
|
|
cameraData.pixelHeight / (float)m_BlueNoiseTextures[m_BlueNoiseTextureIndex].height, // Y Scale
|
|
Random.value, // X Offset
|
|
Random.value // Y Offset
|
|
);
|
|
|
|
// For testing we use a single blue noise texture and a single set of blue noise params.
|
|
#if UNITY_INCLUDE_TESTS
|
|
noiseTexture = m_BlueNoiseTextures[0];
|
|
blueNoiseParams.z = 1;
|
|
blueNoiseParams.w = 1;
|
|
#endif
|
|
|
|
m_Material.SetTexture(s_BlueNoiseTextureID, noiseTexture);
|
|
m_Material.SetVector(s_SSAOBlueNoiseParamsID, blueNoiseParams);
|
|
}
|
|
|
|
// Setting keywords can be somewhat expensive on low-end platforms.
|
|
// Previous params are cached to avoid setting the same keywords every frame.
|
|
SSAOMaterialParams matParams = new SSAOMaterialParams(settings, cameraData.camera.orthographic);
|
|
bool ssaoParamsDirty = !m_SSAOParamsPrev.Equals(in matParams); // Checks if the parameters have changed.
|
|
bool isParamsPropertySet = m_Material.HasProperty(s_SSAOParamsID); // Checks if the parameters have been set on the material.
|
|
if (!ssaoParamsDirty && isParamsPropertySet)
|
|
return;
|
|
|
|
m_SSAOParamsPrev = matParams;
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_OrthographicCameraKeyword, matParams.orthographicCamera);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_AOBlueNoiseKeyword, matParams.aoBlueNoise);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_AOInterleavedGradientKeyword, matParams.aoInterleavedGradient);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SampleCountHighKeyword, matParams.sampleCountHigh);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SampleCountMediumKeyword, matParams.sampleCountMedium);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SampleCountLowKeyword, matParams.sampleCountLow);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SourceDepthNormalsKeyword, matParams.sourceDepthNormals);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SourceDepthHighKeyword, matParams.sourceDepthHigh);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SourceDepthMediumKeyword, matParams.sourceDepthMedium);
|
|
CoreUtils.SetKeyword(m_Material, ScreenSpaceAmbientOcclusion.k_SourceDepthLowKeyword, matParams.sourceDepthLow);
|
|
m_Material.SetVector(s_SSAOParamsID, matParams.ssaoParams);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------------------------------------
|
|
------------------------------------------------------------- RENDER-GRAPH --------------------------------------------------------------
|
|
----------------------------------------------------------------------------------------------------------------------------------------*/
|
|
|
|
private class SSAOPassData
|
|
{
|
|
internal bool afterOpaque;
|
|
internal ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions BlurQuality;
|
|
internal MaterialPropertyBlock materialPropertyBlock;
|
|
internal Material material;
|
|
internal float directLightingStrength;
|
|
internal TextureHandle cameraColor;
|
|
internal TextureHandle AOTexture;
|
|
internal TextureHandle finalTexture;
|
|
internal TextureHandle blurTexture;
|
|
internal TextureHandle cameraNormalsTexture;
|
|
internal UniversalCameraData cameraData;
|
|
}
|
|
|
|
private class SSAOBlurPassData
|
|
{
|
|
internal TextureHandle srcTexture;
|
|
internal TextureHandle dstTexture;
|
|
internal MaterialPropertyBlock materialPropertyBlock;
|
|
internal Material material;
|
|
internal UniversalCameraData cameraData;
|
|
internal int pass;
|
|
internal ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions BlurQuality;
|
|
internal bool afterOpaque;
|
|
}
|
|
|
|
private class SSAOFinalPassData
|
|
{
|
|
internal float directLightingStrength;
|
|
}
|
|
|
|
private void InitSSAOPassData(SSAOPassData data)
|
|
{
|
|
data.material = m_Material;
|
|
data.BlurQuality = m_CurrentSettings.BlurQuality;
|
|
data.afterOpaque = m_CurrentSettings.AfterOpaque;
|
|
data.directLightingStrength = m_CurrentSettings.DirectLightingStrength;
|
|
}
|
|
|
|
private void InitSSAOBlurPassData(SSAOBlurPassData data)
|
|
{
|
|
data.material = m_Material;
|
|
data.BlurQuality = m_CurrentSettings.BlurQuality;
|
|
data.afterOpaque = m_CurrentSettings.AfterOpaque;
|
|
}
|
|
|
|
private static Vector4 ComputeScaleBias(in TextureHandle source, bool yFlip)
|
|
{
|
|
RTHandle srcRTHandle = source;
|
|
Vector2 viewportScale;
|
|
if (srcRTHandle is { useScaling: true })
|
|
{
|
|
var scale = srcRTHandle.rtHandleProperties.rtHandleScale;
|
|
viewportScale.x = scale.x;
|
|
viewportScale.y = scale.y;
|
|
}
|
|
else
|
|
{
|
|
viewportScale = Vector2.one;
|
|
}
|
|
|
|
if (yFlip)
|
|
return new Vector4(viewportScale.x, -viewportScale.y, 0, viewportScale.y);
|
|
else
|
|
return new Vector4(viewportScale.x, viewportScale.y, 0, 0);
|
|
}
|
|
|
|
private static readonly int _BlitScaleBias = Shader.PropertyToID(nameof(_BlitScaleBias));
|
|
private static readonly int _BlitTexture = Shader.PropertyToID(nameof(_BlitTexture));
|
|
|
|
private void RecordBlurStep(RenderGraph renderGraph, UniversalCameraData cameraData, string blurPassName, in TextureHandle src, in TextureHandle dst, int pass, bool isLastPass)
|
|
{
|
|
using (var builder = renderGraph.AddRasterRenderPass<SSAOBlurPassData>(blurPassName, out var passData, m_ProfilingSampler))
|
|
{
|
|
// Fill in the Pass data...
|
|
InitSSAOBlurPassData(passData);
|
|
passData.srcTexture = src;
|
|
passData.dstTexture = dst;
|
|
passData.cameraData = cameraData;
|
|
passData.pass = pass;
|
|
passData.materialPropertyBlock ??= new();
|
|
|
|
builder.UseTexture(passData.srcTexture);
|
|
|
|
AccessFlags finalDstAccess = passData.afterOpaque && isLastPass ? AccessFlags.Write : AccessFlags.WriteAll;
|
|
builder.SetRenderAttachment(passData.dstTexture, 0, finalDstAccess);
|
|
|
|
builder.SetRenderFunc(static (SSAOBlurPassData data, RasterGraphContext ctx) =>
|
|
{
|
|
bool yFlip = ctx.GetTextureUVOrigin(in data.srcTexture) != ctx.GetTextureUVOrigin(in data.dstTexture);
|
|
Vector4 viewScaleBias = ComputeScaleBias(data.srcTexture, yFlip);
|
|
|
|
data.materialPropertyBlock.Clear();
|
|
data.materialPropertyBlock.SetVector(_BlitScaleBias, viewScaleBias);
|
|
data.materialPropertyBlock.SetTexture(_BlitTexture, data.srcTexture);
|
|
CoreUtils.DrawFullScreen(ctx.cmd, data.material, data.materialPropertyBlock, data.pass);
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc cref="IRenderGraphRecorder.RecordRenderGraph"/>
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
|
{
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
|
|
|
// Create the texture handles...
|
|
CreateRenderTextureHandles(renderGraph,
|
|
resourceData,
|
|
cameraData,
|
|
out TextureHandle aoTexture,
|
|
out TextureHandle blurTexture,
|
|
out TextureHandle finalTexture);
|
|
|
|
// Get the resources
|
|
TextureHandle cameraDepthTexture = resourceData.cameraDepthTexture;
|
|
TextureHandle cameraNormalsTexture = resourceData.cameraNormalsTexture;
|
|
|
|
// Update keywords and other shader params
|
|
SetupKeywordsAndParameters(ref m_CurrentSettings, ref cameraData);
|
|
|
|
using (var builder = renderGraph.AddRasterRenderPass<SSAOPassData>("Blit SSAO", out var passData, m_ProfilingSampler))
|
|
{
|
|
// Shader keyword changes are considered as global state modifications
|
|
builder.AllowGlobalStateModification(true);
|
|
|
|
// Fill in the Pass data...
|
|
InitSSAOPassData(passData);
|
|
passData.cameraColor = resourceData.cameraColor;
|
|
passData.AOTexture = aoTexture;
|
|
passData.finalTexture = finalTexture;
|
|
passData.blurTexture = blurTexture;
|
|
passData.cameraData = cameraData;
|
|
passData.materialPropertyBlock ??= new();
|
|
|
|
// Declare input textures
|
|
builder.SetRenderAttachment(passData.AOTexture, 0, AccessFlags.WriteAll);
|
|
|
|
// TODO: Refactor to eliminate the need for 'UseTexture'.
|
|
// Currently required only because 'PostProcessUtils.SetSourceSize' allocates an RTHandle,
|
|
// which expects a valid graphicsResource. Without this call, 'cameraColor.graphicsResource'
|
|
// may be null if it wasn't initialized in an earlier pass (e.g., DrawOpaque).
|
|
if (passData.cameraColor.IsValid())
|
|
builder.UseTexture(passData.cameraColor, AccessFlags.Read);
|
|
|
|
if (cameraDepthTexture.IsValid())
|
|
builder.UseTexture(cameraDepthTexture, AccessFlags.Read);
|
|
|
|
if (m_CurrentSettings.Source == ScreenSpaceAmbientOcclusionSettings.DepthSource.DepthNormals && cameraNormalsTexture.IsValid())
|
|
{
|
|
builder.UseTexture(cameraNormalsTexture, AccessFlags.Read);
|
|
passData.cameraNormalsTexture = cameraNormalsTexture;
|
|
}
|
|
|
|
builder.SetRenderFunc(static (SSAOPassData data, RasterGraphContext ctx) =>
|
|
{
|
|
// Setup
|
|
PostProcessUtils.SetGlobalShaderSourceSize(ctx.cmd, data.cameraData.cameraTargetDescriptor.width, data.cameraData.cameraTargetDescriptor.height, data.cameraColor);
|
|
|
|
data.materialPropertyBlock.Clear();
|
|
|
|
if (data.cameraNormalsTexture.IsValid())
|
|
data.materialPropertyBlock.SetTexture(s_CameraNormalsTextureID, data.cameraNormalsTexture);
|
|
|
|
Vector4 viewScaleBias = new(1, 1, 0, 0);
|
|
data.materialPropertyBlock.SetVector(_BlitScaleBias, viewScaleBias);
|
|
|
|
CoreUtils.DrawFullScreen(ctx.cmd, data.material, data.materialPropertyBlock, (int)ShaderPasses.AmbientOcclusion);
|
|
});
|
|
}
|
|
|
|
switch (m_CurrentSettings.BlurQuality)
|
|
{
|
|
case ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.High:
|
|
RecordBlurStep(renderGraph, cameraData, "Blur SSAO Horizontal (High)", aoTexture, blurTexture, (int)ShaderPasses.BilateralBlurHorizontal, false);
|
|
RecordBlurStep(renderGraph, cameraData, "Blur SSAO Vertical (High)", blurTexture, aoTexture, (int)ShaderPasses.BilateralBlurVertical, false);
|
|
RecordBlurStep(renderGraph, cameraData, "Blur SSAO Final (High)", aoTexture, finalTexture, (int)(m_CurrentSettings.AfterOpaque ? ShaderPasses.BilateralAfterOpaque : ShaderPasses.BilateralBlurFinal), true);
|
|
break;
|
|
case ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.Medium:
|
|
RecordBlurStep(renderGraph, cameraData, "Blur SSAO Horizontal (Medium)", aoTexture, blurTexture, (int)ShaderPasses.GaussianBlurHorizontal, false);
|
|
RecordBlurStep(renderGraph, cameraData, "Blur SSAO Final (Medium)", blurTexture, finalTexture, (int)(m_CurrentSettings.AfterOpaque ? ShaderPasses.GaussianAfterOpaque : ShaderPasses.GaussianBlurVertical), true);
|
|
break;
|
|
case ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.Low:
|
|
RecordBlurStep(renderGraph, cameraData, "Blur SSAO (Low)", aoTexture, finalTexture, (int)(m_CurrentSettings.AfterOpaque ? ShaderPasses.KawaseAfterOpaque : ShaderPasses.KawaseBlur), true);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
if (!m_CurrentSettings.AfterOpaque)
|
|
{
|
|
// Add cleanup pass to:
|
|
// - Set global keywords for next passes
|
|
// - Set global texture as there is a limitation in Render Graph where an input texture cannot be set as a global texture after the pass runs
|
|
// A Raster pass is used so it can be merged easily with the blur passes.
|
|
using (var builder = renderGraph.AddRasterRenderPass<SSAOFinalPassData>("Cleanup SSAO", out var passData, m_ProfilingSampler))
|
|
{
|
|
passData.directLightingStrength = m_CurrentSettings.DirectLightingStrength;
|
|
|
|
builder.AllowGlobalStateModification(true);
|
|
|
|
builder.UseTexture(finalTexture, AccessFlags.Read);
|
|
builder.SetGlobalTextureAfterPass(finalTexture, s_SSAOFinalTextureID);
|
|
|
|
builder.SetRenderFunc(static (SSAOFinalPassData data, RasterGraphContext ctx) =>
|
|
{
|
|
// We only want URP shaders to sample SSAO if After Opaque is disabled...
|
|
ctx.cmd.SetKeyword(ShaderGlobalKeywords.ScreenSpaceOcclusion, true);
|
|
ctx.cmd.SetGlobalVector(s_AmbientOcclusionParamID, new Vector4(1f, 0f, 0f, data.directLightingStrength));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateRenderTextureHandles(RenderGraph renderGraph, UniversalResourceData resourceData,
|
|
UniversalCameraData cameraData, out TextureHandle aoTexture, out TextureHandle blurTexture, out TextureHandle finalTexture)
|
|
{
|
|
// Descriptor for the final blur pass
|
|
RenderTextureDescriptor finalTextureDescriptor = cameraData.cameraTargetDescriptor;
|
|
finalTextureDescriptor.colorFormat = m_SupportsR8RenderTextureFormat ? RenderTextureFormat.R8 : RenderTextureFormat.ARGB32;
|
|
finalTextureDescriptor.depthStencilFormat = GraphicsFormat.None;
|
|
finalTextureDescriptor.msaaSamples = 1;
|
|
|
|
// Descriptor for the AO and Blur passes
|
|
int downsampleDivider = m_CurrentSettings.Downsample ? 2 : 1;
|
|
bool useRedComponentOnly = m_SupportsR8RenderTextureFormat && m_BlurType > BlurTypes.Bilateral;
|
|
|
|
RenderTextureDescriptor aoBlurDescriptor = finalTextureDescriptor;
|
|
aoBlurDescriptor.colorFormat = useRedComponentOnly ? RenderTextureFormat.R8 : RenderTextureFormat.ARGB32;
|
|
aoBlurDescriptor.width /= downsampleDivider;
|
|
aoBlurDescriptor.height /= downsampleDivider;
|
|
|
|
// Handles
|
|
aoTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, aoBlurDescriptor, "_SSAO_OcclusionTexture0", false, FilterMode.Bilinear);
|
|
finalTexture = m_CurrentSettings.AfterOpaque ? resourceData.activeColorTexture : UniversalRenderer.CreateRenderGraphTexture(renderGraph, finalTextureDescriptor, k_SSAOTextureName, false, FilterMode.Bilinear);
|
|
|
|
if (m_CurrentSettings.BlurQuality != ScreenSpaceAmbientOcclusionSettings.BlurQualityOptions.Low)
|
|
blurTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, aoBlurDescriptor, "_SSAO_OcclusionTexture1", false, FilterMode.Bilinear);
|
|
else
|
|
blurTexture = TextureHandle.nullHandle;
|
|
|
|
if (!m_CurrentSettings.AfterOpaque)
|
|
resourceData.ssaoTexture = finalTexture;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
|
{
|
|
if (cmd == null)
|
|
throw new ArgumentNullException("cmd");
|
|
|
|
if (!m_CurrentSettings.AfterOpaque)
|
|
cmd.SetKeyword(ShaderGlobalKeywords.ScreenSpaceOcclusion, false);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
m_SSAOParamsPrev = default;
|
|
}
|
|
}
|
|
}
|