From 6642850c02d17dc8accfb6636200e2c596d698a9 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 04:44:26 -0700 Subject: [PATCH] Cleaned up new Depth of Field, ready for PR Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../NewDepthOfFieldCommon.azsli | 4 - .../NewDepthOfFieldComposite.azsl | 76 ++++++++++++++----- .../NewDepthOfFieldFilterLarge.azsl | 44 ++++++++--- .../NewDepthOfFieldFilterSmall.azsl | 65 +++++++++++----- .../NewDepthOfFieldTile3x3.azsl | 7 +- .../NewDepthOfFieldTileReduce.azsl | 3 + .../atom_feature_common_asset_files.cmake | 1 + .../Code/Source/CommonSystemComponent.cpp | 4 - .../PostProcessing/NewDepthOfFieldPasses.cpp | 44 ++--------- .../PostProcessing/NewDepthOfFieldPasses.h | 35 ++------- 10 files changed, 155 insertions(+), 128 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli index a789537819..cd0f334f29 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli @@ -23,9 +23,5 @@ struct NewDepthOfFieldConstants float4 samplePositions[60]; // XY are sample positions (normalized so max lenght is 1) // Z is the length of XY (0 - 1) // W is unused - - }; - - diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl index 14bc0d3b18..b15095535d 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl @@ -51,33 +51,69 @@ PSOutput MainPS(VSOutput IN) float focusDistance = ViewSrg::m_dof.m_cameraParameters.z; float coc = ConvertDofFactor(InvertDepth(depth), far, near, focusDistance); - // Calculate Alpha - float cocRadius = abs(coc) * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; - float maxPixelDist = max(PassSrg::m_halfResDimensions.z, PassSrg::m_halfResDimensions.w); - float alpha = saturate(cocRadius / maxPixelDist); + // --- Weights based on CoC similarity --- + + // Gather CoCs + float4 cocGather = PassSrg::m_halfResColorAndCoc.GatherAlpha(PassSrg::LinearSampler, halfResUV); + + // Calculate differences + float4 diff = saturate(cocGather - coc); - // Sample half res color and CoC - float4 colorAndCoC = PassSrg::m_halfResColorAndCoc.Sample(PassSrg::LinearSampler, halfResUV); + // Slide differences such that small difference (i.e. most similar CoC) will become 0 + // (which then gets inverted in the next step) + float minDiff = min4(diff); + diff -= minDiff; + + // Invert the differences with a slope multiplier of 2 + float4 cocDiffWeights = saturate(1 - (2 * diff)); + + // --- 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 + // + // 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) + ? ( (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) + : float4(0.1875f, 0.5625f, 0.1875f, 0.0625f) ); + + // Combine and normalize weights + weights *= cocDiffWeights; + weights /= (weights.x + weights.y + weights.z + weights.w); + + // --- Color --- + + // For each color channel, do a gather and multiply the samples by the weights calculated above + float3 color; + float4 red = PassSrg::m_halfResColorAndCoc.GatherRed(PassSrg::LinearSampler, halfResUV); + color.r = dot(red, weights); + float4 blue = PassSrg::m_halfResColorAndCoc.GatherBlue(PassSrg::LinearSampler, halfResUV); + color.b = dot(blue, weights); + float4 green = PassSrg::m_halfResColorAndCoc.GatherGreen(PassSrg::LinearSampler, halfResUV); + color.g = dot(green, weights); - if(false) - { - // Make out of focus foreground increasingly blue - float multiplier = saturate(1.0f + coc); - colorAndCoC.r *= multiplier; - colorAndCoC.g *= multiplier; + // --- Alpha --- - // Make out of focus background increasingly red - multiplier = saturate(1.0f - coc); - colorAndCoC.b *= multiplier; - colorAndCoC.g *= multiplier; - } + // Calculate alpha such that we fully take the half res texture value if the CoC of the full + // resolution pixel is greater than the size of a half resolution pixel + float cocRadius = abs(coc) * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; + float alpha = saturate(cocRadius / PassSrg::m_halfResDimensions.w); + + // We may have objects in focus (CoC = 0) but that receive contribution from background bokeh + // (which have a negative CoC that we calculated in the large filter). Take the max here. + float minCoc = min4(cocGather); + alpha = max(alpha, -minCoc); - // Output PSOutput OUT; - OUT.m_color.rgb = colorAndCoC.rgb; + OUT.m_color.rgb = color.rgb; OUT.m_color.a = alpha; - return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl index 6ab47b14ea..ff955493d6 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl @@ -18,6 +18,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_colorAndCoc; Texture2D m_minMaxCocTile; + // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height float4 m_textureDimensions; NewDepthOfFieldConstants m_dofConstants; @@ -43,10 +44,10 @@ ShaderResourceGroup PassSrg : SRG_PerPass }; } -float3 GetOffsetUV(uint index, float2 offsetMultiplier) +float3 GetOffset(uint index, float2 offsetUVMultiplier) { float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz; - offset.xy *= offsetMultiplier; + offset.xy *= offsetUVMultiplier; return offset; } @@ -55,14 +56,19 @@ float CaclulateWeight(float offsetRadius, float samplingRadius, float sampleCoc, // 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)); + // Easy human readable calculations: // radius = samplingRadius * offsetRadius; // falloff = maxRadius - radius; - // weight = 1 + (4 * falloff) + // weight = 1 + (4 * falloff) + // + // The same thing in mad form: float falloff = mad(-samplingRadius, offsetRadius, maxRadius); - float weight = saturate(mad(4, falloff, 1)); - return weight; + return saturate(mad(4, falloff, 1)); } +// This shader blurs by sampling 48 pixels in a circle around the center pixel +// See http://advances.realtimerendering.com/s2013/Sousa_Graphics_Gems_CryENGINE3.pptx +// for a detailed explanation. PSOutput MainPS(VSOutput IN) { // Get center sample @@ -70,10 +76,12 @@ PSOutput MainPS(VSOutput IN) float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba; float centerCoc = color.a; - // Get tile min and max + // Get tile min CoC int2 tile = int2(IN.m_position.xy) / 16; float minCoc = PassSrg::m_minMaxCocTile[tile].x; + // Aspect ratio is needed because sample offsets are calculated in a perfect circle, but + // UV space is stretched due to normalized device coordinates. Correct this with aspect ratio // Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w float aspectRatio = PassSrg::m_textureDimensions.x * PassSrg::m_textureDimensions.w; @@ -82,15 +90,20 @@ PSOutput MainPS(VSOutput IN) float screenRadius = cocRadius * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; float2 offsetMultiplier = float2(screenRadius / aspectRatio, screenRadius); - + // Background samples are samples behind the current pixel. Because of how depth of field works, + // these pixels can contribute to the center pixel even if they are out of range of the center pixel's CoC + // We accumulate them seperately and calculate a new estimated alpha value based on the ratio of samples + // that were background pixels. float4 backgroundColor = float4(0, 0, 0, 0); + // If there are only positive CoCs in our region, we don't need to consider background blur + // Do the faster and nicer approach if(minCoc >= 0) { for(uint i = 0; i < SAMPLES_LOOP_TOTAL; ++i) { // Calculate sample offset - float3 offset = GetOffsetUV(i, offsetMultiplier); + float3 offset = GetOffset(i, offsetMultiplier); // Get sample float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offset.xy).rgba; @@ -102,18 +115,22 @@ PSOutput MainPS(VSOutput IN) color += weight * sampleColorCoc; } } - else + else // Some CoCs in the region are negative, need to consider possible background bokeh contribution { + // Distance behind which samples are considered background samples float backgroundMin = min(0, centerCoc); + + // Linear sampling colors pre-multiplied with CoC yields artefacts when combined with this background technique + // We therefore do point sampling and unpack the original color value per sample color.rgb /= abs(color.a); color.a = 1; for(uint i = 0; i < SAMPLES_LOOP_TOTAL; ++i) { // Calculate sample offset - float3 offset = GetOffsetUV(i, offsetMultiplier); + float3 offset = GetOffset(i, offsetMultiplier); - // Get sample + // Get sample + unpack float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba; sampleColorCoc.rgb /= abs(sampleColorCoc.a); @@ -131,16 +148,19 @@ PSOutput MainPS(VSOutput IN) color += !isBackground * sampleColorCoc; } + // Average background samples backgroundColor.rgb /= max(backgroundColor.a, COC_EPSILON); } + // Calculate background ratio. If greater than the current CoC, replace the current CoC with + // background ratio. This is so background bokeh effects will still render on in-focus objects float backgroundRatio = saturate( backgroundColor.a / float(SAMPLES_LOOP_TOTAL) ); float alpha = backgroundRatio > abs(centerCoc) ? -backgroundRatio : centerCoc; + // Average accumulated color samples and combine with background samples color.rgb /= max(color.a, COC_EPSILON); color = lerp(color, backgroundColor, backgroundRatio); - PSOutput OUT = (PSOutput)0; OUT.m_color.rgb = color.rgb; OUT.m_color.a = alpha; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl index 05227cfee7..04bc095a93 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl @@ -18,6 +18,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_colorAndCoc; Texture2D m_minMaxCocTile; + // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height float4 m_textureDimensions; NewDepthOfFieldConstants m_dofConstants; @@ -43,55 +44,77 @@ ShaderResourceGroup PassSrg : SRG_PerPass }; } -float2 GetOffsetUV(uint index, float2 offsetMultiplier) +float3 GetOffset(uint index, float2 offsetUVMultiplier) { - return PassSrg::m_dofConstants.samplePositions[index].xy * offsetMultiplier; + float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz; + offset.xy *= offsetUVMultiplier; + return offset; } +float CaclulateWeight(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)); + + // Easy human readable calculations: + // radius = samplingRadius * offsetRadius; + // falloff = maxRadius - radius; + // weight = 1 + (4 * falloff) + // + // The same thing in mad form: + float falloff = mad(-samplingRadius, offsetRadius, maxRadius); + return saturate(mad(4, falloff, 1)); +} + +// This shader attempts to fill the gaps left by the large filter by sampling 8 pixels around the center pixel +// See http://advances.realtimerendering.com/s2013/Sousa_Graphics_Gems_CryENGINE3.pptx +// for a detailed overview of the technique PSOutput MainPS(VSOutput IN) { - // UV of pixel being shaded + // Get center sample float2 pixelUV = IN.m_texCoord.xy; + float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV).rgba; + float centerCoc = color.a; - // Sample pixel being shaded - float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV).rgba; - float centerCoc = centerSample.a; + // Get tile min CoC + int2 tile = int2(IN.m_position.xy) / 16; + float minCoc = PassSrg::m_minMaxCocTile[tile].x; + // Aspect ratio is needed because sample offsets are calculated in a perfect circle, but + // UV space is stretched due to normalized device coordinates. Correct this with aspect ratio // Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w float aspectRatio = PassSrg::m_textureDimensions.x * PassSrg::m_textureDimensions.w; // Sampling radius - float cocRadius = abs(centerCoc) * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; - cocRadius *= 0.5f; // This is the small filter, half the sampling radius - float2 offsetMultiplier = float2(cocRadius / aspectRatio, cocRadius); + float cocRadius = max( abs(centerCoc), -minCoc) * 0.5f; // Small filter pass so half the radius + float screenRadius = cocRadius * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; + float2 offsetMultiplier = float2(screenRadius / aspectRatio, screenRadius); - // Color and weight accumulation - float3 color = centerSample.rgb; + // Weight accumulation. Start with 1 for center pixel. float totalWeight = 1; - for(uint i = 0; i < 8; ++i) + for(uint i = 0; i < SAMPLES_LOOP_1; ++i) { // Calculate sample offset - float2 offsetUV = GetOffsetUV(i, offsetMultiplier); + float3 offset = GetOffset(i, offsetMultiplier); // Get sample - float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offsetUV).rgba; + float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba; // Calculate weight - float cocDiff = sampleColorCoc.a - centerCoc; - float weight = saturate( 2 - (20 * cocDiff)); + float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); // Accumulate sample and weight - color += sampleColorCoc.rgb * weight; + color.rgb += sampleColorCoc.rgb * weight; totalWeight += weight; } - // Normalize accumulated sample - color /= totalWeight; - // Output + // Normalize accumulated sample + color.rgb /= totalWeight; + PSOutput OUT; - OUT.m_color.rgb = color; + OUT.m_color.rgb = color.rgb; OUT.m_color.a = centerCoc; return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl index 7238b391aa..e7ce99aae9 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl @@ -33,13 +33,14 @@ struct PSOutput float2 m_color : SV_Target0; }; +// Expands the min and max tiles so each tile contains the min and max of it's 3x3 neighborhood 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 stepSize = PassSrg::m_textureDimensions.zw; - float2 startUV = startPixelPos * stepSize; + float2 pixelSizeInUV = PassSrg::m_textureDimensions.zw; + float2 startUV = startPixelPos * pixelSizeInUV; float cocMin = 1.0f; float cocMax = -1.0f; @@ -51,7 +52,7 @@ PSOutput MainPS(VSOutput IN) [unroll] for(float X = 0.0f; X < 3.0f; X += 1.0f) { - float2 sampleUV = mad(float2(X, Y), stepSize, startUV); + float2 sampleUV = mad(float2(X, Y), pixelSizeInUV, startUV); float2 minMax = PassSrg::m_minMaxSource.SampleLevel(PassSrg::PointSampler, sampleUV, 0).xy; cocMin = min(cocMin, minMax.x); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl index 2705e1fdfd..740ebabaff 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl @@ -36,6 +36,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass groupshared uint LDS_MIN_COC[8]; groupshared uint LDS_MAX_COC[8]; +// Calculates the min and max CoC (Circle of Confusion) for 16x16 pixel tiles [numthreads(8, 8, 1)] void MainCS(uint3 group_thread_id : SV_GroupThreadID, uint3 group_id : SV_GroupID, uint3 dispatch_id: SV_DispatchThreadID, uint linear_id : SV_GroupIndex) { @@ -68,9 +69,11 @@ void MainCS(uint3 group_thread_id : SV_GroupThreadID, uint3 group_id : SV_GroupI return; } + // Min the mins and max the maxs InterlockedMin( LDS_MIN_COC[0], LDS_MIN_COC[group_thread_id.x] ); InterlockedMax( LDS_MAX_COC[0], LDS_MAX_COC[group_thread_id.x] ); + // Each group write to just one pixel. If we're the last thread in the group, write out if(group_thread_id.x == 0) { // Unpack uints diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index d1f94afe3c..0423741dda 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -443,6 +443,7 @@ set(FILES Shaders/PostProcessing/MSAAResolveCustom.shader Shaders/PostProcessing/MSAAResolveDepth.azsl Shaders/PostProcessing/MSAAResolveDepth.shader + Shaders/PostProcessing/NewDepthOfFieldCommon.azsli Shaders/PostProcessing/NewDepthOfFieldComposite.azsl Shaders/PostProcessing/NewDepthOfFieldComposite.shader Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index a7891b7907..c117cadbde 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -252,10 +252,6 @@ namespace AZ passSystem->AddPassCreator(Name("NewDepthOfFieldParentPass"), &NewDepthOfFieldParentPass::Create); passSystem->AddPassCreator(Name("NewDepthOfFieldTileReducePass"), &NewDepthOfFieldTileReducePass::Create); passSystem->AddPassCreator(Name("NewDepthOfFieldFilterPass"), &NewDepthOfFieldFilterPass::Create); - passSystem->AddPassCreator(Name("NewDepthOfFieldCompositePass"), &NewDepthOfFieldCompositePass::Create); - - - // Add FastDepthAwareBlur passes passSystem->AddPassCreator(Name("FastDepthAwareBlurHorPass"), &FastDepthAwareBlurHorPass::Create); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp index b69484297a..69ee2a6751 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp @@ -32,7 +32,6 @@ namespace AZ // W is unused }; - // --- Depth of Field Parent Pass --- RPI::Ptr NewDepthOfFieldParentPass::Create(const RPI::PassDescriptor& descriptor) @@ -103,8 +102,8 @@ namespace AZ NewDepthOfFieldTileReducePass::NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor) : RPI::ComputePass(descriptor) { - // Though this is a fullscreen pass, the algorithm used makes each thread output 3 blurred pixels, so - // it's not a 1-to-1 ratio and requires custom calculation of target thread counts + // Though this is a fullscreen pass, the shader computes 16x16 tiles with groups of 8x8 threads, + // each thread outputting to a single pixel in the tiled min/max texture m_isFullscreenPass = false; } @@ -124,8 +123,6 @@ namespace AZ RPI::ComputePass::FrameBeginInternal(params); } - - // --- Filter Pass --- RPI::Ptr NewDepthOfFieldFilterPass::Create(const RPI::PassDescriptor& descriptor) @@ -144,22 +141,19 @@ namespace AZ uint32_t sampleIndex = 0; + // Calculate all the offset positions for (uint32_t loop = 0; loop < NewDepthOfFieldConstants::numberOfLoops; ++loop) { float radius = (loop + 1.0f) / float(NewDepthOfFieldConstants::numberOfLoops); float loopCount = NewDepthOfFieldConstants::loopCounts[loop]; - float angleOffset = 0; + float angleStep = Constants::TwoPi / loopCount; // Every other loop slightly rotate sample ring so they don't line up - if (loop & 1) - { - angleOffset = Constants::TwoPi * 0.5f / loopCount; - } + float angle = (loop & 1) ? (angleStep * 0.5f) : 0; for (float i = 0.0f; i < loopCount; ++i) { - float angle = Constants::TwoPi * i / loopCount; Vector2 pos = Vector2::CreateFromAngle(angle); pos = pos * radius; @@ -167,38 +161,16 @@ namespace AZ dofConstants.m_samplePositions[sampleIndex][1] = pos.GetY(); dofConstants.m_samplePositions[sampleIndex][2] = radius; dofConstants.m_samplePositions[sampleIndex][3] = 0.0f; - ++sampleIndex; - } + ++sampleIndex; + angle += angleStep; + } } m_shaderResourceGroup->SetConstant(m_constantsIndex, dofConstants); - // TODO HERE RPI::FullscreenTrianglePass::FrameBeginInternal(params); } - - - // --- Composite Pass --- - - RPI::Ptr NewDepthOfFieldCompositePass::Create(const RPI::PassDescriptor& descriptor) - { - RPI::Ptr pass = aznew NewDepthOfFieldCompositePass(descriptor); - return AZStd::move(pass); - } - - NewDepthOfFieldCompositePass::NewDepthOfFieldCompositePass(const RPI::PassDescriptor& descriptor) - : RPI::ComputePass(descriptor) - { } - - void NewDepthOfFieldCompositePass::FrameBeginInternal(FramePrepareParams params) - { - // TODO HERE - RPI::ComputePass::FrameBeginInternal(params); - } - - - } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h index f7a0ee95ca..d529623c0a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h @@ -17,7 +17,9 @@ namespace AZ { namespace Render { - //! + //! 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 class NewDepthOfFieldParentPass final : public RPI::ParentPass { @@ -41,8 +43,7 @@ namespace AZ }; - - //! + //! Need a class for the tile reduce pass because it dispatches a non-trivial number of threads class NewDepthOfFieldTileReducePass final : public RPI::ComputePass { @@ -64,8 +65,9 @@ namespace AZ }; - - //! + //! Filter pass used to render the bokeh blur effect on downsampled image buffer + //! This class is used for both the large filter and the small filter + //! It's main purpose is calculating the sample positions and setting srg constants class NewDepthOfFieldFilterPass final : public RPI::FullscreenTrianglePass { @@ -90,28 +92,5 @@ namespace AZ }; - - //! - class NewDepthOfFieldCompositePass final - : public RPI::ComputePass - { - AZ_RPI_PASS(NewDepthOfFieldCompositePass); - - public: - AZ_RTTI(AZ::Render::NewDepthOfFieldCompositePass, "{63270A3A-EAE5-4C0C-98AA-43CA55279613}", AZ::RPI::ComputePass); - AZ_CLASS_ALLOCATOR(NewDepthOfFieldCompositePass, SystemAllocator, 0); - virtual ~NewDepthOfFieldCompositePass() = default; - - static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); - - protected: - // Behavior functions override... - void FrameBeginInternal(FramePrepareParams params) override; - - private: - NewDepthOfFieldCompositePass(const RPI::PassDescriptor& descriptor); - }; - - } // namespace Render } // namespace AZ