diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md
index 776cb94e3ef..759be1dbdc5 100644
--- a/com.unity.render-pipelines.high-definition/CHANGELOG.md
+++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md
@@ -96,6 +96,7 @@ The version number for this package has increased due to a version update of a r
- Added the support of eye shader for ray tracing.
- Exposed Refraction Model to the material UI when using a Lit ShaderGraph.
- Added bounding sphere support to screen-space axis-aligned bounding box generation pass.
+- Added new algorithm for SSR with temporal accumulation
### Fixed
- Fixed several issues with physically-based DoF (TAA ghosting of the CoC buffer, smooth layer transitions, etc)
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDRP-SSRImprovement.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDRP-SSRImprovement.png
new file mode 100644
index 00000000000..18c00a07e33
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDRP-SSRImprovement.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:62caf65f55dc28df7eb71470f257e5af5ca1c3174cb96f6700761c389cc45ab7
+size 739508
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Override-Screen-Space-Reflection.md b/com.unity.render-pipelines.high-definition/Documentation~/Override-Screen-Space-Reflection.md
index 06aeb4b3d74..7a5d80f6b4a 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/Override-Screen-Space-Reflection.md
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Override-Screen-Space-Reflection.md
@@ -27,6 +27,7 @@ HDRP uses the [Volume](Volumes.md) framework to calculate SSR, so to enable and
| **Property** | **Description** |
| ----------------------------- | ------------------------------------------------------------ |
| **Enable** | Indicates whether HDRP processes SSR for Cameras in the influence of this effect's Volume . |
+| **Algorithm** | Unity provide two algorithm 'Approximation' and 'PBR Accumulation'. 'Approximation' is the regular one which try to have fast and less precise, 'PBR Accumulation' provide a more precise SSR by accumulating through multiple frames (controlable with 'Accumulation Factor'). |
| **Minimum Smoothness** | Use the slider to set the minimum amount of surface smoothness at which HDRP performs SSR tracing. Lower values result in HDRP performing SSR tracing for less smooth GameObjects. |
| **Smoothness Fade Start** | Use the slider to set the smoothness value at which SSR reflections begin to fade out. Lower values result in HDRP fading out SSR reflections for less smooth GameObjects |
| **Reflect Sky** | Indicates whether HDRP should use SSR to handle sky reflection. If you disable this property, pixels that reflect the sky use the next level of the [reflection hierarchy](Reflection-in-HDRP.md#ReflectionHierarchy).
**Note**: SSR uses the depth buffer to calculate reflection and HDRP does not add transparent GameObjects to the depth buffer. If you enable this property, transparent GameObject that appear over the sky in the color buffer can cause visual artifacts and incorrect looking reflection. This is a common limitation for SSR techniques. |
@@ -34,6 +35,7 @@ HDRP uses the [Volume](Volumes.md) framework to calculate SSR, so to enable and
| **Object Thickness** | Use the slider to control the thickness of the GameObjects on screen. Because the SSR algorithm can not distinguish thin GameObjects from thick ones, this property helps trace rays behind GameObjects. The algorithm applies this property to every GameObject uniformly. |
| **Quality** | Specifies the quality level to use for this effect. Each quality level applies different preset values. Unity also stops you from editing the properties that the preset overrides. If you want to set your own values for every property, select **Custom**. |
| **Max Ray Steps** | Sets the maximum number of iterations that the algorithm can execute before it stops trying to find an intersection with a Mesh. For example, if you set the number of iterations to 1000 and the algorithm only needs 10 to find an intersection, the algorithm terminates after 10 iterations. If you set this value too low, the algorithm may terminate too early and abruptly stop reflections. |
+| **Accumulation Factor** | Use the slider to control the speed of converge. 0 means no accumulation. 1 means accumulation is very slow which is useful for fixed image. Use carefuly to find a balance between convergence and ghosting. The more rough the reflection surfaces is, the more accumulation it will need to have a converged image without noise. |
## Limitations
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/whats-new-10.md b/com.unity.render-pipelines.high-definition/Documentation~/whats-new-10.md
index 7e99eda0d7c..75dcb92d6b7 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/whats-new-10.md
+++ b/com.unity.render-pipelines.high-definition/Documentation~/whats-new-10.md
@@ -199,6 +199,12 @@ This version of HDRP introduces a new injection point for custom post-processing
HDRP, being a high-end modern renderer, contains a lot of compute shader passes. Up until now, to define variations of some compute shaders, HDRP had to manually declare new kernels for each variation. From this version, every compute shader in HDRP uses Unity's multi-compile API which makes maintenance easier, but more importantly allows HDRP to strip shaders that you do not need to improve compilation times.
+### Screen Space Reflection
+
+
+
+HDRP improves the Screen Space Reflection by providing a new implementation 'PBR Accumulation'
+
### Planar reflection probe filtering

diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs
index 78cfaa72336..fa82dd5a4d7 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs
@@ -9,6 +9,7 @@ namespace UnityEditor.Rendering.HighDefinition
class HDScreenSpaceReflectionEditor : VolumeComponentWithQualityEditor
{
SerializedDataParameter m_Enable;
+ SerializedDataParameter m_UsedAlgorithm;
SerializedDataParameter m_RayTracing;
// Shared data
@@ -20,6 +21,7 @@ class HDScreenSpaceReflectionEditor : VolumeComponentWithQualityEditor
SerializedDataParameter m_ScreenFadeDistance;
SerializedDataParameter m_RayMaxIterations;
SerializedDataParameter m_DepthBufferThickness;
+ SerializedDataParameter m_AccumulationFactor;
// Ray Tracing
SerializedDataParameter m_LayerMask;
@@ -41,6 +43,7 @@ public override void OnEnable()
{
var o = new PropertyFetcher(serializedObject);
m_Enable = Unpack(o.Find(x => x.enabled));
+ m_UsedAlgorithm = Unpack(o.Find(x => x.usedAlgorithm));
m_RayTracing = Unpack(o.Find(x => x.rayTracing));
// Shared data
@@ -52,6 +55,7 @@ public override void OnEnable()
m_DepthBufferThickness = Unpack(o.Find(x => x.depthBufferThickness));
m_RayMaxIterations = Unpack(o.Find(x => x.rayMaxIterations));
m_ScreenFadeDistance = Unpack(o.Find(x => x.screenFadeDistance));
+ m_AccumulationFactor = Unpack(o.Find(x => x.accumulationFactor));
// Generic ray tracing
m_LayerMask = Unpack(o.Find(x => x.layerMask));
@@ -72,12 +76,14 @@ public override void OnEnable()
base.OnEnable();
}
+ static public readonly GUIContent k_Algo = EditorGUIUtility.TrTextContent("Algorithm", "The screen space reflection algorithm used.");
static public readonly GUIContent k_RayTracingText = EditorGUIUtility.TrTextContent("Ray Tracing (Preview)", "Enable ray traced reflections.");
static public readonly GUIContent k_ReflectSkyText = EditorGUIUtility.TrTextContent("Reflect Sky", "When enabled, SSR handles sky reflection.");
static public readonly GUIContent k_LayerMaskText = EditorGUIUtility.TrTextContent("Layer Mask", "Layer mask used to include the objects for screen space reflection.");
static public readonly GUIContent k_MinimumSmoothnessText = EditorGUIUtility.TrTextContent("Minimum Smoothness", "Controls the smoothness value at which HDRP activates SSR and the smoothness-controlled fade out stops.");
static public readonly GUIContent k_SmoothnessFadeStartText = EditorGUIUtility.TrTextContent("Smoothness Fade Start", "Controls the smoothness value at which the smoothness-controlled fade out starts. The fade is in the range [Min Smoothness, Smoothness Fade Start].");
static public readonly GUIContent k_ScreenFaceDistanceText = EditorGUIUtility.TrTextContent("Screen Edge Fade Distance", "Controls the distance at which HDRP fades out SSR near the edge of the screen.");
+ static public readonly GUIContent k_AccumulationFactorText = EditorGUIUtility.TrTextContent("Accumulation Factor", "Controls Controls the amount of accumulation (0 no accumulation, 1 just accumulate).");
static public readonly GUIContent k_DepthBufferThicknessText = EditorGUIUtility.TrTextContent("Object Thickness", "Controls the typical thickness of objects the reflection rays may pass behind.");
static public readonly GUIContent k_RayMaxIterationsText = EditorGUIUtility.TrTextContent("Max Ray Steps", "Sets the maximum number of steps HDRP uses for raytracing. Affects both correctness and performance.");
static public readonly GUIContent k_RayLengthText = EditorGUIUtility.TrTextContent("Max Ray Length", "Controls the maximal length of reflection rays. The higher this value is, the more expensive ray traced reflections are.");
@@ -106,7 +112,6 @@ void RayTracingQualityModeGUI()
}
}
-
void RayTracingPerformanceModeGUI()
{
base.OnInspectorGUI();
@@ -191,12 +196,16 @@ public override void OnInspectorGUI()
}
else
{
+ PropertyField(m_UsedAlgorithm, k_Algo);
+
// Shared Data
PropertyField(m_MinSmoothness, k_MinimumSmoothnessText);
PropertyField(m_SmoothnessFadeStart, k_SmoothnessFadeStartText);
PropertyField(m_ReflectSky, k_ReflectSkyText);
m_SmoothnessFadeStart.value.floatValue = Mathf.Max(m_MinSmoothness.value.floatValue, m_SmoothnessFadeStart.value.floatValue);
- PropertyField(m_ScreenFadeDistance, k_ScreenFaceDistanceText);
+
+ if (m_UsedAlgorithm.value.intValue != (int)ScreenSpaceReflectionAlgorithm.PBRAccumulation)
+ PropertyField(m_ScreenFadeDistance, k_ScreenFaceDistanceText);
PropertyField(m_DepthBufferThickness, k_DepthBufferThicknessText);
m_DepthBufferThickness.value.floatValue = Mathf.Clamp(m_DepthBufferThickness.value.floatValue, 0.001f, 1.0f);
@@ -209,6 +218,8 @@ public override void OnInspectorGUI()
PropertyField(m_RayMaxIterations, k_RayMaxIterationsText);
m_RayMaxIterations.value.intValue = Mathf.Max(0, m_RayMaxIterations.value.intValue);
}
+ if (m_UsedAlgorithm.value.intValue == (int)ScreenSpaceReflectionAlgorithm.PBRAccumulation)
+ PropertyField(m_AccumulationFactor, k_AccumulationFactorText);
}
}
public override QualitySettingsBlob SaveCustomQualitySettingsAsObject(QualitySettingsBlob settings = null)
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs
index 5ecaa6689e3..9068e65dc45 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs
@@ -57,7 +57,7 @@ public enum FullScreenDebugMode
MinLightingFullScreenDebug,
/// Display Screen Space Ambient Occlusion buffer.
ScreenSpaceAmbientOcclusion,
- /// Display Screen Space Reflections buffer.
+ /// Display Screen Space Reflections buffer used for lighting.
ScreenSpaceReflections,
/// Display the Transparent Screen Space Reflections buffer.
TransparentScreenSpaceReflections,
@@ -116,7 +116,12 @@ public enum FullScreenDebugMode
/// Display specular Color validation mode.
ValidateSpecularColor,
/// Maximum Full Screen Material debug mode value (used internally).
- MaxMaterialFullScreenDebug
+ MaxMaterialFullScreenDebug,
+ // TODO: Move before count for 11.0
+ /// Display Screen Space Reflections buffer of the previous frame accumulated.
+ ScreenSpaceReflectionsPrev,
+ /// Display Screen Space Reflections buffer of the current frame hit.
+ ScreenSpaceReflectionsAccum
}
///
@@ -1944,7 +1949,7 @@ internal bool DebugNeedsExposure()
debugLighting == DebugLightingMode.DiffuseLighting || debugLighting == DebugLightingMode.SpecularLighting || debugLighting == DebugLightingMode.VisualizeCascade) ||
(data.lightingDebugSettings.overrideAlbedo || data.lightingDebugSettings.overrideNormal || data.lightingDebugSettings.overrideSmoothness || data.lightingDebugSettings.overrideSpecularColor || data.lightingDebugSettings.overrideEmissiveColor || data.lightingDebugSettings.overrideAmbientOcclusion) ||
(debugGBuffer == DebugViewGbuffer.BakeDiffuseLightingWithAlbedoPlusEmissive) || (data.lightingDebugSettings.debugLightFilterMode != DebugLightFilterMode.None) ||
- (data.fullScreenDebugMode == FullScreenDebugMode.PreRefractionColorPyramid || data.fullScreenDebugMode == FullScreenDebugMode.FinalColorPyramid || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceReflections || data.fullScreenDebugMode == FullScreenDebugMode.LightCluster || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceShadows || data.fullScreenDebugMode == FullScreenDebugMode.NanTracker || data.fullScreenDebugMode == FullScreenDebugMode.ColorLog) || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceGlobalIllumination ||
+ (data.fullScreenDebugMode == FullScreenDebugMode.PreRefractionColorPyramid || data.fullScreenDebugMode == FullScreenDebugMode.FinalColorPyramid || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceReflections || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceReflectionsPrev || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceReflectionsAccum || data.fullScreenDebugMode == FullScreenDebugMode.LightCluster || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceShadows || data.fullScreenDebugMode == FullScreenDebugMode.NanTracker || data.fullScreenDebugMode == FullScreenDebugMode.ColorLog) || data.fullScreenDebugMode == FullScreenDebugMode.ScreenSpaceGlobalIllumination ||
(debugLighting == DebugLightingMode.ProbeVolume || debugProbeVolume == ProbeVolumeDebugMode.VisualizeAtlas);
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl
index 17289409a65..8e3563cf69e 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl
@@ -37,6 +37,8 @@
#define FULLSCREENDEBUGMODE_VALIDATE_DIFFUSE_COLOR (27)
#define FULLSCREENDEBUGMODE_VALIDATE_SPECULAR_COLOR (28)
#define FULLSCREENDEBUGMODE_MAX_MATERIAL_FULL_SCREEN_DEBUG (29)
+#define FULLSCREENDEBUGMODE_SCREEN_SPACE_REFLECTIONS_PREV (30)
+#define FULLSCREENDEBUGMODE_SCREEN_SPACE_REFLECTIONS_ACCUM (31)
// Generated from UnityEngine.Rendering.HighDefinition.ShaderVariablesDebugDisplay
// PackingRules = Exact
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader
index d984b75900d..78157717bbe 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader
+++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader
@@ -306,7 +306,10 @@ Shader "Hidden/HDRP/DebugFullScreen"
return float4(fade.xxx, 0.0);
}
- if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_SCREEN_SPACE_REFLECTIONS || _FullScreenDebugMode == FULLSCREENDEBUGMODE_TRANSPARENT_SCREEN_SPACE_REFLECTIONS)
+ if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_SCREEN_SPACE_REFLECTIONS ||
+ _FullScreenDebugMode == FULLSCREENDEBUGMODE_SCREEN_SPACE_REFLECTIONS_PREV ||
+ _FullScreenDebugMode == FULLSCREENDEBUGMODE_SCREEN_SPACE_REFLECTIONS_ACCUM ||
+ _FullScreenDebugMode == FULLSCREENDEBUGMODE_TRANSPARENT_SCREEN_SPACE_REFLECTIONS)
{
float4 color = SAMPLE_TEXTURE2D_X(_DebugFullScreenTexture, s_point_clamp_sampler, input.texcoord) * GetCurrentExposureMultiplier();
return float4(color.rgb, 1.0f);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs
index 89b1f3c3c09..21f4a1c80d9 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs
@@ -1,8 +1,35 @@
using System;
+using System.Diagnostics;
using UnityEngine.Serialization;
namespace UnityEngine.Rendering.HighDefinition
{
+ ///
+ /// Screen Space Reflection Algorithm
+ ///
+ public enum ScreenSpaceReflectionAlgorithm
+ {
+ /// Legacy SSR approximation.
+ Approximation,
+ /// Screen Space Reflection, Physically Based with Accumulation through multiple frame.
+ PBRAccumulation
+ }
+
+ ///
+ /// Screen Space Reflection Algorithm Type volume parameter.
+ ///
+ [Serializable, DebuggerDisplay(k_DebuggerDisplay)]
+ public sealed class SSRAlgoParameter : VolumeParameter
+ {
+ ///
+ /// Screen Space Reflection Algorithm Type volume parameter constructor.
+ ///
+ /// SSR Algo Type parameter.
+ /// Initial override state.
+ public SSRAlgoParameter(ScreenSpaceReflectionAlgorithm value, bool overrideState = false)
+ : base(value, overrideState) { }
+ }
+
///
/// A volume component that holds settings for screen space reflection and ray traced reflections.
///
@@ -26,6 +53,9 @@ bool UsesRayTracing()
[Tooltip("Enable Screen Space Reflections.")]
public BoolParameter enabled = new BoolParameter(true);
+ /// Screen Space Reflections Algorithm used.
+ public SSRAlgoParameter usedAlgorithm = new SSRAlgoParameter(ScreenSpaceReflectionAlgorithm.Approximation);
+
///
/// Enable ray traced reflections.
///
@@ -78,6 +108,11 @@ public float smoothnessFadeStart
///
public ClampedFloatParameter screenFadeDistance = new ClampedFloatParameter(0.1f, 0.0f, 1.0f);
+ ///
+ /// Controls the amount of accumulation (0 no accumulation, 1 just accumulate)
+ ///
+ public ClampedFloatParameter accumulationFactor = new ClampedFloatParameter(0.75f, 0.0f, 1.0f);
+
///
/// Layer mask used to include the objects for screen space reflection.
///
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute
index eaf5cb19baa..d5ff83d685d 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute
@@ -1,20 +1,27 @@
-//--------------------------------------------------------------------------------------------------
+
// Definitions
//--------------------------------------------------------------------------------------------------
// #pragma enable_d3d11_debug_symbols
#pragma only_renderers d3d11 playstation xboxone vulkan metal switch
-#pragma kernel ScreenSpaceReflectionsTracing SSR_TRACE
-#pragma kernel ScreenSpaceReflectionsReprojection SSR_REPROJECT
+#pragma kernel ScreenSpaceReflectionsTracing SSR_TRACE
+#pragma kernel ScreenSpaceReflectionsReprojection SSR_REPROJECT
+#pragma kernel ScreenSpaceReflectionsAccumulate SSR_ACCUMULATE
#pragma multi_compile _ DEPTH_SOURCE_NOT_FROM_MIP_CHAIN
+#pragma multi_compile _ SSR_APPROX
// Tweak parameters.
// #define DEBUG
#define SSR_TRACE_BEHIND_OBJECTS
#define SSR_TRACE_TOWARDS_EYE
-#define SSR_TRACE_EPS 0.00024414 // 2^-12, should be good up to 4K
+#ifndef SSR_APPROX
+ #define SAMPLES_VNDF
+#endif
+#define SSR_TRACE_EPS 0.00024414 // 2^-12, should be good up to 4K
+#define MIN_GGX_ROUGHNESS 0.00001f
+#define MAX_GGX_ROUGHNESS 0.99999f
//--------------------------------------------------------------------------------------------------
// Included headers
@@ -27,7 +34,6 @@
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Builtin/BuiltinData.hlsl"
-
#ifdef DEBUG_DISPLAY
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Debug.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl"
@@ -35,6 +41,14 @@
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl"
+#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
+#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingSampling.hlsl"
+#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingCommon.hlsl"
+#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/PreIntegratedFGD/PreIntegratedFGD.cs.hlsl"
+#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/PreIntegratedFGD/PreIntegratedFGD.hlsl"
+
+#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntialiasing.hlsl"
+
//--------------------------------------------------------------------------------------------------
// Inputs & outputs
//--------------------------------------------------------------------------------------------------
@@ -60,9 +74,14 @@ TEXTURE2D_X(_DepthTexture);
#ifdef SSR_TRACE
TEXTURE2D_X_UINT2( _StencilTexture);
RW_TEXTURE2D_X(float2, _SsrHitPointTexture);
-#else
+#elif defined(SSR_REPROJECT)
TEXTURE2D_X( _SsrHitPointTexture);
- RW_TEXTURE2D_X(float4, _SsrLightingTextureRW); // ShaderVariablesScreenSpaceLighting.hlsl already pulls in a non-RW _SsrLightingTexture
+ RW_TEXTURE2D_X(float4, _SSRAccumTexture);
+#else //if defined(SSR_ACCUMULATE)
+ TEXTURE2D_X( _SsrHitPointTexture);
+ RW_TEXTURE2D_X(float4, _SsrAccumPrev);
+ RW_TEXTURE2D_X(float4, _SsrLightingTextureRW);
+ RW_TEXTURE2D_X(float4, _SSRAccumTexture);
#endif
TEXTURE2D_X( _SsrClearCoatMaskTexture);
@@ -70,9 +89,250 @@ TEXTURE2D_X(_DepthTexture);
StructuredBuffer _CoarseStencilBuffer;
//--------------------------------------------------------------------------------------------------
-// Implementation
+// Helpers
//--------------------------------------------------------------------------------------------------
+// Adapted from: "Sampling the GGX Distribution of Visible Normals", by E. Heitz
+// http://jcgt.org/published/0007/04/01/paper.pdf
+void SampleGGXVisibleNormal(float2 u,
+ float3 V,
+ float3x3 localToWorld,
+ float roughness,
+ out float3 localV,
+ out float3 localH,
+ out float VdotH)
+{
+ localV = mul(V, transpose(localToWorld));
+
+ // Construct an orthonormal basis around the stretched view direction
+ float3x3 viewToLocal;
+ viewToLocal[2] = normalize(float3(roughness * localV.x, roughness * localV.y, localV.z));
+ viewToLocal[0] = (viewToLocal[2].z < 0.9999) ? normalize(cross(float3(0, 0, 1), viewToLocal[2])) : float3(1, 0, 0);
+ viewToLocal[1] = cross(viewToLocal[2], viewToLocal[0]);
+
+ // Compute a sample point with polar coordinates (r, phi)
+ float r = sqrt(u.x);
+ float phi = 2.0 * PI * u.y;
+ float t1 = r * cos(phi);
+ float t2 = r * sin(phi);
+ float s = 0.5 * (1.0 + viewToLocal[2].z);
+ t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2;
+
+ // Reproject onto hemisphere
+ localH = t1 * viewToLocal[0] + t2 * viewToLocal[1] + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * viewToLocal[2];
+
+ // Transform the normal back to the ellipsoid configuration
+ localH = normalize(float3(roughness * localH.xy, max(0.0, localH.z)));
+
+ VdotH = saturate(dot(localV, localH));
+}
+
+float Lambda_GGX(float roughness,
+ float3 V)
+{
+ return 0.5 * (sqrt(1.0 + (Sq(roughness * V.x) + Sq(roughness * V.y)) / Sq(V.z)) - 1.0);
+}
+
+bool SampleGGX_VNDF(float roughness_,
+ float3x3 localToWorld,
+ float3 V,
+ float2 inputSample,
+ out float3 outgoingDir,
+ out float weight)
+{
+ float roughness = clamp(roughness_, MIN_GGX_ROUGHNESS, MAX_GGX_ROUGHNESS);
+
+ float VdotH;
+ float3 localV, localH;
+ SampleGGXVisibleNormal(inputSample, V, localToWorld, roughness, localV, localH, VdotH);
+
+ // Compute the reflection direction
+ float3 localL = 2.0 * VdotH * localH - localV;
+ outgoingDir = mul(localL, localToWorld);
+
+ if (localL.z < 0.001)
+ return false;
+
+ float pdfNoGV = D_GGX(localH.z, roughness);
+ float lambdaVPlusOne = Lambda_GGX(roughness, localV) + 1.0;
+
+ float lambdaL = Lambda_GGX(roughness, localL);
+
+ weight = 1.0f + lambdaL / lambdaVPlusOne;
+
+ if (weight < 0.001)
+ return false;
+
+ return true;
+}
+
+float PerceptualRoughnessFade(float perceptualRoughness, float fadeRcpLength, float fadeEndTimesRcpLength)
+{
+ float t = Remap10(perceptualRoughness, fadeRcpLength, fadeEndTimesRcpLength);
+ return Smoothstep01(t);
+}
+
+void GetHitInfos(uint2 positionSS, out float2 hitPositionNDC, out float srcPerceptualRoughness, out float3 positionWS, out float weight, out float3 N, out float3 L, out float3 V, out float NdotL, out float NdotH, out float VdotH, out float NdotV)
+{
+ float2 uv = float2(positionSS) * _RTHandleScale.xy;
+
+ hitPositionNDC = _SsrHitPointTexture[COORD_TEXTURE2D_X(positionSS)].xy;
+
+ float2 Xi;
+ Xi.x = GetBNDSequenceSample(positionSS, _FrameCount, 0);
+ Xi.y = GetBNDSequenceSample(positionSS, _FrameCount, 1);
+
+ NormalData normalData;
+ DecodeFromNormalBuffer(positionSS, normalData);
+
+ srcPerceptualRoughness = normalData.perceptualRoughness;
+
+ float roughness = PerceptualRoughnessToRoughness(normalData.perceptualRoughness);
+ float3x3 localToWorld = GetLocalFrame(normalData.normalWS);
+
+ Xi.x = lerp(Xi.x, 0.0f, srcPerceptualRoughness * 0.7f); // 0.7 is an arbitrary bias to reduce noise for high roughness
+
+#ifdef DEPTH_SOURCE_NOT_FROM_MIP_CHAIN
+ float deviceDepth = LOAD_TEXTURE2D_X(_DepthTexture, positionSS).r;
+#else
+ float deviceDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, positionSS).r;
+#endif
+
+ float2 positionNDC = positionSS * _ScreenSize.zw + (0.5 * _ScreenSize.zw);
+ positionWS = ComputeWorldSpacePosition(positionNDC, deviceDepth, UNITY_MATRIX_I_VP);
+ V = GetWorldSpaceNormalizeViewDir(positionWS);
+
+ N = normalData.normalWS;
+
+#ifdef SAMPLES_VNDF
+ float value;
+
+ SampleGGX_VNDF(roughness,
+ localToWorld,
+ V,
+ Xi,
+ L,
+ weight);
+
+ NdotV = dot(normalData.normalWS, V);
+ NdotL = dot(normalData.normalWS, L);
+ float3 H = normalize(V + L);
+ NdotH = dot(normalData.normalWS, H);
+ VdotH = dot(V, H);
+#else
+ SampleGGXDir(Xi, V, localToWorld, roughness, L, NdotL, NdotH, VdotH);
+
+ NdotV = dot(normalData.normalWS, V);
+ float Vg = V_SmithJointGGX(NdotL, NdotV, roughness);
+
+ weight = 4.0f * NdotL * VdotH * Vg / NdotH;
+#endif
+}
+
+float2 GetHitNDC(float2 positionNDC)
+{
+ // TODO: it's important to account for occlusion/disocclusion to avoid artifacts in motion.
+ // This would require keeping the depth buffer from the previous frame.
+ float2 motionVectorNDC;
+ DecodeMotionVector(SAMPLE_TEXTURE2D_X_LOD(_CameraMotionVectorsTexture, s_linear_clamp_sampler, min(positionNDC, 1.0f - 0.5f * _ScreenSize.zw) * _RTHandleScale.xy, 0), motionVectorNDC);
+ float2 prevFrameNDC = positionNDC - motionVectorNDC;
+ return prevFrameNDC;
+}
+
+float2 GetHitUV(float2 positionNDC)
+{
+ return GetHitNDC(positionNDC) * _ColorPyramidUvScaleAndLimitPrevFrame.xy;
+}
+
+float3 GetWorldSpacePosition(uint2 positionSS)
+{
+ float2 uv = float2(positionSS) * _RTHandleScale.xy;
+
+#ifdef DEPTH_SOURCE_NOT_FROM_MIP_CHAIN
+ float deviceDepth = LOAD_TEXTURE2D_X(_DepthTexture, positionSS).r;
+#else
+ float deviceDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, positionSS).r;
+#endif
+
+ float2 positionNDC = positionSS *_ScreenSize.zw + (0.5 * _ScreenSize.zw);
+
+ return ComputeWorldSpacePosition(positionNDC, deviceDepth, UNITY_MATRIX_I_VP);
+}
+
+float2 GetWorldSpacePoint(uint2 positionSS, out float3 positionSrcWS, out float3 positionDstWS)
+{
+ positionSrcWS = GetWorldSpacePosition(positionSS);
+
+ float2 hitData = _SsrHitPointTexture[COORD_TEXTURE2D_X(positionSS)].xy;
+ uint2 positionDstSS = (hitData.xy - (0.5 * _ScreenSize.zw)) / _ScreenSize.zw;
+
+ positionDstWS = GetWorldSpacePosition(positionDstSS);
+
+ return hitData.xy;
+}
+
+float GetTraceDistance(uint2 positionSS)
+{
+ float3 positionSrcWS;
+ float3 positionDstWS;
+ GetWorldSpacePoint(positionSS, positionSrcWS, positionDstWS);
+
+ return length(positionDstWS - positionSrcWS);
+}
+
+float3 GetHitColorFromUV(float2 prevFrameUV, float perceptualRoughness, out float opacity, int mipLevel = 0)
+{
+ float tmpCoef = PerceptualRoughnessFade(perceptualRoughness, _SsrRoughnessFadeRcpLength, _SsrRoughnessFadeEndTimesRcpLength);
+ opacity = EdgeOfScreenFade(prevFrameUV / _ColorPyramidUvScaleAndLimitPrevFrame.xy, _SsrEdgeFadeRcpLength) * tmpCoef;
+ return SAMPLE_TEXTURE2D_X_LOD(_ColorPyramidTexture, s_trilinear_clamp_sampler, prevFrameUV, mipLevel).rgb;
+}
+
+float3 GetHitColor(float2 hitPositionNDC, float perceptualRoughness, out float opacity, int mipLevel = 0)
+{
+ float2 prevFrameNDC = GetHitNDC(hitPositionNDC);
+ float2 prevFrameUV = prevFrameNDC * _ColorPyramidUvScaleAndLimitPrevFrame.xy;
+
+ float tmpCoef = PerceptualRoughnessFade(perceptualRoughness, _SsrRoughnessFadeRcpLength, _SsrRoughnessFadeEndTimesRcpLength);
+ opacity = EdgeOfScreenFade(prevFrameNDC, _SsrEdgeFadeRcpLength) * tmpCoef;
+ return SAMPLE_TEXTURE2D_X_LOD(_ColorPyramidTexture, s_trilinear_clamp_sampler, prevFrameUV, mipLevel).rgb;
+}
+
+float2 GetSampleInfo(uint2 positionSS, out float3 color, out float weight, out float opacity)
+{
+ float3 positionSrcWS;
+ float3 positionDstWS;
+ float2 hitData = GetWorldSpacePoint(positionSS, positionSrcWS, positionDstWS);
+
+ float3 V = GetWorldSpaceNormalizeViewDir(positionSrcWS);
+ float3 L = normalize(positionDstWS - positionSrcWS);
+ float3 H = normalize(V + L);
+
+ NormalData normalData;
+ DecodeFromNormalBuffer(positionSS, normalData);
+
+ float roughness = PerceptualRoughnessToRoughness(normalData.perceptualRoughness);
+
+ roughness = clamp(roughness, MIN_GGX_ROUGHNESS, MAX_GGX_ROUGHNESS);
+
+ float NdotV = dot(normalData.normalWS, V);
+ float NdotL = dot(normalData.normalWS, L);
+ float VdotH = dot(V, H);
+ float NdotH = dot(normalData.normalWS, H);
+ float Vg = V_SmithJointGGX(NdotL, NdotV, roughness);
+
+ float jac = 4.0 * NdotV;
+
+ float lambdaVPlusOne = Lambda_GGX(roughness, V) + 1.0;
+
+ float lambdaL = Lambda_GGX(roughness, L);
+
+ weight = 1.0f + lambdaL / lambdaVPlusOne;
+
+ color = GetHitColor(hitData.xy, normalData.perceptualRoughness, opacity, 0);
+
+ return hitData;
+}
+
void GetNormalAndPerceptualRoughness(uint2 positionSS, out float3 normalWS, out float perceptualRoughness)
{
// Load normal and perceptualRoughness.
@@ -90,8 +350,11 @@ void WriteDebugInfo(uint2 positionSS, float4 value)
#endif
}
-#define USE_COARSE_STENCIL 0
+//--------------------------------------------------------------------------------------------------
+// Implementation
+//--------------------------------------------------------------------------------------------------
+#define USE_COARSE_STENCIL 0
#ifdef SSR_TRACE
[numthreads(8, 8, 1)]
@@ -127,7 +390,8 @@ void ScreenSpaceReflectionsTracing(uint3 groupId : SV_GroupID,
return;
}
- float2 positionNDC = positionSS * _ScreenSize.zw + (0.5 * _ScreenSize.zw); // Should we precompute the half-texel bias? We seem to use it a lot.
+ NormalData normalData;
+ DecodeFromNormalBuffer(positionSS, normalData);
#ifdef DEPTH_SOURCE_NOT_FROM_MIP_CHAIN
float deviceDepth = LOAD_TEXTURE2D_X(_DepthTexture, positionSS).r;
@@ -135,21 +399,39 @@ void ScreenSpaceReflectionsTracing(uint3 groupId : SV_GroupID,
float deviceDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, positionSS).r;
#endif
- bool killRay = deviceDepth == UNITY_RAW_FAR_CLIP_VALUE;
-
+#ifdef SSR_APPROX
+ float2 positionNDC = positionSS * _ScreenSize.zw + (0.5 * _ScreenSize.zw); // Should we precompute the half-texel bias? We seem to use it a lot.
float3 positionWS = ComputeWorldSpacePosition(positionNDC, deviceDepth, UNITY_MATRIX_I_VP); // Jittered
- float3 V = GetWorldSpaceNormalizeViewDir(positionWS);
+ float3 V = GetWorldSpaceNormalizeViewDir(positionWS);
float3 N;
float perceptualRoughness;
GetNormalAndPerceptualRoughness(positionSS, N, perceptualRoughness);
+ float3 R = reflect(-V, N);
+#else
+ float weight;
+ float NdotL, NdotH, VdotH, NdotV;
+ float3 R, V, N;
+ float3 positionWS;
+ float2 hitPositionNDC;
+ float perceptualRoughness;
+ GetHitInfos(positionSS, hitPositionNDC, perceptualRoughness, positionWS, weight, N, R, V, NdotL, NdotH, VdotH, NdotV);
+
+ if (NdotL < 0.001f || weight < 0.001f)
+ {
+ WriteDebugInfo(positionSS, -1);
+ return;
+ }
+#endif
+
float3 camPosWS = GetCurrentViewPosition();
// Apply normal bias with the magnitude dependent on the distance from the camera.
// Unfortunately, we only have access to the shading normal, which is less than ideal...
- positionWS = camPosWS + (positionWS - camPosWS) * (1 - 0.001 * rcp(max(dot(N, V), FLT_EPS)));
+ positionWS = camPosWS + (positionWS - camPosWS) * (1 - 0.001 * rcp(max(dot(N, V), FLT_EPS)));
deviceDepth = ComputeNormalizedDeviceCoordinatesWithZ(positionWS, UNITY_MATRIX_VP).z;
+ bool killRay = deviceDepth == UNITY_RAW_FAR_CLIP_VALUE;
// Ref. #1: Michal Drobot - Quadtree Displacement Mapping with Height Blending.
// Ref. #2: Yasin Uludag - Hi-Z Screen-Space Cone-Traced Reflections.
@@ -159,9 +441,6 @@ void ScreenSpaceReflectionsTracing(uint3 groupId : SV_GroupID,
// We start tracing from the center of the current pixel, and do so up to the far plane.
float3 rayOrigin = float3(positionSS + 0.5, deviceDepth);
- // TODO: this does not match GGX.
- float3 R = reflect(-V, N);
-
float3 reflPosWS = positionWS + R;
float3 reflPosNDC = ComputeNormalizedDeviceCoordinatesWithZ(reflPosWS, UNITY_MATRIX_VP); // Jittered
float3 reflPosSS = float3(reflPosNDC.xy * _ScreenSize.xy, reflPosNDC.z);
@@ -315,29 +594,31 @@ void ScreenSpaceReflectionsTracing(uint3 groupId : SV_GroupID,
// recompute it using the last value of 't', which would result in an overshoot.
// It also needs to be precisely at the center of the pixel to avoid artifacts.
float2 hitPositionNDC = floor(rayPos.xy) * _ScreenSize.zw + (0.5 * _ScreenSize.zw); // Should we precompute the half-texel bias? We seem to use it a lot.
- _SsrHitPointTexture[COORD_TEXTURE2D_X(positionSS)] = hitPositionNDC;
+ _SsrHitPointTexture[COORD_TEXTURE2D_X(positionSS)] = hitPositionNDC.xy;
}
// If we do not hit anything, 'rayPos.xy' provides an indication where we stopped the search.
WriteDebugInfo(positionSS, float4(rayPos.xy, iterCount, hit ? 1 : 0));
}
-#else // SSR_REPROJECT
-
-float PerceptualRoughnessFade(float perceptualRoughness, float fadeRcpLength, float fadeEndTimesRcpLength)
-{
- float t = Remap10(perceptualRoughness, fadeRcpLength, fadeEndTimesRcpLength);
- return Smoothstep01(t);
-}
+#elif defined(SSR_REPROJECT)
[numthreads(8, 8, 1)]
void ScreenSpaceReflectionsReprojection(uint3 dispatchThreadId : SV_DispatchThreadID)
{
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
- uint2 positionSS = dispatchThreadId.xy;
- // TODO: this texture is sparse (mostly black). Can we avoid reading every texel? How about using Hi-S?
- float2 hitPositionNDC = LOAD_TEXTURE2D_X(_SsrHitPointTexture, positionSS).xy;
+ const uint2 positionSS0 = dispatchThreadId.xy;
+
+ float3 N;
+ float perceptualRoughness;
+ GetNormalAndPerceptualRoughness(positionSS0, N, perceptualRoughness);
+
+ // Compute the actual roughness
+ float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
+ roughness = clamp(roughness, MIN_GGX_ROUGHNESS, MAX_GGX_ROUGHNESS);
+
+ float2 hitPositionNDC = LOAD_TEXTURE2D_X(_SsrHitPointTexture, positionSS0).xy;
if (max(hitPositionNDC.x, hitPositionNDC.y) == 0)
{
@@ -345,25 +626,30 @@ void ScreenSpaceReflectionsReprojection(uint3 dispatchThreadId : SV_DispatchThre
return;
}
- // TODO: it's important to account for occlusion/disocclusion to avoid artifacts in motion.
- // This would require keeping the depth buffer from the previous frame.
+#ifdef DEPTH_SOURCE_NOT_FROM_MIP_CHAIN
+ float depthOrigin = LOAD_TEXTURE2D_X(_DepthTexture, positionSS0.xy).r;
+#else
+ float depthOrigin = LOAD_TEXTURE2D_X(_CameraDepthTexture, positionSS0.xy).r;
+#endif
+
+ PositionInputs posInputOrigin = GetPositionInput(positionSS0.xy, _ScreenSize.zw, depthOrigin, UNITY_MATRIX_I_VP, UNITY_MATRIX_V, uint2(8, 8));
+ float3 originWS = posInputOrigin.positionWS + _WorldSpaceCameraPos;
+
+ // TODO: this texture is sparse (mostly black). Can we avoid reading every texel? How about using Hi-S?
float2 motionVectorNDC;
DecodeMotionVector(SAMPLE_TEXTURE2D_X_LOD(_CameraMotionVectorsTexture, s_linear_clamp_sampler, min(hitPositionNDC, 1.0f - 0.5f * _ScreenSize.zw) * _RTHandleScale.xy, 0), motionVectorNDC);
float2 prevFrameNDC = hitPositionNDC - motionVectorNDC;
- float2 prevFrameUV = prevFrameNDC * _ColorPyramidUvScaleAndLimitPrevFrame.xy;
+ float2 prevFrameUV = prevFrameNDC * _ColorPyramidUvScaleAndLimitPrevFrame.xy;
// TODO: optimize with max().
if ((prevFrameUV.x < 0) || (prevFrameUV.x > _ColorPyramidUvScaleAndLimitPrevFrame.z) ||
(prevFrameUV.y < 0) || (prevFrameUV.y > _ColorPyramidUvScaleAndLimitPrevFrame.w))
{
- // Off-screen.
+ // Off-Screen.
return;
}
- float3 N;
- float perceptualRoughness;
- GetNormalAndPerceptualRoughness(positionSS, N, perceptualRoughness);
-
+#ifdef SSR_APPROX
// TODO: filtering is quite awful. Needs to be non-Gaussian, bilateral and anisotropic.
float mipLevel = lerp(0, _SsrColorPyramidMaxMip, perceptualRoughness);
@@ -379,8 +665,118 @@ void ScreenSpaceReflectionsReprojection(uint3 dispatchThreadId : SV_DispatchThre
color = isPosFin ? color : 0;
opacity = isPosFin ? opacity : 0;
- // Use premultiplied alpha.
- _SsrLightingTextureRW[COORD_TEXTURE2D_X(positionSS)] = float4(color, 1) * opacity;
+ _SSRAccumTexture[COORD_TEXTURE2D_X(positionSS0)] = float4(color, 1.0f) * opacity;
+#else
+ float3 color = 0.0f;
+
+ float4 accum = _SSRAccumTexture[COORD_TEXTURE2D_X(positionSS0)];
+
+#define BLOCK_SAMPLE_RADIUS 1
+ int samplesCount = 0;
+ float4 outputs = 0.0f;
+ float wAll = 0.0f;
+ for (int y = -BLOCK_SAMPLE_RADIUS; y <= BLOCK_SAMPLE_RADIUS; ++y)
+ {
+ for (int x = -BLOCK_SAMPLE_RADIUS; x <= BLOCK_SAMPLE_RADIUS; ++x)
+ {
+ if (abs(x) == abs(y) && abs(x) == 1)
+ continue;
+
+ uint2 positionSS = uint2(int2(positionSS0) + int2(x, y));
+
+ float3 color;
+ float opacity;
+ float weight;
+ float2 hitData = GetSampleInfo(positionSS, color, weight, opacity);
+ if (max(hitData.x, hitData.y) != 0.0f && opacity > 0.0f)
+ {
+ //// Note that the color pyramid uses it's own viewport scale, since it lives on the camera.
+ // Disable SSR for negative, infinite and NaN history values.
+ uint3 intCol = asuint(color);
+ bool isPosFin = Max3(intCol.r, intCol.g, intCol.b) < 0x7F800000;
+
+ float2 prevFrameUV = hitData * _ColorPyramidUvScaleAndLimitPrevFrame.xy;
+
+ color = isPosFin ? color : 0;
+
+ outputs += weight * float4(color, 1.0f);
+ wAll += weight;
+ }
+ }
+ }
+#undef BLOCK_SAMPLE_RADIUS
+
+ if (wAll > 0.0f)
+ {
+ uint3 intCol = asuint(outputs.rgb);
+ bool isPosFin = Max3(intCol.r, intCol.g, intCol.b) < 0x7F800000;
+
+ outputs.rgb = isPosFin ? outputs.rgb : 0;
+ wAll = isPosFin ? wAll : 0;
+
+ _SSRAccumTexture[COORD_TEXTURE2D_X(positionSS0)] = outputs / wAll;
+ }
+#endif
+}
+
+#elif defined(SSR_ACCUMULATE)
+
+[numthreads(8, 8, 1)]
+void ScreenSpaceReflectionsAccumulate(uint3 dispatchThreadId : SV_DispatchThreadID)
+{
+ UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
+ uint2 positionSS = dispatchThreadId.xy;
+
+ float3 N;
+ float perceptualRoughness0;
+ GetNormalAndPerceptualRoughness(positionSS, N, perceptualRoughness0);
+
+ // Compute the actual roughness
+ float roughness = PerceptualRoughnessToRoughness(perceptualRoughness0);
+ roughness = clamp(roughness, MIN_GGX_ROUGHNESS, MAX_GGX_ROUGHNESS);
+
+ float4 data0 = _SSRAccumTexture[COORD_TEXTURE2D_X(int2(positionSS))];
+
+ float2 hitPositionNDC = LOAD_TEXTURE2D_X(_SsrHitPointTexture, positionSS).xy;
+
+ // Compute the radius of the projected solid angle
+ float dist = GetTraceDistance(positionSS);
+
+ // Approximate the footprint based on the hit normal
+ float2 hitSS = (hitPositionNDC.xy - (0.5 * _ColorPyramidUvScaleAndLimitPrevFrame.zw)) / _ColorPyramidUvScaleAndLimitPrevFrame.zw;
+
+ NormalData hitNormalData;
+ DecodeFromNormalBuffer(hitSS, hitNormalData);
+ float3 hitN = hitNormalData.normalWS;
+
+ float4 original = _SSRAccumTexture[COORD_TEXTURE2D_X(positionSS)];
+ float4 previous = _SsrAccumPrev[COORD_TEXTURE2D_X(positionSS)];
+
+ float2 motionVectorNDC;
+ DecodeMotionVector(SAMPLE_TEXTURE2D_X_LOD(_CameraMotionVectorsTexture, s_linear_clamp_sampler, min(hitPositionNDC.xy, 1.0f - 0.5f * _ScreenSize.zw)* _RTHandleScale.xy, 0), motionVectorNDC);
+ float speedDst = length(motionVectorNDC);
+
+ float2 motionVectorCenterNDC;
+ float2 positionNDC = positionSS * _ScreenSize.zw + (0.5 * _ScreenSize.zw);
+ DecodeMotionVector(SAMPLE_TEXTURE2D_X_LOD(_CameraMotionVectorsTexture, s_linear_clamp_sampler, min(positionNDC, 1.0f - 0.5f * _ScreenSize.zw)* _RTHandleScale.xy, 0), motionVectorCenterNDC);
+ float speedSrc = length(motionVectorCenterNDC);
+ float speed = saturate((speedDst + speedDst) * 128.0f); // 128 is arbitrary
+
+ float coefExpAvg = lerp(_SsrAccumulationAmount, 1.0f, speed);
+
+ float4 result = lerp(previous, original, coefExpAvg);
+
+ uint3 intCol = asuint(result.rgb);
+ bool isPosFin = Max3(intCol.r, intCol.g, intCol.b) < 0x7F800000;
+
+ result.rgb = isPosFin ? result.rgb : 0;
+ result.w = isPosFin ? result.w : 0;
+
+ _SsrLightingTextureRW[COORD_TEXTURE2D_X(positionSS)] = result;
+ _SSRAccumTexture[COORD_TEXTURE2D_X(positionSS)] = result;
}
#endif
+
+#undef MIN_GGX_ROUGHNESS
+#undef MAX_GGX_ROUGHNESS
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs
index d0be0791579..0ed5a611b0b 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs
@@ -18,6 +18,6 @@ unsafe struct ShaderVariablesScreenSpaceReflection
public int _SsrDepthPyramidMaxMip;
public int _SsrColorPyramidMaxMip;
public int _SsrReflectsSky;
- public float _ScreenSpaceReflectionPad0;
+ public float _SsrAccumulationAmount;
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs.hlsl
index c9eb01809ca..770a0ab1865 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ShaderVariablesScreenSpaceReflection.cs.hlsl
@@ -19,7 +19,7 @@ CBUFFER_START(ShaderVariablesScreenSpaceReflection)
int _SsrDepthPyramidMaxMip;
int _SsrColorPyramidMaxMip;
int _SsrReflectsSky;
- float _ScreenSpaceReflectionPad0;
+ float _SsrAccumulationAmount;
CBUFFER_END
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs
index 9c29e1faf00..a9dd4aa4a13 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs
@@ -765,6 +765,34 @@ internal void AllocateAmbientOcclusionHistoryBuffer(float scaleFactor)
}
}
+ internal void AllocateScreenSpaceAccumulationHistoryBuffer(float scaleFactor)
+ {
+ if (scaleFactor != m_ScreenSpaceAccumulationResolutionScale || GetCurrentFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation) == null)
+ {
+ ReleaseHistoryFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+
+ var ssrAlloc = new ScreenSpaceAccumulationAllocator(scaleFactor);
+ AllocHistoryFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation, ssrAlloc.Allocator, 2);
+
+ m_ScreenSpaceAccumulationResolutionScale = scaleFactor;
+ }
+ }
+
+ #region Private API
+ // Workaround for the Allocator callback so it doesn't allocate memory because of the capture of scaleFactor.
+ struct ScreenSpaceAllocator
+ {
+ float scaleFactor;
+
+ public ScreenSpaceAllocator(float scaleFactor) => this.scaleFactor = scaleFactor;
+
+ public RTHandle Allocator(string id, int frameIndex, RTHandleSystem rtHandleSystem)
+ {
+ return rtHandleSystem.Alloc(Vector2.one * scaleFactor, TextureXR.slices, filterMode: FilterMode.Point, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, dimension: TextureXR.dimension, useDynamicScale: true, enableRandomWrite: true, name: string.Format("{0}_ScreenSpaceReflection history_{1}", id, frameIndex));
+ }
+ }
+ #endregion
+
internal void ReleaseHistoryFrameRT(int id)
{
m_HistoryRTSystem.ReleaseBuffer(id);
@@ -895,6 +923,18 @@ public RTHandle Allocator(string id, int frameIndex, RTHandleSystem rtHandleSyst
}
}
+ struct ScreenSpaceAccumulationAllocator
+ {
+ float scaleFactor;
+
+ public ScreenSpaceAccumulationAllocator(float scaleFactor) => this.scaleFactor = scaleFactor;
+
+ public RTHandle Allocator(string id, int frameIndex, RTHandleSystem rtHandleSystem)
+ {
+ return rtHandleSystem.Alloc(Vector2.one * scaleFactor, TextureXR.slices, filterMode: FilterMode.Point, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, dimension: TextureXR.dimension, useDynamicScale: true, enableRandomWrite: true, name: string.Format("{0}_SSR_Accum Packed history_{1}", id, frameIndex));
+ }
+ }
+
static Dictionary<(Camera, int), HDCamera> s_Cameras = new Dictionary<(Camera, int), HDCamera>();
static List<(Camera, int)> s_Cleanup = new List<(Camera, int)>(); // Recycled to reduce GC pressure
@@ -903,6 +943,9 @@ public RTHandle Allocator(string id, int frameIndex, RTHandleSystem rtHandleSyst
int m_NumColorPyramidBuffersAllocated = 0;
int m_NumVolumetricBuffersAllocated = 0;
float m_AmbientOcclusionResolutionScale = 0.0f; // Factor used to track if history should be reallocated for Ambient Occlusion
+ float m_ScreenSpaceAccumulationResolutionScale = 0.0f; // Use another scale if AO & SSR don't have the same resolution
+ public ScreenSpaceReflectionAlgorithm
+ currentSSRAlgorithm = ScreenSpaceReflectionAlgorithm.Approximation; // Store current algorithm which help to know if we trigger to reset history SSR Buffers
ViewConstants[] m_XRViewConstants;
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCameraFrameHistoryType.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCameraFrameHistoryType.cs
index 95c52429323..7c9b4b4703d 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCameraFrameHistoryType.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCameraFrameHistoryType.cs
@@ -44,6 +44,9 @@ public enum HDCameraFrameHistoryType
/// Temporal antialiasing history after DoF.
TemporalAntialiasingPostDoF,
/// Number of history buffers.
- Count
+ Count, // TODO: Obsolete
+ // TODO: Move before count for 11.0
+ /// Screen Space Reflection Accumulation.
+ ScreenSpaceReflectionAccumulation
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs
index ece21070aec..fd76c647433 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs
@@ -37,6 +37,7 @@ internal enum HDProfileId
SubsurfaceScattering,
SsrTracing,
SsrReprojection,
+ SsrAccumulate,
PrepareForTransparentSsr,
// SSGI
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs
index f2bbb4f9cc4..b44c4391829 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs
@@ -254,7 +254,7 @@ TextureHandle CreateDiffuseLightingBuffer(RenderGraph renderGraph, bool msaa)
return renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = !msaa,
bindTextureMS = msaa, enableMSAA = msaa, clearBuffer = true, clearColor = Color.clear, name = msaa ? "CameraSSSDiffuseLightingMSAA" : "CameraSSSDiffuseLighting" });
- }
+ }
class DeferredLightingPassData
{
@@ -398,9 +398,13 @@ class RenderSSRPassData
public TextureHandle colorPyramid;
public TextureHandle stencilBuffer;
public TextureHandle hitPointsTexture;
+ public TextureHandle ssrAccum;
public TextureHandle lightingTexture;
+ public TextureHandle ssrAccumPrev;
public TextureHandle clearCoatMask;
public ComputeBufferHandle coarseStencilBuffer;
+ public BlueNoise blueNoise;
+ public HDCamera hdCamera;
//public TextureHandle debugTexture;
}
@@ -433,15 +437,19 @@ TextureHandle RenderSSR( RenderGraph renderGraph,
// However if the generated HTile will be used for something else but SSR, this should be made NOT resolve only and
// re-enabled in the shader.
BuildCoarseStencilAndResolveIfNeeded(renderGraph, hdCamera, resolveOnly: true, ref prepassOutput);
-
}
using (var builder = renderGraph.AddRenderPass("Render SSR", out var passData))
{
builder.EnableAsyncCompute(hdCamera.frameSettings.SSRRunsAsync());
+ hdCamera.AllocateScreenSpaceAccumulationHistoryBuffer(1.0f);
+
var colorPyramid = renderGraph.ImportTexture(hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ColorBufferMipChain));
+ var ssrAccum = renderGraph.ImportTexture(hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation));
+ var ssrAccumPrev = renderGraph.ImportTexture(hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation));
+
passData.parameters = PrepareSSRParameters(hdCamera, m_DepthBufferMipChainInfo, transparent);
passData.depthBuffer = builder.ReadTexture(prepassOutput.depthBuffer);
passData.depthPyramid = builder.ReadTexture(prepassOutput.depthPyramidTexture);
@@ -457,19 +465,35 @@ TextureHandle RenderSSR( RenderGraph renderGraph,
else
passData.motionVectorsBuffer = builder.ReadTexture(renderGraph.defaultResources.blackTextureXR);
+ passData.hdCamera = hdCamera;
+ passData.blueNoise = GetBlueNoiseManager();
+
+ ScreenSpaceReflection ssrVolumeSettings = hdCamera.volumeStack.GetComponent();
+
// In practice, these textures are sparse (mostly black). Therefore, clearing them is fast (due to CMASK),
// and much faster than fully overwriting them from within SSR shaders.
passData.hitPointsTexture = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
- { colorFormat = GraphicsFormat.R16G16_UNorm, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Hit_Point_Texture" });
- passData.lightingTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
- { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Lighting_Texture" }));
- //passData.hitPointsTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
- // { colorFormat = GraphicsFormat.ARGBFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Debug_Texture" }));
+ { colorFormat = GraphicsFormat.R16G16_UNorm, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = transparent ? "SSR_Hit_Point_Texture_Trans" : "SSR_Hit_Point_Texture" });
+
+ if (ssrVolumeSettings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation)
+ {
+ passData.ssrAccum = builder.WriteTexture(ssrAccum);
+ passData.ssrAccumPrev = builder.WriteTexture(ssrAccumPrev);
+ passData.lightingTexture = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
+ { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Lighting_Texture" });
+ }
+ else
+ {
+ passData.lightingTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
+ { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Lighting_Texture" }));
+ }
builder.SetRenderFunc(
(RenderSSRPassData data, RenderGraphContext context) =>
{
RenderSSR(data.parameters,
+ data.hdCamera,
+ data.blueNoise,
data.depthBuffer,
data.depthPyramid,
data.normalBuffer,
@@ -478,12 +502,23 @@ TextureHandle RenderSSR( RenderGraph renderGraph,
data.stencilBuffer,
data.clearCoatMask,
data.colorPyramid,
+ data.ssrAccum,
data.lightingTexture,
+ data.ssrAccumPrev,
data.coarseStencilBuffer,
context.cmd, context.renderContext);
});
- result = passData.lightingTexture;
+ if (ssrVolumeSettings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation)
+ result = passData.ssrAccum;
+ else
+ result = passData.lightingTexture;
+
+ if (!transparent)
+ {
+ PushFullScreenDebugTexture(renderGraph, ssrAccum, FullScreenDebugMode.ScreenSpaceReflectionsAccum);
+ PushFullScreenDebugTexture(renderGraph, ssrAccumPrev, FullScreenDebugMode.ScreenSpaceReflectionsPrev);
+ }
}
if (!hdCamera.colorPyramidHistoryIsValid)
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
index fa9eddadf5c..47a899847e0 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
@@ -151,8 +151,9 @@ internal static Volume GetOrCreateDefaultVolume()
IBLFilterBSDF[] m_IBLFilterArray = null;
ComputeShader m_ScreenSpaceReflectionsCS { get { return defaultResources.shaders.screenSpaceReflectionsCS; } }
- int m_SsrTracingKernel = -1;
+ int m_SsrTracingKernel = -1;
int m_SsrReprojectionKernel = -1;
+ int m_SsrAccumulateKernel = -1;
Material m_ApplyDistortionMaterial;
@@ -490,8 +491,9 @@ public HDRenderPipeline(HDRenderPipelineAsset asset, HDRenderPipelineAsset defau
m_AmbientOcclusionSystem = new AmbientOcclusionSystem(asset, defaultResources);
// Initialize various compute shader resources
- m_SsrTracingKernel = m_ScreenSpaceReflectionsCS.FindKernel("ScreenSpaceReflectionsTracing");
+ m_SsrTracingKernel = m_ScreenSpaceReflectionsCS.FindKernel("ScreenSpaceReflectionsTracing");
m_SsrReprojectionKernel = m_ScreenSpaceReflectionsCS.FindKernel("ScreenSpaceReflectionsReprojection");
+ m_SsrAccumulateKernel = m_ScreenSpaceReflectionsCS.FindKernel("ScreenSpaceReflectionsAccumulate");
// General material
m_CameraMotionVectorsMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.cameraMotionVectorsPS);
@@ -749,7 +751,6 @@ void InitializeRenderTextures()
if (settings.supportSSR)
{
- // m_SsrDebugTexture = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: RenderTextureFormat.ARGBFloat, sRGB: false, enableRandomWrite: true, useDynamicScale: true, name: "SSR_Debug_Texture");
m_SsrHitPointTexture = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GraphicsFormat.R16G16_UNorm, enableRandomWrite: true, useDynamicScale: true, name: "SSR_Hit_Point_Texture");
m_SsrLightingTexture = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite: true, useDynamicScale: true, name: "SSR_Lighting_Texture");
}
@@ -1844,8 +1845,6 @@ void AddVisibleProbeVisibleIndexIfUpdateIsRequired(HDProbe probe, int visibleInI
if (m_FrameCount > 1 && visibility > 0.0f)
probe.SetIsRendered(m_FrameCount);
-
-
if (!renderRequestIndicesWhereTheProbeIsVisible.TryGetValue(probe, out var visibleInIndices))
{
visibleInIndices = ListPool<(int index, float weight)>.Get();
@@ -2333,7 +2332,6 @@ ref _cullingResults
}
-
void PropagateScreenSpaceShadowData()
{
// For every unique light that has been registered, update the previous transform
@@ -2670,7 +2668,6 @@ void Callback(CommandBuffer c, HDCamera cam)
RenderCameraMotionVectors(cullingResults, hdCamera, renderContext, cmd);
}
-
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.MotionVectors))
cmd.SetGlobalTexture(HDShaderIDs._CameraMotionVectorsTexture, m_SharedRTManager.GetMotionVectorsBuffer());
else
@@ -2694,7 +2691,6 @@ void Callback(CommandBuffer c, HDCamera cam)
hdCamera.volumeStack.GetComponent().enable.value &&
hdCamera.camera.cameraType != CameraType.Preview)
{
-
// We only request the light cluster if we are gonna use it for debug mode
if (FullScreenDebugMode.LightCluster == m_CurrentDebugDisplaySettings.data.fullScreenDebugMode && GetRayTracingClusterState())
{
@@ -2706,7 +2702,6 @@ void Callback(CommandBuffer c, HDCamera cam)
}
else
{
-
// When debug is enabled we need to clear otherwise we may see non-shadows areas with stale values.
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.ContactShadows) && m_CurrentDebugDisplaySettings.data.fullScreenDebugMode == FullScreenDebugMode.ContactShadows)
{
@@ -2719,7 +2714,7 @@ void Callback(CommandBuffer c, HDCamera cam)
if (hdCamera.IsSSREnabled())
BuildCoarseStencilAndResolveIfNeeded(hdCamera, cmd, resolveOnly: true);
- hdCamera.xr.StopSinglePass(cmd);
+ hdCamera.xr.StopSinglePass(cmd);
var buildLightListTask = new HDGPUAsyncTask("Build light list", ComputeQueueType.Background);
// It is important that this task is in the same queue as the build light list due to dependency it has on it. If really need to move it, put an extra fence to make sure buildLightListTask has finished.
@@ -2754,7 +2749,7 @@ void Callback(CommandBuffer c, HDGPUAsyncTaskParams a)
haveAsyncTaskWithShadows = true;
- void Callback(CommandBuffer c, HDGPUAsyncTaskParams a)
+ void Callback(CommandBuffer c, HDGPUAsyncTaskParams a)
=> RenderSSR(a.hdCamera, c, a.renderContext);
}
@@ -2870,7 +2865,6 @@ void Callback(CommandBuffer c, HDCamera cam)
SetContactShadowsTexture(hdCamera, m_ContactShadowBuffer, cmd);
-
if (hdCamera.frameSettings.SSRRunsAsync())
{
SSRTask.End(cmd, hdCamera);
@@ -2946,7 +2940,7 @@ void Callback(CommandBuffer c, HDCamera cam)
}
// We push the motion vector debug texture here as transparent object can overwrite the motion vector texture content.
- if(m_Asset.currentPlatformRenderPipelineSettings.supportMotionVectors)
+ if (m_Asset.currentPlatformRenderPipelineSettings.supportMotionVectors)
PushFullScreenDebugTexture(hdCamera, cmd, m_SharedRTManager.GetMotionVectorsBuffer(), FullScreenDebugMode.MotionVectors);
// Second resolve the color buffer for finishing the frame
@@ -4727,7 +4721,9 @@ struct RenderSSRParameters
public ComputeShader ssrCS;
public int tracingKernel;
public int reprojectionKernel;
+ public int accumulateKernel;
public bool transparentSSR;
+ public bool usePBRAlgo;
public int width, height, viewCount;
@@ -4744,7 +4740,9 @@ RenderSSRParameters PrepareSSRParameters(HDCamera hdCamera, in HDUtils.PackedMip
parameters.ssrCS = m_ScreenSpaceReflectionsCS;
parameters.tracingKernel = m_SsrTracingKernel;
parameters.reprojectionKernel = m_SsrReprojectionKernel;
+ parameters.accumulateKernel = m_SsrAccumulateKernel;
parameters.transparentSSR = transparentSSR;
+ parameters.usePBRAlgo = volumeSettings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation;
parameters.width = hdCamera.actualWidth;
parameters.height = hdCamera.actualHeight;
@@ -4769,6 +4767,10 @@ RenderSSRParameters PrepareSSRParameters(HDCamera hdCamera, in HDUtils.PackedMip
cb._ColorPyramidUvScaleAndLimitPrevFrame = HDUtils.ComputeViewportScaleAndLimit(hdCamera.historyRTHandleProperties.previousViewportSize, hdCamera.historyRTHandleProperties.previousRenderTargetSize);
cb._SsrColorPyramidMaxMip = hdCamera.colorPyramidHistoryMipCount - 1;
cb._SsrDepthPyramidMaxMip = depthPyramid.mipLevelCount - 1;
+ if (hdCamera.isFirstFrame || hdCamera.cameraFrameCount <= 2)
+ cb._SsrAccumulationAmount = 1.0f;
+ else
+ cb._SsrAccumulationAmount = Mathf.Pow(2, Mathf.Lerp(0.0f, -7.0f, volumeSettings.accumulationFactor.value));
parameters.offsetBufferData = depthPyramid.GetOffsetBufferData(m_DepthPyramidMipLevelOffsetsBuffer);
@@ -4776,6 +4778,8 @@ RenderSSRParameters PrepareSSRParameters(HDCamera hdCamera, in HDUtils.PackedMip
}
static void RenderSSR( in RenderSSRParameters parameters,
+ HDCamera hdCamera,
+ BlueNoise blueNoise,
RTHandle depthTexture,
RTHandle depthPyramid,
RTHandle normalBuffer,
@@ -4784,12 +4788,41 @@ static void RenderSSR( in RenderSSRParameters parameters,
RTHandle stencilBuffer,
RTHandle clearCoatMask,
RTHandle previousColorPyramid,
+ RTHandle ssrAccum,
RTHandle ssrLightingTexture,
+ RTHandle ssrAccumPrev,
ComputeBuffer coarseStencilBuffer,
CommandBuffer cmd,
ScriptableRenderContext renderContext)
{
var cs = parameters.ssrCS;
+ bool usePBRAlgo = parameters.usePBRAlgo;
+
+ ScreenSpaceReflection ssrSettings = hdCamera.volumeStack.GetComponent();
+
+ if (!parameters.transparentSSR)
+ {
+ bool ssrNeedReset = false;
+ if (ssrSettings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation &&
+ hdCamera.currentSSRAlgorithm == ScreenSpaceReflectionAlgorithm.Approximation)
+ ssrNeedReset = true;
+
+ hdCamera.currentSSRAlgorithm = ssrSettings.usedAlgorithm.value;
+
+ if (ssrSettings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation)
+ {
+ CoreUtils.SetRenderTarget(cmd, ssrAccum, ClearFlag.Color, Color.clear);
+ if (ssrNeedReset || hdCamera.isFirstFrame)
+ {
+ CoreUtils.SetRenderTarget(cmd, ssrAccumPrev, ClearFlag.Color, Color.clear);
+ }
+ }
+ }
+
+ if (!usePBRAlgo)
+ {
+ CoreUtils.SetKeyword(cmd, "SSR_APPROX", true);
+ }
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.SsrTracing)))
{
@@ -4817,6 +4850,8 @@ static void RenderSSR( in RenderSSRParameters parameters,
cmd.SetComputeBufferParam(cs, parameters.tracingKernel, HDShaderIDs._CoarseStencilBuffer, coarseStencilBuffer);
cmd.SetComputeBufferParam(cs, parameters.tracingKernel, HDShaderIDs._DepthPyramidMipLevelOffsets, parameters.offsetBufferData);
+ blueNoise.BindDitheredRNGData1SPP(cmd);
+
ConstantBuffer.Push(cmd, parameters.cb, cs, HDShaderIDs._ShaderVariablesScreenSpaceReflection);
cmd.DispatchCompute(cs, parameters.tracingKernel, HDUtils.DivRoundUp(parameters.width, 8), HDUtils.DivRoundUp(parameters.height, 8), parameters.viewCount);
@@ -4827,17 +4862,61 @@ static void RenderSSR( in RenderSSRParameters parameters,
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.SsrReprojection)))
{
- // cmd.SetComputeTextureParam(cs, kernel, "_SsrDebugTexture", m_SsrDebugTexture);
- cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._SsrHitPointTexture, SsrHitPointTexture);
- cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._SsrLightingTextureRW, ssrLightingTexture);
+ if (parameters.transparentSSR)
+ {
+ CoreUtils.SetKeyword(cmd, "DEPTH_SOURCE_NOT_FROM_MIP_CHAIN", true);
+ cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._DepthTexture, depthTexture);
+ }
+ cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._CameraDepthTexture, depthPyramid);
cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._ColorPyramidTexture, previousColorPyramid);
+ cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._NormalBufferTexture, normalBuffer);
+ cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._SsrHitPointTexture, SsrHitPointTexture);
+ if (usePBRAlgo)
+ cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._SSRAccumTexture, ssrAccum);
+ else
+ cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._SSRAccumTexture, ssrLightingTexture);
cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._SsrClearCoatMaskTexture, clearCoatMask);
cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._CameraMotionVectorsTexture, motionVectorsBuffer);
- cmd.SetComputeTextureParam(cs, parameters.reprojectionKernel, HDShaderIDs._NormalBufferTexture, normalBuffer);
ConstantBuffer.Push(cmd, parameters.cb, cs, HDShaderIDs._ShaderVariablesScreenSpaceReflection);
cmd.DispatchCompute(cs, parameters.reprojectionKernel, HDUtils.DivRoundUp(parameters.width, 8), HDUtils.DivRoundUp(parameters.height, 8), parameters.viewCount);
+
+ if (parameters.transparentSSR)
+ CoreUtils.SetKeyword(cmd, "DEPTH_SOURCE_NOT_FROM_MIP_CHAIN", false);
+ }
+
+ if (usePBRAlgo)
+ {
+ using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.SsrAccumulate)))
+ {
+ if (parameters.transparentSSR)
+ {
+ CoreUtils.SetKeyword(cmd, "DEPTH_SOURCE_NOT_FROM_MIP_CHAIN", true);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._DepthTexture, depthTexture);
+ }
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._CameraDepthTexture, depthPyramid);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._NormalBufferTexture, normalBuffer);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._ColorPyramidTexture, previousColorPyramid);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._SsrHitPointTexture, SsrHitPointTexture);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._SSRAccumTexture, ssrAccum);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._SsrLightingTextureRW, ssrLightingTexture);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._SsrAccumPrev, ssrAccumPrev);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._SsrClearCoatMaskTexture, clearCoatMask);
+ cmd.SetComputeTextureParam(cs, parameters.accumulateKernel, HDShaderIDs._CameraMotionVectorsTexture, motionVectorsBuffer);
+
+ ConstantBuffer.Push(cmd, parameters.cb, cs, HDShaderIDs._ShaderVariablesScreenSpaceReflection);
+
+ cmd.DispatchCompute(cs, parameters.accumulateKernel, HDUtils.DivRoundUp(parameters.width, 8), HDUtils.DivRoundUp(parameters.height, 8), parameters.viewCount);
+
+ if (parameters.transparentSSR)
+ CoreUtils.SetKeyword(cmd, "DEPTH_SOURCE_NOT_FROM_MIP_CHAIN", false);
+ }
+ }
+
+ if (!usePBRAlgo)
+ {
+ CoreUtils.SetKeyword(cmd, "SSR_APPROX", false);
}
}
@@ -4857,6 +4936,11 @@ void RenderSSR(HDCamera hdCamera, CommandBuffer cmd, ScriptableRenderContext ren
}
else
{
+ hdCamera.AllocateScreenSpaceAccumulationHistoryBuffer(1.0f);
+
+ RTHandle ssrAccumulation = hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+ RTHandle ssrAccumulationPrev = hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+
var previousColorPyramid = hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ColorBufferMipChain);
// Evaluate the clear coat mask texture based on the lit shader mode
@@ -4864,16 +4948,19 @@ void RenderSSR(HDCamera hdCamera, CommandBuffer cmd, ScriptableRenderContext ren
var parameters = PrepareSSRParameters(hdCamera, m_SharedRTManager.GetDepthBufferMipChainInfo(), false);
var motionVectors = m_Asset.currentPlatformRenderPipelineSettings.supportMotionVectors ? m_SharedRTManager.GetMotionVectorsBuffer() : TextureXR.GetBlackTexture();
- RenderSSR(parameters, m_SharedRTManager.GetDepthStencilBuffer(), m_SharedRTManager.GetDepthTexture(), m_SharedRTManager.GetNormalBuffer(), motionVectors, m_SsrHitPointTexture,
+ RenderSSR(parameters, hdCamera, GetBlueNoiseManager(), m_SharedRTManager.GetDepthStencilBuffer(), m_SharedRTManager.GetDepthTexture(), m_SharedRTManager.GetNormalBuffer(), motionVectors, m_SsrHitPointTexture,
m_SharedRTManager.GetStencilBuffer(hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA)), clearCoatMask, previousColorPyramid,
- m_SsrLightingTexture, m_SharedRTManager.GetCoarseStencilBuffer(), cmd, renderContext);
+ ssrAccumulation, m_SsrLightingTexture, ssrAccumulationPrev, m_SharedRTManager.GetCoarseStencilBuffer(), cmd, renderContext);
- if (!hdCamera.colorPyramidHistoryIsValid)
- {
- cmd.SetGlobalTexture(HDShaderIDs._SsrLightingTexture, TextureXR.GetClearTexture());
- hdCamera.colorPyramidHistoryIsValid = true; // For the next frame...
- }
- }
+ if (!hdCamera.colorPyramidHistoryIsValid)
+ {
+ cmd.SetGlobalTexture(HDShaderIDs._SsrLightingTexture, TextureXR.GetClearTexture());
+ hdCamera.colorPyramidHistoryIsValid = true; // For the next frame...
+ }
+
+ PushFullScreenDebugTexture(hdCamera, cmd, ssrAccumulation, FullScreenDebugMode.ScreenSpaceReflectionsAccum);
+ PushFullScreenDebugTexture(hdCamera, cmd, ssrAccumulationPrev, FullScreenDebugMode.ScreenSpaceReflectionsPrev);
+ }
cmd.SetGlobalTexture(HDShaderIDs._SsrLightingTexture, m_SsrLightingTexture);
PushFullScreenDebugTexture(hdCamera, cmd, m_SsrLightingTexture, FullScreenDebugMode.ScreenSpaceReflections);
@@ -4897,6 +4984,11 @@ void RenderSSRTransparent(HDCamera hdCamera, CommandBuffer cmd, ScriptableRender
// re-enabled in the shader.
BuildCoarseStencilAndResolveIfNeeded(hdCamera, cmd, resolveOnly: true);
+ hdCamera.AllocateScreenSpaceAccumulationHistoryBuffer(1.0f);
+
+ RTHandle ssrAccumulation = hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+ RTHandle ssrAccumulationPrev = hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+
// Before doing anything, we need to clear the target buffers and rebuild the depth pyramid for tracing
// NOTE: This is probably something we can avoid if we read from the depth buffer and traced on the pyramid without the transparent objects
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.PrepareForTransparentSsr)))
@@ -4910,8 +5002,8 @@ void RenderSSRTransparent(HDCamera hdCamera, CommandBuffer cmd, ScriptableRender
var previousColorPyramid = hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ColorBufferMipChain);
var parameters = PrepareSSRParameters(hdCamera, m_SharedRTManager.GetDepthBufferMipChainInfo(), true);
var motionVectors = m_Asset.currentPlatformRenderPipelineSettings.supportMotionVectors ? m_SharedRTManager.GetMotionVectorsBuffer() : TextureXR.GetBlackTexture();
- RenderSSR(parameters, m_SharedRTManager.GetDepthStencilBuffer(), m_SharedRTManager.GetDepthTexture(), m_SharedRTManager.GetNormalBuffer(), motionVectors,
- m_SsrHitPointTexture, m_SharedRTManager.GetStencilBuffer(), TextureXR.GetBlackTexture(), previousColorPyramid, m_SsrLightingTexture, m_SharedRTManager.GetCoarseStencilBuffer(), cmd, renderContext);
+ RenderSSR(parameters, hdCamera, GetBlueNoiseManager(), m_SharedRTManager.GetDepthStencilBuffer(), m_SharedRTManager.GetDepthTexture(), m_SharedRTManager.GetNormalBuffer(), motionVectors,
+ m_SsrHitPointTexture, m_SharedRTManager.GetStencilBuffer(), TextureXR.GetBlackTexture(), previousColorPyramid, ssrAccumulation, m_SsrLightingTexture, ssrAccumulationPrev, m_SharedRTManager.GetCoarseStencilBuffer(), cmd, renderContext);
// If color pyramid was not valid, we bind a black texture
if (!hdCamera.colorPyramidHistoryIsValid)
@@ -5317,7 +5409,6 @@ static void ResolveColorPickerDebug(in DebugParameters parameters,
HDUtils.DrawFullScreen(cmd, parameters.colorPickerMaterial, output);
}
-
static void RenderExposureDebug(in DebugParameters parameters,
RTHandle inputColorBuffer,
RTHandle postprocessedColorBuffer,
@@ -5564,11 +5655,30 @@ void ClearBuffers(HDCamera hdCamera, CommandBuffer cmd)
{
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ClearSsrBuffers)))
{
+ hdCamera.AllocateScreenSpaceAccumulationHistoryBuffer(1.0f);
+
+ RTHandle ssrAccumulation = hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+
+ ScreenSpaceReflection ssrSettings = hdCamera.volumeStack.GetComponent();
+
+ bool ssrNeedReset = false;
+ if (ssrSettings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation &&
+ hdCamera.currentSSRAlgorithm == ScreenSpaceReflectionAlgorithm.Approximation)
+ ssrNeedReset = true;
+
+ hdCamera.currentSSRAlgorithm = ssrSettings.usedAlgorithm.value;
+
// In practice, these textures are sparse (mostly black). Therefore, clearing them is fast (due to CMASK),
// and much faster than fully overwriting them from within SSR shaders.
// CoreUtils.SetRenderTarget(cmd, hdCamera, m_SsrDebugTexture, ClearFlag.Color, Color.clear);
CoreUtils.SetRenderTarget(cmd, m_SsrHitPointTexture, ClearFlag.Color, Color.clear);
- CoreUtils.SetRenderTarget(cmd, m_SsrLightingTexture, ClearFlag.Color, Color.clear);
+ CoreUtils.SetRenderTarget(cmd, m_SsrLightingTexture, ClearFlag.None);
+ CoreUtils.SetRenderTarget(cmd, ssrAccumulation, ClearFlag.Color, Color.clear);
+ if (ssrNeedReset || hdCamera.isFirstFrame)
+ {
+ RTHandle ssrAccumulationPrev = hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation);
+ CoreUtils.SetRenderTarget(cmd, ssrAccumulationPrev, ClearFlag.Color, Color.clear);
+ }
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs
index 42b8e46b14f..11040089031 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs
@@ -369,13 +369,15 @@ static class HDShaderIDs
public static readonly int _NormalBufferTexture = Shader.PropertyToID("_NormalBufferTexture");
public static readonly int _RaytracePrepassBufferTexture = Shader.PropertyToID("_RaytracePrepassBufferTexture");
- public static readonly int _ShaderVariablesScreenSpaceReflection = Shader.PropertyToID("ShaderVariablesScreenSpaceReflection");
- public static readonly int _SsrLightingTexture = Shader.PropertyToID("_SsrLightingTexture");
- public static readonly int _SsrLightingTextureRW = Shader.PropertyToID("_SsrLightingTextureRW");
- public static readonly int _SsrHitPointTexture = Shader.PropertyToID("_SsrHitPointTexture");
- public static readonly int _SsrClearCoatMaskTexture = Shader.PropertyToID("_SsrClearCoatMaskTexture");
- public static readonly int _DepthPyramidMipLevelOffsets = Shader.PropertyToID("_DepthPyramidMipLevelOffsets");
- public static readonly int _DepthPyramidFirstMipLevelOffset = Shader.PropertyToID("_DepthPyramidFirstMipLevelOffset");
+ public static readonly int _ShaderVariablesScreenSpaceReflection = Shader.PropertyToID("ShaderVariablesScreenSpaceReflection");
+ public static readonly int _SsrLightingTexture = Shader.PropertyToID("_SsrLightingTexture");
+ public static readonly int _SsrAccumPrev = Shader.PropertyToID("_SsrAccumPrev");
+ public static readonly int _SsrLightingTextureRW = Shader.PropertyToID("_SsrLightingTextureRW");
+ public static readonly int _SSRAccumTexture = Shader.PropertyToID("_SSRAccumTexture");
+ public static readonly int _SsrHitPointTexture = Shader.PropertyToID("_SsrHitPointTexture");
+ public static readonly int _SsrClearCoatMaskTexture = Shader.PropertyToID("_SsrClearCoatMaskTexture");
+ public static readonly int _DepthPyramidMipLevelOffsets = Shader.PropertyToID("_DepthPyramidMipLevelOffsets");
+ public static readonly int _DepthPyramidFirstMipLevelOffset = Shader.PropertyToID("_DepthPyramidFirstMipLevelOffset");
// Still used by ray tracing.