Firstborn/Library/PackageCache/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/ScalableAO.cs

167 lines
6.5 KiB
C#
Raw Normal View History

2023-03-28 13:24:16 -04:00
using System;
namespace UnityEngine.Rendering.PostProcessing
{
// Scalable ambient obscurance
[UnityEngine.Scripting.Preserve]
[Serializable]
internal sealed class ScalableAO : IAmbientOcclusionMethod
{
RenderTexture m_Result;
PropertySheet m_PropertySheet;
AmbientOcclusion m_Settings;
readonly RenderTargetIdentifier[] m_MRT =
{
BuiltinRenderTextureType.GBuffer0, // Albedo, Occ
BuiltinRenderTextureType.CameraTarget // Ambient
};
readonly int[] m_SampleCount = { 4, 6, 10, 8, 12 };
enum Pass
{
OcclusionEstimationForward,
OcclusionEstimationDeferred,
HorizontalBlurForward,
HorizontalBlurDeferred,
VerticalBlur,
CompositionForward,
CompositionDeferred,
DebugOverlay
}
public ScalableAO(AmbientOcclusion settings)
{
m_Settings = settings;
}
public DepthTextureMode GetCameraFlags()
{
return DepthTextureMode.Depth | DepthTextureMode.DepthNormals;
}
void DoLazyInitialization(PostProcessRenderContext context)
{
m_PropertySheet = context.propertySheets.Get(context.resources.shaders.scalableAO);
bool reset = false;
if (m_Result == null || !m_Result.IsCreated())
{
// Initial allocation
m_Result = context.GetScreenSpaceTemporaryRT(0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
m_Result.hideFlags = HideFlags.DontSave;
m_Result.filterMode = FilterMode.Bilinear;
reset = true;
}
else if (m_Result.width != context.width || m_Result.height != context.height)
{
// Release and reallocate
m_Result.Release();
m_Result.width = context.width;
m_Result.height = context.height;
reset = true;
}
if (reset)
m_Result.Create();
}
void Render(PostProcessRenderContext context, CommandBuffer cmd, int occlusionSource)
{
DoLazyInitialization(context);
m_Settings.radius.value = Mathf.Max(m_Settings.radius.value, 1e-4f);
// Material setup
// Always use a quater-res AO buffer unless High/Ultra quality is set.
bool downsampling = (int)m_Settings.quality.value < (int)AmbientOcclusionQuality.High;
float px = m_Settings.intensity.value;
float py = m_Settings.radius.value;
float pz = downsampling ? 0.5f : 1f;
float pw = m_SampleCount[(int)m_Settings.quality.value];
var sheet = m_PropertySheet;
sheet.ClearKeywords();
sheet.properties.SetVector(ShaderIDs.AOParams, new Vector4(px, py, pz, pw));
sheet.properties.SetVector(ShaderIDs.AOColor, Color.white - m_Settings.color.value);
// In forward fog is applied at the object level in the grometry pass so we need to
// apply it to AO as well or it'll drawn on top of the fog effect.
// Not needed in Deferred.
if (context.camera.actualRenderingPath == RenderingPath.Forward && RenderSettings.fog)
{
sheet.EnableKeyword("APPLY_FORWARD_FOG");
sheet.properties.SetVector(
ShaderIDs.FogParams,
new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance)
);
}
// Texture setup
int ts = downsampling ? 2 : 1;
const RenderTextureFormat kFormat = RenderTextureFormat.ARGB32;
const RenderTextureReadWrite kRWMode = RenderTextureReadWrite.Linear;
const FilterMode kFilter = FilterMode.Bilinear;
// AO buffer
var rtMask = ShaderIDs.OcclusionTexture1;
int scaledWidth = context.width / ts;
int scaledHeight = context.height / ts;
context.GetScreenSpaceTemporaryRT(cmd, rtMask, 0, kFormat, kRWMode, kFilter, scaledWidth, scaledHeight);
// AO estimation
cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, rtMask, sheet, (int)Pass.OcclusionEstimationForward + occlusionSource);
// Blur buffer
var rtBlur = ShaderIDs.OcclusionTexture2;
context.GetScreenSpaceTemporaryRT(cmd, rtBlur, 0, kFormat, kRWMode, kFilter);
// Separable blur (horizontal pass)
cmd.BlitFullscreenTriangle(rtMask, rtBlur, sheet, (int)Pass.HorizontalBlurForward + occlusionSource);
cmd.ReleaseTemporaryRT(rtMask);
// Separable blur (vertical pass)
cmd.BlitFullscreenTriangle(rtBlur, m_Result, sheet, (int)Pass.VerticalBlur);
cmd.ReleaseTemporaryRT(rtBlur);
if (context.IsDebugOverlayEnabled(DebugOverlay.AmbientOcclusion))
context.PushDebugOverlay(cmd, m_Result, sheet, (int)Pass.DebugOverlay);
}
public void RenderAfterOpaque(PostProcessRenderContext context)
{
var cmd = context.command;
cmd.BeginSample("Ambient Occlusion");
Render(context, cmd, 0);
cmd.SetGlobalTexture(ShaderIDs.SAOcclusionTexture, m_Result);
cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionForward, RenderBufferLoadAction.Load);
cmd.EndSample("Ambient Occlusion");
}
public void RenderAmbientOnly(PostProcessRenderContext context)
{
var cmd = context.command;
cmd.BeginSample("Ambient Occlusion Render");
Render(context, cmd, 1);
cmd.EndSample("Ambient Occlusion Render");
}
public void CompositeAmbientOnly(PostProcessRenderContext context)
{
var cmd = context.command;
cmd.BeginSample("Ambient Occlusion Composite");
cmd.SetGlobalTexture(ShaderIDs.SAOcclusionTexture, m_Result);
cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_MRT, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionDeferred);
cmd.EndSample("Ambient Occlusion Composite");
}
public void Release()
{
RuntimeUtilities.Destroy(m_Result);
m_Result = null;
}
}
}