You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
14 KiB
333 lines
14 KiB
using System;
|
|
using System.Runtime.InteropServices;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace FidelityFX
|
|
{
|
|
/// <summary>
|
|
/// Port of ffx_cacao.cpp/.h
|
|
/// </summary>
|
|
public static class Cacao
|
|
{
|
|
/// <summary>
|
|
/// Matrix to flip a couple of axes from Unity view space to CACAO's expected view space.
|
|
/// </summary>
|
|
public static Matrix4x4 UnityToCacaoViewMatrix = Matrix4x4.Scale(new Vector3(1f, -1f, -1f));
|
|
|
|
/// <summary>
|
|
/// The quality levels that FidelityFX CACAO can generate SSAO at. This affects the number of samples taken for generating SSAO.
|
|
/// </summary>
|
|
public enum Quality
|
|
{
|
|
Lowest = 0,
|
|
Low = 1,
|
|
Medium = 2,
|
|
High = 3,
|
|
Highest = 4,
|
|
}
|
|
|
|
/// <summary>
|
|
/// A structure for the settings used by FidelityFX CACAO. These settings may be updated with each draw call.
|
|
/// </summary>
|
|
[Serializable]
|
|
public struct Settings
|
|
{
|
|
[Range(0, 10), Tooltip("World (view) space size of the occlusion sphere.")]
|
|
public float radius;
|
|
|
|
[Range(0, 5), Tooltip("Effect strength linear multiplier.")]
|
|
public float shadowMultiplier;
|
|
|
|
[Range(0.5f, 5), Tooltip("Effect strength pow modifier.")]
|
|
public float shadowPower;
|
|
|
|
[Range(0, 1), Tooltip("Effect max limit (applied after multiplier but before blur).")]
|
|
public float shadowClamp;
|
|
|
|
[Range(0, 0.2f), Tooltip("Limits self-shadowing (makes the sampling area less of a hemisphere, more of a spherical cone, to avoid self-shadowing and various artifacts due to low tessellation and depth buffer imprecision, etc.).")]
|
|
public float horizonAngleThreshold;
|
|
|
|
[Range(0, 1000), Tooltip("Distance to start fading out the effect.")]
|
|
public float fadeOutFrom;
|
|
|
|
[Range(0, 1000), Tooltip("Distance at which the effect is faded out.")]
|
|
public float fadeOutTo;
|
|
|
|
[Tooltip("Effect quality, affects number of taps etc.")]
|
|
public Quality qualityLevel;
|
|
|
|
[Range(0, 1), Tooltip("Only for quality level Highest.")]
|
|
public float adaptiveQualityLimit;
|
|
|
|
[Range(0, 8), Tooltip("Number of edge-sensitive smart blur passes to apply.")]
|
|
public uint blurPassCount;
|
|
|
|
[Range(0, 1), Tooltip("How much to bleed over edges; 1: not at all, 0.5: half-half; 0.0: completely ignore edges.")]
|
|
public float sharpness;
|
|
|
|
[Range(0, Mathf.PI), Tooltip("Used to rotate sampling kernel; If using temporal AA / supersampling, suggested to rotate by ( (frame%3)/3.0*PI ) or similar. Kernel is already symmetrical, which is why we use PI and not 2*PI.")]
|
|
public float temporalSupersamplingAngleOffset;
|
|
|
|
[Range(0, 2), Tooltip("Used to scale sampling kernel; If using temporal AA / supersampling, suggested to scale by ( 1.0f + (((frame%3)-1.0)/3.0)*0.1 ) or similar.")]
|
|
public float temporalSupersamplingRadiusOffset;
|
|
|
|
[Range(0, 5), Tooltip("Used for high-res detail AO using neighboring depth pixels: adds a lot of detail but also reduces temporal stability (adds aliasing).")]
|
|
public float detailShadowStrength;
|
|
|
|
[Tooltip("This option should be set to true if FidelityFX-CACAO should reconstruct a normal buffer from the depth buffer. It is required to be true if no normal buffer is provided.")]
|
|
public bool generateNormals;
|
|
|
|
[Tooltip("Sigma squared value for use in bilateral upsampler giving Gaussian blur term. Should be greater than 0.0.")]
|
|
public float bilateralSigmaSquared;
|
|
|
|
[Tooltip("Sigma squared value for use in bilateral upsampler giving similarity weighting for neighbouring pixels. Should be greater than 0.0.")]
|
|
public float bilateralSimilarityDistanceSigma;
|
|
}
|
|
|
|
public static readonly Settings DefaultSettings = new()
|
|
{
|
|
radius = 1.2f,
|
|
shadowMultiplier = 1.0f,
|
|
shadowPower = 1.5f,
|
|
shadowClamp = 0.98f,
|
|
horizonAngleThreshold = 0.06f,
|
|
fadeOutFrom = 50f,
|
|
fadeOutTo = 300f,
|
|
qualityLevel = Quality.Highest,
|
|
adaptiveQualityLimit = 0.45f,
|
|
blurPassCount = 2,
|
|
sharpness = 0.98f,
|
|
temporalSupersamplingAngleOffset = 0f,
|
|
temporalSupersamplingRadiusOffset = 0f,
|
|
detailShadowStrength = 0.5f,
|
|
generateNormals = false,
|
|
bilateralSigmaSquared = 5f,
|
|
bilateralSimilarityDistanceSigma = 0.01f,
|
|
};
|
|
|
|
/// <summary>
|
|
/// The parameters necessary when changing the screen size of FidelityFX CACAO.
|
|
/// </summary>
|
|
public struct ScreenSizeInfo
|
|
{
|
|
public uint Width;
|
|
public uint Height;
|
|
public bool UseDownsampledSsao;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A structure containing all of the input and output render targets used by FidelityFX CACAO.
|
|
/// </summary>
|
|
public struct DispatchInfo
|
|
{
|
|
public ResourceView DepthView;
|
|
public ResourceView? NormalsView; // This will be ignored if GenerateNormals is true
|
|
public ResourceView OutputView;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A structure containing sizes of each of the buffers used by FidelityFX CACAO.
|
|
/// </summary>
|
|
internal struct BufferSizeInfo
|
|
{
|
|
public uint InputOutputBufferWidth;
|
|
public uint InputOutputBufferHeight;
|
|
|
|
public uint SsaoBufferWidth;
|
|
public uint SsaoBufferHeight;
|
|
|
|
public uint DepthBufferXOffset;
|
|
public uint DepthBufferYOffset;
|
|
|
|
public uint DepthBufferWidth;
|
|
public uint DepthBufferHeight;
|
|
|
|
public uint DeinterleavedDepthBufferXOffset;
|
|
public uint DeinterleavedDepthBufferYOffset;
|
|
|
|
public uint DeinterleavedDepthBufferWidth;
|
|
public uint DeinterleavedDepthBufferHeight;
|
|
|
|
public uint ImportanceMapWidth;
|
|
public uint ImportanceMapHeight;
|
|
|
|
public uint DownsampledSsaoBufferWidth;
|
|
public uint DownsampledSsaoBufferHeight;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A C# structure for the constant buffer used by FidelityFX CACAO.
|
|
/// </summary>
|
|
[Serializable, StructLayout(LayoutKind.Sequential)]
|
|
internal struct Constants
|
|
{
|
|
public Vector2 DepthUnpackConsts;
|
|
public Vector2 CameraTanHalfFOV;
|
|
|
|
public Vector2 NDCToViewMul;
|
|
public Vector2 NDCToViewAdd;
|
|
|
|
public Vector2 DepthBufferUVToViewMul;
|
|
public Vector2 DepthBufferUVToViewAdd;
|
|
|
|
public float EffectRadius;
|
|
public float EffectShadowStrength;
|
|
public float EffectShadowPow;
|
|
public float EffectShadowClamp;
|
|
|
|
public float EffectFadeOutMul;
|
|
public float EffectFadeOutAdd;
|
|
public float EffectHorizonAngleThreshold;
|
|
public float EffectSamplingRadiusNearLimitRec;
|
|
|
|
public float DepthPrecisionOffsetMod;
|
|
public float NegRecEffectRadius;
|
|
public float LoadCounterAvgDiv;
|
|
public float AdaptiveSampleCountLimit;
|
|
|
|
public float InvSharpness;
|
|
public int BlurNumPasses;
|
|
public float BilateralSigmaSquared;
|
|
public float BilateralSimilarityDistanceSigma;
|
|
|
|
public PatternRotScaleMatrices PatternRotScaleMatrices0;
|
|
public PatternRotScaleMatrices PatternRotScaleMatrices1;
|
|
public PatternRotScaleMatrices PatternRotScaleMatrices2;
|
|
public PatternRotScaleMatrices PatternRotScaleMatrices3;
|
|
|
|
public float NormalsUnpackMul;
|
|
public float NormalsUnpackAdd;
|
|
public float DetailAOStrength;
|
|
public int Dummy0;
|
|
|
|
public Vector2 SSAOBufferDimensions;
|
|
public Vector2 SSAOBufferInverseDimensions;
|
|
|
|
public Vector2 DepthBufferDimensions;
|
|
public Vector2 DepthBufferInverseDimensions;
|
|
|
|
public Vector2Int DepthBufferOffset;
|
|
public Vector2Int Pad;
|
|
|
|
public Vector4 PerPassFullResUVOffset0;
|
|
public Vector4 PerPassFullResUVOffset1;
|
|
public Vector4 PerPassFullResUVOffset2;
|
|
public Vector4 PerPassFullResUVOffset3;
|
|
|
|
public Vector2 InputOutputBufferDimensions;
|
|
public Vector2 InputOutputBufferInverseDimensions;
|
|
|
|
public Vector2 ImportanceMapDimensions;
|
|
public Vector2 ImportanceMapInverseDimensions;
|
|
|
|
public Vector2 DeinterleavedDepthBufferDimensions;
|
|
public Vector2 DeinterleavedDepthBufferInverseDimensions;
|
|
|
|
public Vector2 DeinterleavedDepthBufferOffset;
|
|
public Vector2 DeinterleavedDepthBufferNormalisedOffset;
|
|
|
|
public Matrix4x4 NormalsWorldToViewspaceMatrix;
|
|
|
|
public Vector4 RTHandleScale;
|
|
}
|
|
|
|
[Serializable, StructLayout(LayoutKind.Sequential)]
|
|
internal struct PatternRotScaleMatrices
|
|
{
|
|
// This is a really ugly solution, but fixed-size arrays are not blittable by Unity
|
|
public Vector4 PatternRotScaleMatrix0;
|
|
public Vector4 PatternRotScaleMatrix1;
|
|
public Vector4 PatternRotScaleMatrix2;
|
|
public Vector4 PatternRotScaleMatrix3;
|
|
public Vector4 PatternRotScaleMatrix4;
|
|
}
|
|
|
|
// Nasty workaround for the fact that we can't store these matrices in an array
|
|
internal static ref Vector4 GetPerPassFullResUVOffset(this ref Constants consts, int index)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
return ref consts.PerPassFullResUVOffset0;
|
|
case 1:
|
|
return ref consts.PerPassFullResUVOffset1;
|
|
case 2:
|
|
return ref consts.PerPassFullResUVOffset2;
|
|
case 3:
|
|
return ref consts.PerPassFullResUVOffset3;
|
|
default:
|
|
throw new IndexOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
// Nasty workaround for the fact that we can't store these matrices in an array
|
|
internal static ref PatternRotScaleMatrices GetPatternRotScaleMatrices(this ref Constants consts, int index)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
return ref consts.PatternRotScaleMatrices0;
|
|
case 1:
|
|
return ref consts.PatternRotScaleMatrices1;
|
|
case 2:
|
|
return ref consts.PatternRotScaleMatrices2;
|
|
case 3:
|
|
return ref consts.PatternRotScaleMatrices3;
|
|
default:
|
|
throw new IndexOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
// Nasty workaround for the fact that we can't store these matrices in an array
|
|
internal static ref Vector4 GetPatternRotScaleMatrix(this ref PatternRotScaleMatrices matrices, int index)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
return ref matrices.PatternRotScaleMatrix0;
|
|
case 1:
|
|
return ref matrices.PatternRotScaleMatrix1;
|
|
case 2:
|
|
return ref matrices.PatternRotScaleMatrix2;
|
|
case 3:
|
|
return ref matrices.PatternRotScaleMatrix3;
|
|
case 4:
|
|
return ref matrices.PatternRotScaleMatrix4;
|
|
default:
|
|
throw new IndexOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// An immutable structure wrapping all of the necessary information to bind a specific buffer or attachment of a render target to a compute shader.
|
|
/// </summary>
|
|
public readonly struct ResourceView
|
|
{
|
|
/// <summary>
|
|
/// This value is the equivalent of not setting any value at all; all struct fields will have their default values.
|
|
/// It does not refer to a valid texture, therefore any variable set to this value should be checked for IsValid and reassigned before being bound to a shader.
|
|
/// </summary>
|
|
public static readonly ResourceView Unassigned = new ResourceView(default);
|
|
|
|
/// <summary>
|
|
/// This value contains a valid texture reference that can be bound to a shader, however it is just an empty placeholder texture.
|
|
/// Binding this to a shader can be seen as setting the texture variable inside the shader to null.
|
|
/// </summary>
|
|
public static readonly ResourceView None = new ResourceView(BuiltinRenderTextureType.None);
|
|
|
|
public ResourceView(in RenderTargetIdentifier renderTarget, RenderTextureSubElement subElement = RenderTextureSubElement.Default, int mipLevel = 0)
|
|
{
|
|
RenderTarget = renderTarget;
|
|
SubElement = subElement;
|
|
MipLevel = mipLevel;
|
|
}
|
|
|
|
public bool IsValid => !RenderTarget.Equals(default);
|
|
|
|
public readonly RenderTargetIdentifier RenderTarget;
|
|
public readonly RenderTextureSubElement SubElement;
|
|
public readonly int MipLevel;
|
|
}
|
|
}
|
|
}
|