diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass index e7c6a23c6c..483ce0e49a 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass @@ -67,6 +67,20 @@ } ] }, + { + "Name": "Tile5x5", + "TemplateName": "NewDepthOfFieldTile3x3Template", + + "Connections": [ + { + "LocalSlot": "Input", + "AttachmentRef": { + "Pass": "Tile3x3", + "Attachment": "Output" + } + } + ] + }, { "Name": "LargeFilter", "TemplateName": "NewDepthOfFieldFilterLargeTemplate", @@ -82,7 +96,7 @@ { "LocalSlot": "CocTile", "AttachmentRef": { - "Pass": "Tile3x3", + "Pass": "Tile5x5", "Attachment": "Output" } } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli index fc98cee055..a789537819 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli @@ -15,6 +15,8 @@ #define SAMPLES_LOOP_2 16 #define SAMPLES_LOOP_3 24 +#define SAMPLES_LOOP_TOTAL 48 + // Must match the struct in NewDepthOfFieldPasses.cpp struct NewDepthOfFieldConstants { diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl index 8a766c71d9..14bc0d3b18 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl @@ -54,22 +54,25 @@ PSOutput MainPS(VSOutput IN) // 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(0.25f * cocRadius / maxPixelDist); + float alpha = saturate(cocRadius / maxPixelDist); // Sample half res color and CoC float4 colorAndCoC = PassSrg::m_halfResColorAndCoc.Sample(PassSrg::LinearSampler, halfResUV); - // Make out of focus foreground increasingly blue - float multiplier = saturate(1.0f + coc); - colorAndCoC.r *= multiplier; - colorAndCoC.g *= multiplier; + if(false) + { + // Make out of focus foreground increasingly blue + float multiplier = saturate(1.0f + coc); + colorAndCoC.r *= multiplier; + colorAndCoC.g *= multiplier; + + // Make out of focus background increasingly red + multiplier = saturate(1.0f - coc); + colorAndCoC.b *= multiplier; + colorAndCoC.g *= multiplier; + } - // Make out of focus background increasingly red - multiplier = saturate(1.0f - coc); - colorAndCoC.b *= multiplier; - colorAndCoC.g *= multiplier; - // Output PSOutput OUT; OUT.m_color.rgb = colorAndCoC.rgb; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl index c8070178f0..d9972b8400 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl @@ -93,8 +93,8 @@ PSOutput MainPS(VSOutput IN) // See http://advances.realtimerendering.com/s2013/Sousa_Graphics_Gems_CryENGINE3.pptx coc = abs(coc) > COC_EPSILON ? coc : -COC_EPSILON; OUT.m_color.rgb *= abs(coc); - OUT.m_color.a = coc; + 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 e566db7880..497d73444b 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl @@ -31,20 +31,103 @@ ShaderResourceGroup PassSrg : SRG_PerPass AddressV = Clamp; AddressW = Clamp; }; + + Sampler PointSampler + { + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +float3 GetOffsetUV(uint index, float2 offsetMultiplier) +{ + float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz; + offset.xy *= offsetMultiplier; + 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)); + + // radius = samplingRadius * offsetRadius; + // falloff = maxRadius - radius; + // weight = 1 + (4 * falloff) + float falloff = mad(-samplingRadius, offsetRadius, maxRadius); + float weight = saturate(mad(4, falloff, 1)); + return weight; } PSOutput MainPS(VSOutput IN) { - PSOutput OUT = (PSOutput)0; + // Get center sample + float2 pixelUV = IN.m_texCoord; + float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba; + float centerCoc = color.a; + + // Get tile min and max + int2 tile = int2(IN.m_position.xy) / 16; + float minCoc = PassSrg::m_minMaxCocTile[tile].x; + + // Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w + float aspectRatio = PassSrg::m_textureDimensions.x * PassSrg::m_textureDimensions.w; + + // Sampling radius + float cocRadius = max( abs(centerCoc), -minCoc); + float screenRadius = cocRadius * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; + float2 offsetMultiplier = float2(screenRadius / aspectRatio, screenRadius); - float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, IN.m_texCoord); - float3 centerColor = centerSample.rgb; - float centerCoc = centerSample.a; - centerColor /= centerCoc; + float4 backgroundColor = float4(0, 0, 0, 0); + + { + float backgroundMin = min(0, centerCoc); + 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); + + // Get sample + float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba; + sampleColorCoc.rgb /= abs(sampleColorCoc.a); + + // Calculate weight for sample + float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); + sampleColorCoc.rgb *= weight; + + bool isBackground = (sampleColorCoc.a < backgroundMin); + + // We accumulate weight in alpha channel of color and backgroundColor + sampleColorCoc.a = weight; + + // Accumulate + backgroundColor += isBackground * sampleColorCoc; + color += !isBackground * sampleColorCoc; + } + } + + float backgroundRatio = backgroundColor.a / float(SAMPLES_LOOP_TOTAL); + float alpha = backgroundRatio > abs(centerCoc) ? -backgroundRatio : centerCoc; + + color.rgb /= max(color.a, COC_EPSILON); + backgroundColor.rgb /= max(backgroundColor.a, COC_EPSILON); + + color = color * saturate(1 - backgroundRatio) + backgroundColor * backgroundRatio; + //color.rgb += backgroundColor.rgb; + - OUT.m_color.rgb = centerColor; - OUT.m_color.a = centerCoc; + + PSOutput OUT = (PSOutput)0; + 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~RF1bf9782e.TMP b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl~RF1bf9782e.TMP new file mode 100644 index 0000000000..7c0f32381b --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl~RF1bf9782e.TMP @@ -0,0 +1,105 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include "DepthOfField.azsli" +#include "NewDepthOfFieldCommon.azsli" + +#include + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_colorAndCoc; + Texture2D m_minMaxCocTile; + + float4 m_textureDimensions; + + NewDepthOfFieldConstants m_dofConstants; + + Sampler LinearSampler + { + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +float2 GetOffsetUV(uint index, float2 offsetMultiplier) +{ + return PassSrg::m_dofConstants.samplePositions[index].xy * offsetMultiplier; +} + +PSOutput MainPS(VSOutput IN) +{ + // Get center sample + float2 pixelUV = IN.m_texCoord; + float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba; + float centerCoc = color.a; + + // Get tile min and max + int2 tile = int2(IN.m_position.xy) / 16; + float minCoc = PassSrg::m_minMaxCocTile[tile].x; + + // Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w + float aspectRatio = PassSrg::m_textureDimensions.x * PassSrg::m_textureDimensions.w; + + // Sampling radius + float cocRadius = max( abs(centerCoc), -minCoc); + cocRadius *= ViewSrg::m_dof.m_cocToScreenRatio * 0.5f; + float2 offsetMultiplier = float2(cocRadius / aspectRatio, cocRadius); + + + + float4 negColor = float4(0, 0, 0, 0); + + { + float negMin = min(0, centerCoc); + color.rgb /= abs(color.a); + color.a = 1; + + for(uint i = 0; i < SAMPLES_LOOP_TOTAL; ++i) + { + // Calculate sample offset + float2 offsetUV = GetOffsetUV(i, offsetMultiplier); + + // Get sample + float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offsetUV).rgba; + + // Calculate weight and adjust sample + float cocDiff = sampleColorCoc.a - centerCoc; + float weight = saturate( 2 - (20 * cocDiff)); + sampleColorCoc.rgb *= (weight / abs(sampleColorCoc.a)); + // + // bool isNeg = (sampleColorCoc.a < negMin); + // sampleColorCoc.a = weight; + // + // // Accumulate + // negColor += isNeg * sampleColorCoc; + // color += !isNeg * sampleColorCoc; + } + } + + float negRatio = negColor.a / float(SAMPLES_LOOP_TOTAL); + float alpha = negRatio > abs(centerCoc) ? -negRatio : centerCoc; + + color = color * saturate(1 - negRatio) + negColor; + color.rgb /= max(color.a, COC_EPSILON); + color.rgb += negColor.rgb; + + //float alpha = 1.0f; + + PSOutput OUT = (PSOutput)0; + OUT.m_color.rgb = color.rgb; + OUT.m_color.a = alpha; + return OUT; +} + diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl index dadaf57506..440701ded9 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl @@ -33,9 +33,9 @@ ShaderResourceGroup PassSrg : SRG_PerPass }; } -float2 GetOffsetUV(uint index, float radiusMultiplier) +float2 GetOffsetUV(uint index, float2 offsetMultiplier) { - return PassSrg::m_dofConstants.samplePositions[index] * radiusMultiplier * PassSrg::m_textureDimensions.zw; + return PassSrg::m_dofConstants.samplePositions[index].xy * offsetMultiplier; } PSOutput MainPS(VSOutput IN) @@ -47,27 +47,41 @@ PSOutput MainPS(VSOutput IN) float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba; float centerCoc = centerSample.a; - // Color and weight accumulation - float3 color = centerSample.rgb; - float totalWeight = 1; + // 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); - for(uint i = 0; i < SAMPLES_LOOP_1; ++i) + // Color and weight accumulation + float3 color = centerSample.rgb; + float totalWeight = 1; + + for(uint i = 0; i < 8; ++i) { - float2 offsetUV = GetOffsetUV(i, cocRadius); - float4 sample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offsetUV).rgba; - float cocDiff = abs(sample.a - centerCoC); + // Calculate sample offset + float2 offsetUV = GetOffsetUV(i, offsetMultiplier); + + // Get sample + float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offsetUV).rgba; + + // Calculate weight + float cocDiff = sampleColorCoc.a - centerCoc; float weight = saturate( 2 - (20 * cocDiff)); - color += sample.rgb * weight; + + // Accumulate sample and weight + color += sampleColorCoc.rgb * weight; totalWeight += weight; } + // Normalize accumulated sample + color /= totalWeight; + // Output PSOutput OUT; - OUT.m_color.rgb = color / totalWeight; + OUT.m_color.rgb = color; OUT.m_color.a = centerCoc; return OUT; }