Rasagar/Library/PackageCache/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs
2024-09-27 20:27:46 +03:00

623 lines
30 KiB
C#

using System;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.PostProcessing
{
// Multi-scale volumetric obscurance
// TODO: Fix VR support
[UnityEngine.Scripting.Preserve]
[Serializable]
internal sealed class MultiScaleVO : IAmbientOcclusionMethod
{
internal enum MipLevel { Original, L1, L2, L3, L4, L5, L6 }
enum Pass
{
DepthCopy,
CompositionDeferred,
CompositionForward,
DebugOverlay
}
// The arrays below are reused between frames to reduce GC allocation.
readonly float[] m_SampleThickness =
{
Mathf.Sqrt(1f - 0.2f * 0.2f),
Mathf.Sqrt(1f - 0.4f * 0.4f),
Mathf.Sqrt(1f - 0.6f * 0.6f),
Mathf.Sqrt(1f - 0.8f * 0.8f),
Mathf.Sqrt(1f - 0.2f * 0.2f - 0.2f * 0.2f),
Mathf.Sqrt(1f - 0.2f * 0.2f - 0.4f * 0.4f),
Mathf.Sqrt(1f - 0.2f * 0.2f - 0.6f * 0.6f),
Mathf.Sqrt(1f - 0.2f * 0.2f - 0.8f * 0.8f),
Mathf.Sqrt(1f - 0.4f * 0.4f - 0.4f * 0.4f),
Mathf.Sqrt(1f - 0.4f * 0.4f - 0.6f * 0.6f),
Mathf.Sqrt(1f - 0.4f * 0.4f - 0.8f * 0.8f),
Mathf.Sqrt(1f - 0.6f * 0.6f - 0.6f * 0.6f)
};
readonly float[] m_InvThicknessTable = new float[12];
readonly float[] m_SampleWeightTable = new float[12];
readonly int[] m_Widths = new int[7];
readonly int[] m_Heights = new int[7];
// Scaled dimensions used with dynamic resolution
readonly int[] m_ScaledWidths = new int[7];
readonly int[] m_ScaledHeights = new int[7];
AmbientOcclusion m_Settings;
PropertySheet m_PropertySheet;
PostProcessResources m_Resources;
// Can't use a temporary because we need to share it between cmdbuffers - also fixes a weird
// command buffer warning
RenderTexture m_AmbientOnlyAO;
RenderTextureFormat m_R8Format;
RenderTextureFormat m_R16Format;
bool float4Texture = false;
readonly RenderTargetIdentifier[] m_MRT =
{
BuiltinRenderTextureType.GBuffer0, // Albedo, Occ
BuiltinRenderTextureType.CameraTarget // Ambient
};
public MultiScaleVO(AmbientOcclusion settings)
{
m_Settings = settings;
// R16 is not supported on all platforms as a storage texture format
// R8 is not supported on all platforms as a storage texture format
m_R8Format = RenderTextureFormat.R8;
m_R16Format = RenderTextureFormat.RHalf;
#if UNITY_2023_2_OR_NEWER
if (!SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(m_R8Format, false), GraphicsFormatUsage.LoadStore))
{
if (SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(RenderTextureFormat.ARGB32, false), GraphicsFormatUsage.LoadStore))
{
m_R8Format = RenderTextureFormat.ARGB32;
float4Texture = true;
}
}
if (!SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(m_R16Format, false), GraphicsFormatUsage.LoadStore))
{
if (SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(RenderTextureFormat.RFloat, false), GraphicsFormatUsage.LoadStore))
{
m_R16Format = RenderTextureFormat.RFloat;
}
}
#else
if (!SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(m_R8Format, false), FormatUsage.LoadStore))
{
if (SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(RenderTextureFormat.ARGB32, false), FormatUsage.LoadStore))
{
m_R8Format = RenderTextureFormat.ARGB32;
float4Texture = true;
}
}
if (!SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(m_R16Format, false), FormatUsage.LoadStore))
{
if (SystemInfo.IsFormatSupported(GraphicsFormatUtility.GetGraphicsFormat(RenderTextureFormat.RFloat, false), FormatUsage.LoadStore))
{
m_R16Format = RenderTextureFormat.RFloat;
}
}
#endif
}
public DepthTextureMode GetCameraFlags()
{
return DepthTextureMode.Depth;
}
// Special case for AO [because SRPs], please don't do this in other effects, it's bad
// practice in this framework
public void SetResources(PostProcessResources resources)
{
m_Resources = resources;
}
void Alloc(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav, bool dynamicScale)
{
int sizeId = (int)size;
cmd.GetTemporaryRT(id, new RenderTextureDescriptor
{
#if UNITY_2019_4_OR_NEWER
width = m_Widths[sizeId],
height = m_Heights[sizeId],
#else
width = m_ScaledWidths[sizeId],
height = m_ScaledHeights[sizeId],
#endif
colorFormat = format,
depthBufferBits = 0,
volumeDepth = 1,
autoGenerateMips = false,
msaaSamples = 1,
#if UNITY_2019_2_OR_NEWER
mipCount = 1,
#endif
#if UNITY_2019_4_OR_NEWER
useDynamicScale = dynamicScale,
#endif
enableRandomWrite = uav,
dimension = TextureDimension.Tex2D,
sRGB = false
}, FilterMode.Point);
}
void AllocArray(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav, bool dynamicScale)
{
int sizeId = (int)size;
cmd.GetTemporaryRT(id, new RenderTextureDescriptor
{
#if UNITY_2019_4_OR_NEWER
width = m_Widths[sizeId],
height = m_Heights[sizeId],
#else
width = m_ScaledWidths[sizeId],
height = m_ScaledHeights[sizeId],
#endif
colorFormat = format,
depthBufferBits = 0,
volumeDepth = 16,
autoGenerateMips = false,
msaaSamples = 1,
#if UNITY_2019_2_OR_NEWER
mipCount = 1,
#endif
#if UNITY_2019_4_OR_NEWER
useDynamicScale = dynamicScale,
#endif
enableRandomWrite = uav,
dimension = TextureDimension.Tex2DArray,
sRGB = false
}, FilterMode.Point);
}
void Release(CommandBuffer cmd, int id)
{
cmd.ReleaseTemporaryRT(id);
}
// Calculate values in _ZBuferParams (built-in shader variable)
// We can't use _ZBufferParams in compute shaders, so this function is
// used to give the values in it to compute shaders.
Vector4 CalculateZBufferParams(Camera camera)
{
float fpn = camera.farClipPlane / camera.nearClipPlane;
if (SystemInfo.usesReversedZBuffer)
return new Vector4(fpn - 1f, 1f, 0f, 0f);
return new Vector4(1f - fpn, fpn, 0f, 0f);
}
float CalculateTanHalfFovHeight(Camera camera)
{
return 1f / camera.projectionMatrix[0, 0];
}
Vector2 GetSize(MipLevel mip)
{
return new Vector2(m_ScaledWidths[(int)mip], m_ScaledHeights[(int)mip]);
}
Vector3 GetSizeArray(MipLevel mip)
{
return new Vector3(m_ScaledWidths[(int)mip], m_ScaledHeights[(int)mip], 16);
}
public void GenerateAOMap(CommandBuffer cmd, Camera camera, RenderTargetIdentifier destination, RenderTargetIdentifier? depthMap, bool invert, bool isMSAA)
{
// Base size
m_Widths[0] = m_ScaledWidths[0] = camera.pixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
m_Heights[0] = m_ScaledHeights[0] = camera.pixelHeight;
#if UNITY_2017_3_OR_NEWER
m_ScaledWidths[0] = camera.scaledPixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
m_ScaledHeights[0] = camera.scaledPixelHeight;
#endif
float widthScalingFactor = ScalableBufferManager.widthScaleFactor;
float heightScalingFactor = ScalableBufferManager.heightScaleFactor;
// L1 -> L6 sizes
for (int i = 1; i < 7; i++)
{
int div = 1 << i;
m_Widths[i] = (m_Widths[0] + (div - 1)) / div;
m_Heights[i] = (m_Heights[0] + (div - 1)) / div;
m_ScaledWidths[i] = Mathf.CeilToInt(m_Widths[i] * widthScalingFactor);
m_ScaledHeights[i] = Mathf.CeilToInt(m_Heights[i] * heightScalingFactor);
}
// Allocate temporary textures
PushAllocCommands(cmd, isMSAA, camera);
// Render logic
PushDownsampleCommands(cmd, camera, depthMap, isMSAA);
float tanHalfFovH = CalculateTanHalfFovHeight(camera);
PushRenderCommands(cmd, ShaderIDs.TiledDepth1, ShaderIDs.Occlusion1, GetSizeArray(MipLevel.L3), tanHalfFovH, isMSAA);
PushRenderCommands(cmd, ShaderIDs.TiledDepth2, ShaderIDs.Occlusion2, GetSizeArray(MipLevel.L4), tanHalfFovH, isMSAA);
PushRenderCommands(cmd, ShaderIDs.TiledDepth3, ShaderIDs.Occlusion3, GetSizeArray(MipLevel.L5), tanHalfFovH, isMSAA);
PushRenderCommands(cmd, ShaderIDs.TiledDepth4, ShaderIDs.Occlusion4, GetSizeArray(MipLevel.L6), tanHalfFovH, isMSAA);
PushUpsampleCommands(cmd, ShaderIDs.LowDepth4, ShaderIDs.Occlusion4, ShaderIDs.LowDepth3, ShaderIDs.Occlusion3, ShaderIDs.Combined3, GetSize(MipLevel.L4), GetSize(MipLevel.L3), isMSAA);
PushUpsampleCommands(cmd, ShaderIDs.LowDepth3, ShaderIDs.Combined3, ShaderIDs.LowDepth2, ShaderIDs.Occlusion2, ShaderIDs.Combined2, GetSize(MipLevel.L3), GetSize(MipLevel.L2), isMSAA);
PushUpsampleCommands(cmd, ShaderIDs.LowDepth2, ShaderIDs.Combined2, ShaderIDs.LowDepth1, ShaderIDs.Occlusion1, ShaderIDs.Combined1, GetSize(MipLevel.L2), GetSize(MipLevel.L1), isMSAA);
PushUpsampleCommands(cmd, ShaderIDs.LowDepth1, ShaderIDs.Combined1, ShaderIDs.LinearDepth, null, destination, GetSize(MipLevel.L1), GetSize(MipLevel.Original), isMSAA, invert);
// Cleanup
PushReleaseCommands(cmd);
}
void PushAllocCommands(CommandBuffer cmd, bool isMSAA, Camera camera)
{
bool dynamicResolutionEnabled = RuntimeUtilities.IsDynamicResolutionEnabled(camera);
if (isMSAA)
{
Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
}
else
{
Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, m_R16Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, m_R16Format, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, m_R16Format, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, m_R16Format, true, dynamicResolutionEnabled);
AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, m_R16Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, m_R8Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, m_R8Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, m_R8Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, m_R8Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, m_R8Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, m_R8Format, true, dynamicResolutionEnabled);
Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, m_R8Format, true, dynamicResolutionEnabled);
}
}
void PushDownsampleCommands(CommandBuffer cmd, Camera camera, RenderTargetIdentifier? depthMap, bool isMSAA)
{
RenderTargetIdentifier depthMapId;
bool needDepthMapRelease = false;
if (depthMap != null)
{
depthMapId = depthMap.Value;
}
else
{
// Make a copy of the depth texture, or reuse the resolved depth
// buffer (it's only available in some specific situations).
if (!RuntimeUtilities.IsResolvedDepthAvailable(camera))
{
Alloc(cmd, ShaderIDs.DepthCopy, MipLevel.Original, RenderTextureFormat.RFloat, false, RuntimeUtilities.IsDynamicResolutionEnabled(camera));
depthMapId = new RenderTargetIdentifier(ShaderIDs.DepthCopy);
cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, depthMapId, m_PropertySheet, (int)Pass.DepthCopy);
needDepthMapRelease = true;
}
else
{
depthMapId = BuiltinRenderTextureType.ResolvedDepth;
}
}
// 1st downsampling pass.
var cs = m_Resources.computeShaders.multiScaleAODownsample1;
int kernel = cs.FindKernel(isMSAA ? "MultiScaleVODownsample1_MSAA" : "MultiScaleVODownsample1");
cmd.SetComputeTextureParam(cs, kernel, "LinearZ", ShaderIDs.LinearDepth);
cmd.SetComputeTextureParam(cs, kernel, "DS2x", ShaderIDs.LowDepth1);
cmd.SetComputeTextureParam(cs, kernel, "DS2xAtlas", ShaderIDs.TiledDepth1);
cmd.SetComputeVectorParam(cs, "ZBufferParams", CalculateZBufferParams(camera));
cmd.SetComputeTextureParam(cs, kernel, "Depth", depthMapId);
cmd.SetComputeTextureParam(cs, kernel, "DS4x", ShaderIDs.LowDepth2);
cmd.SetComputeTextureParam(cs, kernel, "DS4xAtlas", ShaderIDs.TiledDepth2);
cmd.DispatchCompute(cs, kernel, m_ScaledWidths[(int)MipLevel.L4], m_ScaledHeights[(int)MipLevel.L4], 1);
if (needDepthMapRelease)
Release(cmd, ShaderIDs.DepthCopy);
// 2nd downsampling pass.
cs = m_Resources.computeShaders.multiScaleAODownsample2;
kernel = isMSAA ? cs.FindKernel("MultiScaleVODownsample2_MSAA") : cs.FindKernel("MultiScaleVODownsample2");
cmd.SetComputeTextureParam(cs, kernel, "DS4x", ShaderIDs.LowDepth2);
cmd.SetComputeTextureParam(cs, kernel, "DS8x", ShaderIDs.LowDepth3);
cmd.SetComputeTextureParam(cs, kernel, "DS16x", ShaderIDs.LowDepth4);
cmd.SetComputeTextureParam(cs, kernel, "DS8xAtlas", ShaderIDs.TiledDepth3);
cmd.SetComputeTextureParam(cs, kernel, "DS16xAtlas", ShaderIDs.TiledDepth4);
cmd.DispatchCompute(cs, kernel, m_ScaledWidths[(int)MipLevel.L6], m_ScaledHeights[(int)MipLevel.L6], 1);
}
void PushRenderCommands(CommandBuffer cmd, int source, int destination, Vector3 sourceSize, float tanHalfFovH, bool isMSAA)
{
// Here we compute multipliers that convert the center depth value into (the reciprocal
// of) sphere thicknesses at each sample location. This assumes a maximum sample radius
// of 5 units, but since a sphere has no thickness at its extent, we don't need to
// sample that far out. Only samples whole integer offsets with distance less than 25
// are used. This means that there is no sample at (3, 4) because its distance is
// exactly 25 (and has a thickness of 0.)
// The shaders are set up to sample a circular region within a 5-pixel radius.
const float kScreenspaceDiameter = 10f;
// SphereDiameter = CenterDepth * ThicknessMultiplier. This will compute the thickness
// of a sphere centered at a specific depth. The ellipsoid scale can stretch a sphere
// into an ellipsoid, which changes the characteristics of the AO.
// TanHalfFovH: Radius of sphere in depth units if its center lies at Z = 1
// ScreenspaceDiameter: Diameter of sample sphere in pixel units
// ScreenspaceDiameter / BufferWidth: Ratio of the screen width that the sphere actually covers
float thicknessMultiplier = 2f * tanHalfFovH * kScreenspaceDiameter / sourceSize.x;
if (RuntimeUtilities.isSinglePassStereoEnabled)
thicknessMultiplier *= 2f;
// This will transform a depth value from [0, thickness] to [0, 1].
float inverseRangeFactor = 1f / thicknessMultiplier;
// The thicknesses are smaller for all off-center samples of the sphere. Compute
// thicknesses relative to the center sample.
for (int i = 0; i < 12; i++)
m_InvThicknessTable[i] = inverseRangeFactor / m_SampleThickness[i];
// These are the weights that are multiplied against the samples because not all samples
// are equally important. The farther the sample is from the center location, the less
// they matter. We use the thickness of the sphere to determine the weight. The scalars
// in front are the number of samples with this weight because we sum the samples
// together before multiplying by the weight, so as an aggregate all of those samples
// matter more. After generating this table, the weights are normalized.
m_SampleWeightTable[0] = 4 * m_SampleThickness[0]; // Axial
m_SampleWeightTable[1] = 4 * m_SampleThickness[1]; // Axial
m_SampleWeightTable[2] = 4 * m_SampleThickness[2]; // Axial
m_SampleWeightTable[3] = 4 * m_SampleThickness[3]; // Axial
m_SampleWeightTable[4] = 4 * m_SampleThickness[4]; // Diagonal
m_SampleWeightTable[5] = 8 * m_SampleThickness[5]; // L-shaped
m_SampleWeightTable[6] = 8 * m_SampleThickness[6]; // L-shaped
m_SampleWeightTable[7] = 8 * m_SampleThickness[7]; // L-shaped
m_SampleWeightTable[8] = 4 * m_SampleThickness[8]; // Diagonal
m_SampleWeightTable[9] = 8 * m_SampleThickness[9]; // L-shaped
m_SampleWeightTable[10] = 8 * m_SampleThickness[10]; // L-shaped
m_SampleWeightTable[11] = 4 * m_SampleThickness[11]; // Diagonal
// Zero out the unused samples.
// FIXME: should we support SAMPLE_EXHAUSTIVELY mode?
m_SampleWeightTable[0] = 0;
m_SampleWeightTable[2] = 0;
m_SampleWeightTable[5] = 0;
m_SampleWeightTable[7] = 0;
m_SampleWeightTable[9] = 0;
// Normalize the weights by dividing by the sum of all weights
var totalWeight = 0f;
foreach (float w in m_SampleWeightTable)
totalWeight += w;
for (int i = 0; i < m_SampleWeightTable.Length; i++)
m_SampleWeightTable[i] /= totalWeight;
// Set the arguments for the render kernel.
var cs = m_Resources.computeShaders.multiScaleAORender;
string kernelName = isMSAA ? "MultiScaleVORender_MSAA_interleaved" : "MultiScaleVORender_interleaved";
if (float4Texture) kernelName += "_Float4";
int kernel = cs.FindKernel(kernelName);
cmd.SetComputeFloatParams(cs, "gInvThicknessTable", m_InvThicknessTable);
cmd.SetComputeFloatParams(cs, "gSampleWeightTable", m_SampleWeightTable);
cmd.SetComputeVectorParam(cs, "gInvSliceDimension", new Vector2(1f / sourceSize.x, 1f / sourceSize.y));
cmd.SetComputeVectorParam(cs, "AdditionalParams", new Vector3(-1f / m_Settings.thicknessModifier.value, m_Settings.intensity.value, m_Settings.zBias.value));
cmd.SetComputeTextureParam(cs, kernel, "DepthTex", source);
cmd.SetComputeTextureParam(cs, kernel, "Occlusion", destination);
// Calculate the thread group count and add a dispatch command with them.
uint xsize, ysize, zsize;
cs.GetKernelThreadGroupSizes(kernel, out xsize, out ysize, out zsize);
cmd.DispatchCompute(
cs, kernel,
((int)sourceSize.x + (int)xsize - 1) / (int)xsize,
((int)sourceSize.y + (int)ysize - 1) / (int)ysize,
((int)sourceSize.z + (int)zsize - 1) / (int)zsize
);
}
void PushUpsampleCommands(CommandBuffer cmd, int lowResDepth, int interleavedAO, int highResDepth, int? highResAO, RenderTargetIdentifier dest, Vector3 lowResDepthSize, Vector2 highResDepthSize, bool isMSAA, bool invert = false)
{
var cs = m_Resources.computeShaders.multiScaleAOUpsample;
int kernel = 0;
if (!isMSAA)
{
string kernelName = highResAO == null ? invert
? "MultiScaleVOUpSample_invert"
: "MultiScaleVOUpSample"
: "MultiScaleVOUpSample_blendout";
if (float4Texture)
{
kernelName += "_Float4";
}
kernel = cs.FindKernel(kernelName);
}
else
{
string kernelName = highResAO == null ? invert
? "MultiScaleVOUpSample_MSAA_invert"
: "MultiScaleVOUpSample_MSAA"
: "MultiScaleVOUpSample_MSAA_blendout";
if (float4Texture)
{
kernelName += "_Float4";
}
kernel = cs.FindKernel(kernelName);
}
float stepSize = 1920f / lowResDepthSize.x;
float bTolerance = 1f - Mathf.Pow(10f, m_Settings.blurTolerance.value) * stepSize;
bTolerance *= bTolerance;
float uTolerance = Mathf.Pow(10f, m_Settings.upsampleTolerance.value);
float noiseFilterWeight = 1f / (Mathf.Pow(10f, m_Settings.noiseFilterTolerance.value) + uTolerance);
cmd.SetComputeVectorParam(cs, "InvLowResolution", new Vector2(1f / lowResDepthSize.x, 1f / lowResDepthSize.y));
cmd.SetComputeVectorParam(cs, "InvHighResolution", new Vector2(1f / highResDepthSize.x, 1f / highResDepthSize.y));
cmd.SetComputeVectorParam(cs, "AdditionalParams", new Vector4(noiseFilterWeight, stepSize, bTolerance, uTolerance));
cmd.SetComputeTextureParam(cs, kernel, "LoResDB", lowResDepth);
cmd.SetComputeTextureParam(cs, kernel, "HiResDB", highResDepth);
cmd.SetComputeTextureParam(cs, kernel, "LoResAO1", interleavedAO);
if (highResAO != null)
cmd.SetComputeTextureParam(cs, kernel, "HiResAO", highResAO.Value);
cmd.SetComputeTextureParam(cs, kernel, "AoResult", dest);
int xcount = ((int)highResDepthSize.x + 17) / 16;
int ycount = ((int)highResDepthSize.y + 17) / 16;
cmd.DispatchCompute(cs, kernel, xcount, ycount, 1);
}
void PushReleaseCommands(CommandBuffer cmd)
{
Release(cmd, ShaderIDs.LinearDepth);
Release(cmd, ShaderIDs.LowDepth1);
Release(cmd, ShaderIDs.LowDepth2);
Release(cmd, ShaderIDs.LowDepth3);
Release(cmd, ShaderIDs.LowDepth4);
Release(cmd, ShaderIDs.TiledDepth1);
Release(cmd, ShaderIDs.TiledDepth2);
Release(cmd, ShaderIDs.TiledDepth3);
Release(cmd, ShaderIDs.TiledDepth4);
Release(cmd, ShaderIDs.Occlusion1);
Release(cmd, ShaderIDs.Occlusion2);
Release(cmd, ShaderIDs.Occlusion3);
Release(cmd, ShaderIDs.Occlusion4);
Release(cmd, ShaderIDs.Combined1);
Release(cmd, ShaderIDs.Combined2);
Release(cmd, ShaderIDs.Combined3);
}
void PreparePropertySheet(PostProcessRenderContext context)
{
var sheet = context.propertySheets.Get(m_Resources.shaders.multiScaleAO);
sheet.ClearKeywords();
sheet.properties.SetVector(ShaderIDs.AOColor, Color.white - m_Settings.color.value);
m_PropertySheet = sheet;
}
void CheckAOTexture(PostProcessRenderContext context)
{
bool AOUpdateNeeded = m_AmbientOnlyAO == null || !m_AmbientOnlyAO.IsCreated() || m_AmbientOnlyAO.width != context.width || m_AmbientOnlyAO.height != context.height;
#if UNITY_2017_3_OR_NEWER
bool dynamicResolutionEnabled = RuntimeUtilities.IsDynamicResolutionEnabled(context.camera);
AOUpdateNeeded = AOUpdateNeeded || m_AmbientOnlyAO.useDynamicScale != dynamicResolutionEnabled;
#endif
if (AOUpdateNeeded)
{
RuntimeUtilities.Destroy(m_AmbientOnlyAO);
m_AmbientOnlyAO = new RenderTexture(context.width, context.height, 0, m_R8Format, RenderTextureReadWrite.Linear)
{
hideFlags = HideFlags.DontSave,
filterMode = FilterMode.Point,
enableRandomWrite = true,
#if UNITY_2017_3_OR_NEWER
useDynamicScale = dynamicResolutionEnabled
#endif
};
m_AmbientOnlyAO.Create();
}
}
void PushDebug(PostProcessRenderContext context)
{
if (context.IsDebugOverlayEnabled(DebugOverlay.AmbientOcclusion))
context.PushDebugOverlay(context.command, m_AmbientOnlyAO, m_PropertySheet, (int)Pass.DebugOverlay);
}
public void RenderAfterOpaque(PostProcessRenderContext context)
{
var cmd = context.command;
cmd.BeginSample("Ambient Occlusion");
SetResources(context.resources);
PreparePropertySheet(context);
CheckAOTexture(context);
// In Forward mode, 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.
if (context.camera.actualRenderingPath == RenderingPath.Forward && RenderSettings.fog)
{
m_PropertySheet.EnableKeyword("APPLY_FORWARD_FOG");
m_PropertySheet.properties.SetVector(
ShaderIDs.FogParams,
new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance)
);
}
GenerateAOMap(cmd, context.camera, m_AmbientOnlyAO, null, false, false);
PushDebug(context);
cmd.SetGlobalTexture(ShaderIDs.MSVOcclusionTexture, m_AmbientOnlyAO);
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");
SetResources(context.resources);
PreparePropertySheet(context);
CheckAOTexture(context);
GenerateAOMap(cmd, context.camera, m_AmbientOnlyAO, null, false, false);
PushDebug(context);
cmd.EndSample("Ambient Occlusion Render");
}
public void CompositeAmbientOnly(PostProcessRenderContext context)
{
var cmd = context.command;
cmd.BeginSample("Ambient Occlusion Composite");
cmd.SetGlobalTexture(ShaderIDs.MSVOcclusionTexture, m_AmbientOnlyAO);
cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_MRT, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionDeferred);
cmd.EndSample("Ambient Occlusion Composite");
}
public void Release()
{
RuntimeUtilities.Destroy(m_AmbientOnlyAO);
m_AmbientOnlyAO = null;
}
}
}