167 lines
6.5 KiB
C#
167 lines
6.5 KiB
C#
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|