From e5c7703aa72339e2a36d5a4fbf977cc6f7040536 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 20:15:39 -0700 Subject: [PATCH] Addressing review feedback Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Assets/Passes/PostProcessParent.pass | 1 + .../NewDepthOfFieldComposite.azsl | 7 ++-- .../NewDepthOfFieldDownsample.azsl | 3 +- .../NewDepthOfFieldFilterLarge.azsl | 7 ++-- .../NewDepthOfFieldFilterSmall.azsl | 5 +-- .../NewDepthOfFieldTile3x3.azsl | 33 ++++++++++--------- .../NewDepthOfFieldTileReduce.azsl | 3 +- .../PostProcessing/NewDepthOfFieldPasses.h | 23 +++++++++++++ 8 files changed, 56 insertions(+), 26 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass index dc1c0f1664..67c5072513 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass @@ -112,6 +112,7 @@ } ] }, + // Todo: remove the old depth of field implementation and rename NewDepthOfField -> DepthOfField //{ // "Name": "DepthOfFieldPass", // "TemplateName": "DepthOfFieldTemplate", diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl index b15095535d..468f93db78 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl @@ -22,6 +22,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_halfResColorAndCoc; // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + // Auto-filled by the pass system when "ShaderImageDimensionsConstant" is specified in the .pass file float4 m_fullResDimensions; float4 m_halfResDimensions; @@ -69,15 +70,15 @@ PSOutput MainPS(VSOutput IN) // --- Weights based on pixel proximity --- - // Based on which pixel we're shading, we'll be closer/further to half res pixels - // Here are the pre-caculated weights, arranged to match the Gather pattern + // Based on which pixel we're shading, we'll be closer/farther to half res pixels + // Here are the pre-calculated weights, arranged to match the Gather pattern // // W Z // X Y // // Note: These weights come down to the same contributions as if we did a linear sample int2 pixel = int2(fullResPixelPos); - float4 weights = (pixel.x & 1) + float4 weights = (pixel.x & 1) ? ( (pixel.y & 1) ? float4(0.1875f, 0.0625f, 0.1875f, 0.5625f) : float4(0.5625f, 0.1875f, 0.0625f, 0.1875f) ) : ( (pixel.y & 1) ? float4(0.0625f, 0.1875f, 0.5625f, 0.1875f) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl index d9972b8400..01ff4b9493 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl @@ -22,6 +22,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_depth; // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + // Auto-filled by the pass system when "ShaderImageDimensionsConstant" is specified in the .pass file float4 m_inputDimensions; float4 m_outputDimensions; @@ -61,7 +62,7 @@ PSOutput MainPS(VSOutput IN) // Clamp CoC cocGather = clamp(cocGather, -1.0f, 1.0f); - // Weigh samles by CoC to avoid in foces pixels bleeding into bokeh effect + // Weight samples by CoC to avoid in focus pixels bleeding into bokeh effect float4 weights = abs(cocGather) + COC_EPSILON; weights = weights / (weights.x + weights.y + weights.z + weights.w); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl index ff955493d6..3b979b9c39 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl @@ -19,6 +19,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_minMaxCocTile; // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + // Auto-filled by the pass system when "ShaderImageDimensionsConstant" is specified in the .pass file float4 m_textureDimensions; NewDepthOfFieldConstants m_dofConstants; @@ -51,7 +52,7 @@ float3 GetOffset(uint index, float2 offsetUVMultiplier) return offset; } -float CaclulateWeight(float offsetRadius, float samplingRadius, float sampleCoc, float centerCoc) +float CalculateWeight(float offsetRadius, float samplingRadius, float sampleCoc, float centerCoc) { // The maximum distance for which samples are valid is the min of the sample CoC and the center CoC float maxRadius = abs(min(sampleCoc, centerCoc)); @@ -109,7 +110,7 @@ PSOutput MainPS(VSOutput IN) float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offset.xy).rgba; // Calculate weight for sample - float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); + float weight = CalculateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); // Accumulate color += weight * sampleColorCoc; @@ -135,7 +136,7 @@ PSOutput MainPS(VSOutput IN) sampleColorCoc.rgb /= abs(sampleColorCoc.a); // Calculate weight for sample - float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); + float weight = CalculateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); sampleColorCoc.rgb *= weight; bool isBackground = (sampleColorCoc.a < backgroundMin); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl index 04bc095a93..38762254a8 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl @@ -19,6 +19,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_minMaxCocTile; // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + // Auto-filled by the pass system when "ShaderImageDimensionsConstant" is specified in the .pass file float4 m_textureDimensions; NewDepthOfFieldConstants m_dofConstants; @@ -51,7 +52,7 @@ float3 GetOffset(uint index, float2 offsetUVMultiplier) return offset; } -float CaclulateWeight(float offsetRadius, float samplingRadius, float sampleCoc, float centerCoc) +float CalculateWeight(float offsetRadius, float samplingRadius, float sampleCoc, float centerCoc) { // The maximum distance for which samples are valid is the min of the sample CoC and the center CoC float maxRadius = abs(min(sampleCoc, centerCoc)); @@ -102,7 +103,7 @@ PSOutput MainPS(VSOutput IN) float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba; // Calculate weight - float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); + float weight = CalculateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); // Accumulate sample and weight color.rgb += sampleColorCoc.rgb * weight; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl index e7ce99aae9..6c56b0b79c 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl @@ -15,6 +15,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_minMaxSource; // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + // Auto-filled by the pass system when "ShaderImageDimensionsConstant" is specified in the .pass file float4 m_textureDimensions; Sampler PointSampler @@ -38,28 +39,28 @@ PSOutput MainPS(VSOutput IN) { // We want the min/max in a 3x3 region. Start sampling up left. float2 startPixelPos = IN.m_position.xy - float2(1, 1); - + float2 pixelSizeInUV = PassSrg::m_textureDimensions.zw; float2 startUV = startPixelPos * pixelSizeInUV; - + float cocMin = 1.0f; - float cocMax = -1.0f; - + float cocMax = -1.0f; + // Gather min/max in 3x3 region - [unroll] - for(float Y = 0.0f; Y < 3.0f; Y += 1.0f) + [unroll] + for(float Y = 0.0f; Y < 3.0f; Y += 1.0f) { - [unroll] - for(float X = 0.0f; X < 3.0f; X += 1.0f) - { - float2 sampleUV = mad(float2(X, Y), pixelSizeInUV, startUV); - float2 minMax = PassSrg::m_minMaxSource.SampleLevel(PassSrg::PointSampler, sampleUV, 0).xy; - - cocMin = min(cocMin, minMax.x); - cocMax = max(cocMax, minMax.y); - } + [unroll] + for(float X = 0.0f; X < 3.0f; X += 1.0f) + { + float2 sampleUV = mad(float2(X, Y), pixelSizeInUV, startUV); + float2 minMax = PassSrg::m_minMaxSource.SampleLevel(PassSrg::PointSampler, sampleUV, 0).xy; + + cocMin = min(cocMin, minMax.x); + cocMax = max(cocMax, minMax.y); + } } - + PSOutput output; output.m_color.x = cocMin; output.m_color.y = cocMax; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl index 740ebabaff..6d55648f22 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl @@ -19,6 +19,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass RWTexture2D m_minMaxCoC; // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + // Auto-filled by the pass system when "ShaderImageDimensionsConstant" is specified in the .pass file float4 m_inputDimensions; float4 m_outputDimensions; @@ -59,7 +60,7 @@ void MainCS(uint3 group_thread_id : SV_GroupThreadID, uint3 group_id : SV_GroupI // For atomic min/max to work with uints, floating point values should be positive // Map from [-1, 1] range to [0, 2] and cast as uint InterlockedMin( LDS_MIN_COC[group_thread_id.x], asuint(cocMin + 1) ); - InterlockedMax( LDS_MAX_COC[group_thread_id.x], asuint(cocMax + 1) ); + InterlockedMax( LDS_MAX_COC[group_thread_id.x], asuint(cocMax + 1) ); // Sync LDS GroupMemoryBarrierWithGroupSync(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h index d529623c0a..159f91e744 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h @@ -17,6 +17,29 @@ namespace AZ { namespace Render { + // Technique + // + // 1. This Depth of Field technique starts by downsampling the lighting buffer and calculating + // the circle of confusion (CoC) for each downsampled pixel. + // + // 2. It then computes the min and max CoC for tiles of 16x16 pixels + // + // 3. It expands the min and max in a 3x3 region (twice, so 5x5 at the end) so that each tile + // tile pixel has the min and max CoCs of the 5x5 tile region around it + // + // 4. We perform a 48 tap scatter-as-gather blur around each pixel + // + // 5. We perform a follow up 8 tap scatter-as-gather blur to fill the holes from the first blur + // + // 6. We composite the blurred half resolution image onto the full resolution lighting buffer + // + // See http://advances.realtimerendering.com/s2013/Sousa_Graphics_Gems_CryENGINE3.pptx + // for a more detailed explanation. + // + // Notes: The name NewDepthOfField is in contrast to the previously implemented depth of field method + // That method will be removed in a follow up change and at that point NewDepthOfField will be renamed + // to simple DepthOfField. + //! Parent pass for the new depth of field technique //! Main updates the view srg via the depth of field settings //! And enables/disables all depth of field passes based on component activation