From 9e8e08a8155e575fd42b2838cb3179227d813360 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Wed, 20 Oct 2021 14:10:11 -0700 Subject: [PATCH 1/9] Throwing up Depth of Field WIP so Galib can investigate AP crash with shader processing Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Common/Assets/Passes/NewDepthOfField.pass | 143 +++++++++++++ .../Passes/NewDepthOfFieldComposite.pass | 37 ++++ .../Passes/NewDepthOfFieldDownsample.pass | 72 +++++++ .../Passes/NewDepthOfFieldFilterLarge.pass | 62 ++++++ .../Passes/NewDepthOfFieldFilterSmall.pass | 62 ++++++ .../Assets/Passes/NewDepthOfFieldTile3x3.pass | 57 +++++ .../Passes/NewDepthOfFieldTileReduce.pass | 63 ++++++ .../Assets/Passes/PassTemplates.azasset | 28 +++ .../Assets/Passes/PostProcessParent.pass | 29 ++- .../Shaders/PostProcessing/DepthOfField.azsli | 8 + .../NewDepthOfFieldCommon.azsli | 29 +++ .../NewDepthOfFieldComposite.azsl | 80 +++++++ .../NewDepthOfFieldComposite.shader | 31 +++ .../NewDepthOfFieldDownsample.azsl | 100 +++++++++ .../NewDepthOfFieldDownsample.shader | 22 ++ .../NewDepthOfFieldFilterLarge.azsl | 50 +++++ .../NewDepthOfFieldFilterLarge.shader | 22 ++ .../NewDepthOfFieldFilterSmall.azsl | 74 +++++++ .../NewDepthOfFieldFilterSmall.shader | 22 ++ .../NewDepthOfFieldTile3x3.azsl | 66 ++++++ .../NewDepthOfFieldTile3x3.shader | 22 ++ .../NewDepthOfFieldTileReduce.azsl | 83 ++++++++ .../NewDepthOfFieldTileReduce.shader | 14 ++ .../atom_feature_common_asset_files.cmake | 73 +++++-- .../Code/Source/CommonSystemComponent.cpp | 9 + .../PostProcessing/NewDepthOfFieldPasses.cpp | 196 ++++++++++++++++++ .../PostProcessing/NewDepthOfFieldPasses.h | 117 +++++++++++ .../Code/Source/PostProcessing/TaaPass.cpp | 2 +- .../Code/atom_feature_common_files.cmake | 2 + .../Atom/RHI.Reflect/ShaderInputNameIndex.h | 4 + .../RHI.Reflect/ShaderInputNameIndex.cpp | 6 + .../RPI/Assets/ShaderLib/Atom/RPI/Math.azsli | 40 ++++ .../Atom/RPI.Public/Pass/PassAttachment.h | 8 +- .../Include/Atom/RPI.Public/Pass/RenderPass.h | 2 +- .../RPI.Reflect/Pass/PassAttachmentReflect.h | 7 + .../Source/RPI.Public/Pass/PassAttachment.cpp | 1 + .../Source/RPI.Public/Pass/RenderPass.cpp | 42 +++- .../Pass/PassAttachmentReflect.cpp | 3 +- 38 files changed, 1657 insertions(+), 31 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldComposite.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldDownsample.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterLarge.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterSmall.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTile3x3.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTileReduce.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.shader create mode 100644 Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass new file mode 100644 index 0000000000..e7c6a23c6c --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass @@ -0,0 +1,143 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldTemplate", + "PassClass": "NewDepthOfFieldParentPass", + "Slots": [ + { + "Name": "Depth", + "SlotType": "Input" + }, + { + "Name": "LightingBuffer", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget" + } + ], + "PassRequests": [ + { + "Name": "Downsample", + "TemplateName": "NewDepthOfFieldDownsampleTemplate", + + "Connections": [ + { + "LocalSlot": "ColorInput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "LightingBuffer" + } + }, + { + "LocalSlot": "DepthInput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "Depth" + } + } + ] + }, + { + "Name": "TileReduce", + "TemplateName": "NewDepthOfFieldTileReduceTemplate", + + "Connections": [ + { + "LocalSlot": "ColorAndCocInput", + "AttachmentRef": { + "Pass": "Downsample", + "Attachment": "OutputColorAndCoC" + } + } + ] + }, + { + "Name": "Tile3x3", + "TemplateName": "NewDepthOfFieldTile3x3Template", + + "Connections": [ + { + "LocalSlot": "Input", + "AttachmentRef": { + "Pass": "TileReduce", + "Attachment": "MinMaxCoC" + } + } + ] + }, + { + "Name": "LargeFilter", + "TemplateName": "NewDepthOfFieldFilterLargeTemplate", + + "Connections": [ + { + "LocalSlot": "ColorAndCoc", + "AttachmentRef": { + "Pass": "Downsample", + "Attachment": "OutputColorAndCoC" + } + }, + { + "LocalSlot": "CocTile", + "AttachmentRef": { + "Pass": "Tile3x3", + "Attachment": "Output" + } + } + ] + }, + { + "Name": "SmallFilter", + "TemplateName": "NewDepthOfFieldFilterSmallTemplate", + + "Connections": [ + { + "LocalSlot": "ColorAndCoc", + "AttachmentRef": { + "Pass": "LargeFilter", + "Attachment": "OutputColorAndCoc" + } + }, + { + "LocalSlot": "CocTile", + "AttachmentRef": { + "Pass": "Tile3x3", + "Attachment": "Output" + } + } + ] + }, + { + "Name": "Composite", + "TemplateName": "NewDepthOfFieldCompositeTemplate", + + "Connections": [ + { + "LocalSlot": "Depth", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "HalfResColorAndCoC", + "AttachmentRef": { + "Pass": "SmallFilter", + "Attachment": "OutputColorAndCoc" + } + }, + { + "LocalSlot": "ColorInputOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "LightingBuffer" + } + } + ] + } + ] + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldComposite.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldComposite.pass new file mode 100644 index 0000000000..522ae78fa5 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldComposite.pass @@ -0,0 +1,37 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldCompositeTemplate", + "PassClass": "FullScreenTriangle", + "Slots": [ + { + "Name": "Depth", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_fullResDimensions" + }, + { + "Name": "HalfResColorAndCoC", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_halfResDimensions" + }, + { + "Name": "ColorInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget" + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/NewDepthOfFieldComposite.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldDownsample.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldDownsample.pass new file mode 100644 index 0000000000..2f1787c6cd --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldDownsample.pass @@ -0,0 +1,72 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldDownsampleTemplate", + "PassClass": "FullScreenTriangle", + "Slots": [ + { + "Name": "ColorInput", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_inputDimensions" + }, + { + "Name": "DepthInput", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ImageViewDesc": { + "AspectFlags": [ + "Depth" + ] + } + }, + { + "Name": "OutputColorAndCoC", + "SlotType": "Output", + "ScopeAttachmentUsage": "RenderTarget", + "ShaderImageDimensionsConstant": "m_outputDimensions", + "LoadStoreAction": { + "LoadAction": "Clear" + } + } + ], + "ImageAttachments": [ + { + "Name": "OutputAttachment", + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "ColorInput" + }, + "Multipliers": { + "WidthMultiplier": 0.5, + "HeightMultiplier": 0.5 + } + }, + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT" + } + } + ], + "Connections": [ + { + "LocalSlot": "OutputColorAndCoC", + "AttachmentRef": { + "Pass": "This", + "Attachment": "OutputAttachment" + } + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/NewDepthOfFieldDownsample.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterLarge.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterLarge.pass new file mode 100644 index 0000000000..7b40009cec --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterLarge.pass @@ -0,0 +1,62 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldFilterLargeTemplate", + "PassClass": "NewDepthOfFieldFilterPass", + "Slots": [ + { + "Name": "ColorAndCoc", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_textureDimensions" + }, + { + "Name": "CocTile", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "OutputColorAndCoc", + "SlotType": "Output", + "ScopeAttachmentUsage": "RenderTarget", + "LoadStoreAction": { + "LoadAction": "Clear" + } + } + ], + "ImageAttachments": [ + { + "Name": "OutputAttachment", + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "ColorAndCoc" + } + }, + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT" + } + } + ], + "Connections": [ + { + "LocalSlot": "OutputColorAndCoc", + "AttachmentRef": { + "Pass": "This", + "Attachment": "OutputAttachment" + } + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/NewDepthOfFieldFilterLarge.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterSmall.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterSmall.pass new file mode 100644 index 0000000000..35a658a3b1 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldFilterSmall.pass @@ -0,0 +1,62 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldFilterSmallTemplate", + "PassClass": "NewDepthOfFieldFilterPass", + "Slots": [ + { + "Name": "ColorAndCoc", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_textureDimensions" + }, + { + "Name": "CocTile", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "OutputColorAndCoc", + "SlotType": "Output", + "ScopeAttachmentUsage": "RenderTarget", + "LoadStoreAction": { + "LoadAction": "Clear" + } + } + ], + "ImageAttachments": [ + { + "Name": "OutputAttachment", + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "ColorAndCoc" + } + }, + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT" + } + } + ], + "Connections": [ + { + "LocalSlot": "OutputColorAndCoc", + "AttachmentRef": { + "Pass": "This", + "Attachment": "OutputAttachment" + } + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/NewDepthOfFieldFilterSmall.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTile3x3.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTile3x3.pass new file mode 100644 index 0000000000..93ae645c83 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTile3x3.pass @@ -0,0 +1,57 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldTile3x3Template", + "PassClass": "FullScreenTriangle", + "Slots": [ + { + "Name": "Input", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_textureDimensions" + }, + { + "Name": "Output", + "SlotType": "Output", + "ScopeAttachmentUsage": "RenderTarget", + "LoadStoreAction": { + "LoadAction": "Clear" + } + } + ], + "ImageAttachments": [ + { + "Name": "OutputAttachment", + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "Input" + } + }, + "ImageDescriptor": { + "Format": "R16G16_SNORM" + } + } + ], + "Connections": [ + { + "LocalSlot": "Output", + "AttachmentRef": { + "Pass": "This", + "Attachment": "OutputAttachment" + } + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/NewDepthOfFieldTile3x3.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTileReduce.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTileReduce.pass new file mode 100644 index 0000000000..2bcf0ef32d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfFieldTileReduce.pass @@ -0,0 +1,63 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "NewDepthOfFieldTileReduceTemplate", + "PassClass": "NewDepthOfFieldTileReducePass", + "Slots": [ + { + "Name": "ColorAndCocInput", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_inputDimensions" + }, + { + "Name": "MinMaxCoC", + "SlotType": "Output", + "ScopeAttachmentUsage": "Shader", + "ShaderImageDimensionsConstant": "m_outputDimensions", + "LoadStoreAction": { + "LoadAction": "Clear" + } + } + ], + "ImageAttachments": [ + { + "Name": "MinMaxCoCAttachment", + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "ColorAndCocInput" + }, + "Multipliers": { + // 1/16 = 0.0625 + "WidthMultiplier": 0.0625, + "HeightMultiplier": 0.0625 + } + }, + "ImageDescriptor": { + "Format": "R16G16_SNORM" + } + } + ], + "Connections": [ + { + "LocalSlot": "MinMaxCoC", + "AttachmentRef": { + "Pass": "This", + "Attachment": "MinMaxCoCAttachment" + } + } + ], + "PassData": { + "$type": "ComputePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/NewDepthOfFieldTileReduce.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset index 76285b00c7..355e930237 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset +++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset @@ -185,6 +185,34 @@ "Path": "Passes/DepthOfFieldWriteFocusDepthFromGpu.pass" }, { + "Name": "NewDepthOfFieldTemplate", + "Path": "Passes/NewDepthOfField.pass" + }, + { + "Name": "NewDepthOfFieldDownsampleTemplate", + "Path": "Passes/NewDepthOfFieldDownsample.pass" + }, + { + "Name": "NewDepthOfFieldTileReduceTemplate", + "Path": "Passes/NewDepthOfFieldTileReduce.pass" + }, + { + "Name": "NewDepthOfFieldTile3x3Template", + "Path": "Passes/NewDepthOfFieldTile3x3.pass" + }, + { + "Name": "NewDepthOfFieldFilterLargeTemplate", + "Path": "Passes/NewDepthOfFieldFilterLarge.pass" + }, + { + "Name": "NewDepthOfFieldFilterSmallTemplate", + "Path": "Passes/NewDepthOfFieldFilterSmall.pass" + }, + { + "Name": "NewDepthOfFieldCompositeTemplate", + "Path": "Passes/NewDepthOfFieldComposite.pass" + }, + { "Name": "EsmShadowmapsTemplate", "Path": "Passes/EsmShadowmaps.pass" }, diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass index fb27770da3..dc1c0f1664 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass @@ -112,20 +112,41 @@ } ] }, + //{ + // "Name": "DepthOfFieldPass", + // "TemplateName": "DepthOfFieldTemplate", + // "Enabled": true, + // "Connections": [ + // { + // "LocalSlot": "DoFColorInput", + // "AttachmentRef": { + // "Pass": "TaaPass", + // "Attachment": "OutputColor" + // } + // }, + // { + // "LocalSlot": "DoFDepthInput", + // "AttachmentRef": { + // "Pass": "Parent", + // "Attachment": "Depth" + // } + // } + // ] + //}, { "Name": "DepthOfFieldPass", - "TemplateName": "DepthOfFieldTemplate", + "TemplateName": "NewDepthOfFieldTemplate", "Enabled": true, "Connections": [ { - "LocalSlot": "DoFColorInput", + "LocalSlot": "LightingBuffer", "AttachmentRef": { "Pass": "TaaPass", "Attachment": "OutputColor" } }, { - "LocalSlot": "DoFDepthInput", + "LocalSlot": "Depth", "AttachmentRef": { "Pass": "Parent", "Attachment": "Depth" @@ -142,7 +163,7 @@ "LocalSlot": "InputOutput", "AttachmentRef": { "Pass": "DepthOfFieldPass", - "Attachment": "DoFOutput" + "Attachment": "LightingBuffer" } } ] diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfField.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfField.azsli index bc94b4a793..f4c396253f 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfField.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfField.azsli @@ -14,6 +14,14 @@ inline float InvertDepth(float depth) return 1.0f - depth; } +inline float4 InvertDepth(float4 depth) +{ + // Convert depth from [1.0 - 0.0] to [0.0 - 1.0]. + // Set the front(near side) to 0.0 and the back(far side) to 1.0. + + return float4(1, 1, 1, 1) - depth; +} + inline float ConvertDofFactor(float depth, float far, float near, float focusDistance) { // dofFactor : The value Calculated from depth. diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli new file mode 100644 index 0000000000..fc98cee055 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldCommon.azsli @@ -0,0 +1,29 @@ +/* + * 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 + +#define COC_EPSILON 0.0001 + +#define SAMPLES_LOOP_1 8 +#define SAMPLES_LOOP_2 16 +#define SAMPLES_LOOP_3 24 + +// Must match the struct in NewDepthOfFieldPasses.cpp +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 new file mode 100644 index 0000000000..8a766c71d9 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.azsl @@ -0,0 +1,80 @@ +/* + * 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 +#include "NewDepthOfFieldCommon.azsli" +#include "DepthOfField.azsli" + +#include + +#define COC_EPSILON 0.0001 + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_depth; + Texture2D m_halfResColorAndCoc; + + // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + float4 m_fullResDimensions; + float4 m_halfResDimensions; + + Sampler LinearSampler + { + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +PSOutput MainPS(VSOutput IN) +{ + // Sampling positions + float2 fullResPixelPos = IN.m_position.xy; + float2 halfResPixelPos = fullResPixelPos * 0.5f; + float2 fullResUV = fullResPixelPos * PassSrg::m_fullResDimensions.zw; + float2 halfResUV = halfResPixelPos * PassSrg::m_halfResDimensions.zw; + + // Full res CoC (Circle of Confusion) + float depth = PassSrg::m_depth.Sample(PassSrg::LinearSampler, fullResUV); + float far = ViewSrg::m_dof.m_cameraParameters.x; + float near = ViewSrg::m_dof.m_cameraParameters.y; + 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(0.25f * 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; + + // 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; + OUT.m_color.a = alpha; + + return OUT; +} + diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.shader new file mode 100644 index 0000000000..f17837b330 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldComposite.shader @@ -0,0 +1,31 @@ +{ + "Source" : "NewDepthOfFieldComposite", + + "DepthStencilState" : + { + "Depth" : { "Enable" : false }, + "Stencil" : { "Enable" : false } + }, + + "BlendState" : { + "Enable" : true, + "BlendSource" : "AlphaSource", + "BlendDest" : "AlphaSourceInverse", + "BlendOp" : "Add" + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl new file mode 100644 index 0000000000..c8070178f0 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl @@ -0,0 +1,100 @@ +/* + * 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 +#include "NewDepthOfFieldCommon.azsli" +#include "DepthOfField.azsli" + +#include + +#define COC_EPSILON 0.0001 + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_colorTexture; + Texture2D m_depth; + + // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + float4 m_inputDimensions; + float4 m_outputDimensions; + + Sampler PointSampler + { + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +PSOutput MainPS(VSOutput IN) +{ + // Sampling positions + float2 outputPixelPos = IN.m_position.xy; + float2 inputPixelPos = outputPixelPos * 2.0f; + float2 inputUV = inputPixelPos * PassSrg::m_inputDimensions.zw; + + // Gather Depth + float4 depthGather = PassSrg::m_depth.Gather(PassSrg::PointSampler, inputUV); + depthGather = InvertDepth(depthGather); + + // Calculate CoC (Circle of Confusion) + float far = ViewSrg::m_dof.m_cameraParameters.x; + float near = ViewSrg::m_dof.m_cameraParameters.y; + float focusDistance = ViewSrg::m_dof.m_cameraParameters.z; + + float4 cocGather; + cocGather.x = ConvertDofFactor(depthGather.x, far, near, focusDistance); + cocGather.y = ConvertDofFactor(depthGather.y, far, near, focusDistance); + cocGather.z = ConvertDofFactor(depthGather.z, far, near, focusDistance); + cocGather.w = ConvertDofFactor(depthGather.w, far, near, focusDistance); + + // Clamp CoC + cocGather = clamp(cocGather, -1.0f, 1.0f); + + // Weigh samles by CoC to avoid in foces pixels bleeding into bokeh effect + float4 weights = abs(cocGather) + COC_EPSILON; + weights = weights / (weights.x + weights.y + weights.z + weights.w); + + PSOutput OUT; + + // Red + float4 redGather = PassSrg::m_colorTexture.GatherRed(PassSrg::PointSampler, inputUV); + OUT.m_color.r = dot(redGather, weights); + + // Green + float4 greenGather = PassSrg::m_colorTexture.GatherGreen(PassSrg::PointSampler, inputUV); + OUT.m_color.g = dot(greenGather, weights); + + // Blue + float4 blueGather = PassSrg::m_colorTexture.GatherBlue(PassSrg::PointSampler, inputUV); + OUT.m_color.b = dot(blueGather, weights); + + // CoC - Take the CoC with the maximum absolute value (note CoC can be negative) to get the fullest bokeh effect + // The above weighting by CoC mitigates bokeh bleeding from taking the max CoC + float coc = cocGather.x; + coc = abs(coc) < abs(cocGather.y) ? cocGather.y : coc; + coc = abs(coc) < abs(cocGather.z) ? cocGather.z : coc; + coc = abs(coc) < abs(cocGather.w) ? cocGather.w : coc; + + // CoC weighting #2: we use linear sampling when we compute the CoC blur + // This can lead to in focus pixels bleeding into the bokeh blur + // Pre-multiply the color values by the CoC to avoid this type of bleeding + // Because we then re-multiply by the CoC value after the linear sampling, we want to avoid coc values of 0 + // 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/NewDepthOfFieldDownsample.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.shader new file mode 100644 index 0000000000..00aa89e6d8 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldDownsample.shader @@ -0,0 +1,22 @@ +{ + "Source" : "NewDepthOfFieldDownsample", + + "DepthStencilState" : { + "Depth" : { "Enable" : false } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl new file mode 100644 index 0000000000..e566db7880 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl @@ -0,0 +1,50 @@ +/* + * 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; + }; +} + +PSOutput MainPS(VSOutput IN) +{ + PSOutput OUT = (PSOutput)0; + + float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, IN.m_texCoord); + float3 centerColor = centerSample.rgb; + float centerCoc = centerSample.a; + + centerColor /= centerCoc; + + OUT.m_color.rgb = centerColor; + OUT.m_color.a = centerCoc; + return OUT; +} + diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.shader new file mode 100644 index 0000000000..8f6faedb76 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.shader @@ -0,0 +1,22 @@ +{ + "Source" : "NewDepthOfFieldFilterLarge", + + "DepthStencilState" : { + "Depth" : { "Enable" : false } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl new file mode 100644 index 0000000000..dadaf57506 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl @@ -0,0 +1,74 @@ +/* + * 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, float radiusMultiplier) +{ + return PassSrg::m_dofConstants.samplePositions[index] * radiusMultiplier * PassSrg::m_textureDimensions.zw; +} + +PSOutput MainPS(VSOutput IN) +{ + // UV of pixel being shaded + float2 pixelUV = IN.m_texCoord.xy; + + // Sample pixel being shaded + 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; + + // 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 + + for(uint i = 0; i < SAMPLES_LOOP_1; ++i) + { + float2 offsetUV = GetOffsetUV(i, cocRadius); + float4 sample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offsetUV).rgba; + float cocDiff = abs(sample.a - centerCoC); + float weight = saturate( 2 - (20 * cocDiff)); + color += sample.rgb * weight; + totalWeight += weight; + } + + // Output + PSOutput OUT; + OUT.m_color.rgb = color / totalWeight; + OUT.m_color.a = centerCoc; + return OUT; +} + diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.shader new file mode 100644 index 0000000000..d05e09be8f --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.shader @@ -0,0 +1,22 @@ +{ + "Source" : "NewDepthOfFieldFilterSmall", + + "DepthStencilState" : { + "Depth" : { "Enable" : false } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl new file mode 100644 index 0000000000..7238b391aa --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl @@ -0,0 +1,66 @@ +/* + * 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 "NewDepthOfFieldCommon.azsli" + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_minMaxSource; + + // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + float4 m_textureDimensions; + + Sampler PointSampler + { + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +struct PSOutput +{ + float2 m_color : SV_Target0; +}; + +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; + + float cocMin = 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 X = 0.0f; X < 3.0f; X += 1.0f) + { + float2 sampleUV = mad(float2(X, Y), stepSize, 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; + return output; +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.shader new file mode 100644 index 0000000000..f7d9cc160e --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTile3x3.shader @@ -0,0 +1,22 @@ +{ + "Source" : "NewDepthOfFieldTile3x3", + + "DepthStencilState" : { + "Depth" : { "Enable" : false } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl new file mode 100644 index 0000000000..2705e1fdfd --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl @@ -0,0 +1,83 @@ +/* + * 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 "NewDepthOfFieldCommon.azsli" + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + // For this shader we're only interested in the CoC values, which are in the alpha channel + Texture2D m_colorAndCoC; + + // Tiled min/max CoC values + RWTexture2D m_minMaxCoC; + + // Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height + float4 m_inputDimensions; + float4 m_outputDimensions; + + Sampler LinearSampler + { + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +groupshared uint LDS_MIN_COC[8]; +groupshared uint LDS_MAX_COC[8]; + +[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) +{ + // Initialize groupshared mem for atomic min/max operations + if(group_thread_id.y == 0) + { + LDS_MIN_COC[group_thread_id.x] = 0xFFFFFFFF; + LDS_MAX_COC[group_thread_id.x] = 0; + } + + // We use gather to get 2x2 values at once, so thread samples are spaced 2 pixels apart (+1 so the sample position is in between the four pixels) + float2 samplePos = float2(dispatch_id.xy) * 2 + float2(1, 1); + float2 sampleUV = samplePos * PassSrg::m_inputDimensions.zw; + + // Gather CoC + float4 cocGather = PassSrg::m_colorAndCoC.GatherAlpha(PassSrg::LinearSampler, sampleUV); + float cocMin = min4(cocGather); + float cocMax = max4(cocGather); + + // 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) ); + + // Sync LDS + GroupMemoryBarrierWithGroupSync(); + + if(group_thread_id.y != 0) + { + return; + } + + InterlockedMin( LDS_MIN_COC[0], LDS_MIN_COC[group_thread_id.x] ); + InterlockedMax( LDS_MAX_COC[0], LDS_MAX_COC[group_thread_id.x] ); + + if(group_thread_id.x == 0) + { + // Unpack uints + cocMin = asfloat(LDS_MIN_COC[0]) - 1; + cocMax = asfloat(LDS_MAX_COC[0]) - 1; + + // Output min/max coc of 16x16 region + PassSrg::m_minMaxCoC[group_id.xy] = float2(cocMin, cocMax); + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.shader new file mode 100644 index 0000000000..f2da5305e5 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldTileReduce.shader @@ -0,0 +1,14 @@ +{ + "Source" : "NewDepthOfFieldTileReduce", + + "ProgramSettings" : + { + "EntryPoints": + [ + { + "name" : "MainCS", + "type" : "Compute" + } + ] + } +} 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 60614993b5..d1f94afe3c 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 @@ -1,9 +1,8 @@ # -# 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 -# +# 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 # set(FILES @@ -86,7 +85,6 @@ set(FILES Passes/CascadedShadowmaps.pass Passes/CheckerboardResolveColor.pass Passes/CheckerboardResolveDepth.pass - Passes/HDRColorGrading.pass Passes/ContrastAdaptiveSharpening.pass Passes/ConvertToAcescg.pass Passes/DebugOverlayParent.pass @@ -144,6 +142,7 @@ set(FILES Passes/ForwardSubsurfaceMSAA.pass Passes/FullscreenCopy.pass Passes/FullscreenOutputOnly.pass + Passes/HDRColorGrading.pass Passes/ImGui.pass Passes/KawaseShadowBlur.pass Passes/LightAdaptationParent.pass @@ -160,8 +159,6 @@ set(FILES Passes/LuminanceHistogramGenerator.pass Passes/MainPipeline.pass Passes/MainPipelineRenderToTexture.pass - Passes/ThumbnailPipeline.pass - Passes/ThumbnailPipelineRenderToTexture.pass Passes/MeshMotionVector.pass Passes/ModulateTexture.pass Passes/MorphTarget.pass @@ -169,6 +166,13 @@ set(FILES Passes/MSAAResolveColor.pass Passes/MSAAResolveCustom.pass Passes/MSAAResolveDepth.pass + Passes/NewDepthOfField.pass + Passes/NewDepthOfFieldComposite.pass + Passes/NewDepthOfFieldDownsample.pass + Passes/NewDepthOfFieldFilterLarge.pass + Passes/NewDepthOfFieldFilterSmall.pass + Passes/NewDepthOfFieldTile3x3.pass + Passes/NewDepthOfFieldTileReduce.pass Passes/OpaqueParent.pass Passes/PostProcessParent.pass Passes/ProjectedShadowmaps.pass @@ -204,11 +208,17 @@ set(FILES Passes/SsaoParent.pass Passes/SubsurfaceScattering.pass Passes/Taa.pass + Passes/ThumbnailPipeline.pass + Passes/ThumbnailPipelineRenderToTexture.pass Passes/Transparent.pass Passes/TransparentParent.pass Passes/UI.pass Passes/UIParent.pass + Scripts/material_find_overrides_demo.lua Scripts/material_property_overrides_demo.lua + ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli + ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli + ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli ShaderLib/Atom/Features/BlendUtility.azsli ShaderLib/Atom/Features/IndirectRendering.azsli ShaderLib/Atom/Features/MatrixUtility.azsli @@ -217,6 +227,8 @@ set(FILES ShaderLib/Atom/Features/SphericalHarmonicsUtility.azsli ShaderLib/Atom/Features/SrgSemantics.azsli ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli + ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli + ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCg_To_LinearSrgb.azsli ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/Aces_To_AcesCg.azsli ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/CalculateLuminance_AcesCg.azsli @@ -224,8 +236,6 @@ set(FILES ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_AcesCg.azsli ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_Srgb.azsli ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/Srgb_To_LinearSrgb.azsli - ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli - ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli ShaderLib/Atom/Features/CoreLights/PhotometricValue.azsli ShaderLib/Atom/Features/Decals/DecalTextureUtil.azsli ShaderLib/Atom/Features/LightCulling/LightCullingShared.azsli @@ -282,18 +292,23 @@ set(FILES ShaderLib/Atom/Features/PostProcessing/GlyphData.azsli ShaderLib/Atom/Features/PostProcessing/GlyphRender.azsli ShaderLib/Atom/Features/PostProcessing/PostProcessUtil.azsli + ShaderLib/Atom/Features/PostProcessing/Shapers.azsli + ShaderLib/Atom/Features/RayTracing/RayTracingMaterialSrg.azsli + ShaderLib/Atom/Features/RayTracing/RayTracingMaterialUtils.azsli ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli + ShaderLib/Atom/Features/RayTracing/RayTracingSceneUtils.azsli + ShaderLib/Atom/Features/RayTracing/RayTracingSrgs.azsl + ShaderLib/Atom/Features/RayTracing/RayTracingSrgs.shader ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli + ShaderLib/Atom/Features/Shadow/ReceiverPlaneDepthBias.azsli ShaderLib/Atom/Features/Shadow/Shadow.azsli ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli + ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli ShaderLib/Atom/Features/Vertex/VertexHelper.azsli - ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli - ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli - ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli ShaderResourceGroups/SceneSrg.azsli ShaderResourceGroups/SceneSrgAll.azsli ShaderResourceGroups/ViewSrg.azsli @@ -304,6 +319,8 @@ set(FILES ShaderResourceGroups/PostProcessing/SceneSrg.azsli ShaderResourceGroups/PostProcessing/ViewSrg.azsli ShaderResourceGroups/SkyBox/SceneSrg.azsli + Shaders/ForwardPassSrg.azsl + Shaders/ForwardPassSrg.shader Shaders/AuxGeom/AuxGeomObject.azsl Shaders/AuxGeom/AuxGeomObject.shader Shaders/AuxGeom/AuxGeomObjectLit.azsl @@ -318,14 +335,20 @@ set(FILES Shaders/Checkerboard/CheckerboardColorResolveCS.shader Shaders/Depth/DepthPass.azsl Shaders/Depth/DepthPass.shader + Shaders/Depth/DepthPassCommon.azsli + Shaders/Depth/DepthPassSkin.azsl + Shaders/Depth/DepthPassSkin.shader Shaders/Depth/DepthPassTransparentMax.shader Shaders/Depth/DepthPassTransparentMin.shader Shaders/DiffuseGlobalIllumination/DiffuseComposite.azsl Shaders/DiffuseGlobalIllumination/DiffuseComposite.shader + Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.azsl Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen.azsl Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen.shader + Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen_nomsaa.azsl Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.azsl Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.shader + Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.azsl Shaders/ImGui/ImGui.azsl Shaders/ImGui/ImGui.shader Shaders/LightCulling/LightCulling.azsl @@ -345,6 +368,9 @@ set(FILES Shaders/MotionVector/CameraMotionVector.shader Shaders/MotionVector/MeshMotionVector.azsl Shaders/MotionVector/MeshMotionVector.shader + Shaders/MotionVector/MeshMotionVectorCommon.azsli + Shaders/MotionVector/MeshMotionVectorSkin.azsl + Shaders/MotionVector/MeshMotionVectorSkin.shader Shaders/PostProcessing/AcesOutputTransformLut.azsl Shaders/PostProcessing/AcesOutputTransformLut.shader Shaders/PostProcessing/ApplyShaperLookupTable.azsl @@ -359,6 +385,8 @@ set(FILES Shaders/PostProcessing/BloomCompositeCS.shader Shaders/PostProcessing/BloomDownsampleCS.azsl Shaders/PostProcessing/BloomDownsampleCS.shader + Shaders/PostProcessing/ContrastAdaptiveSharpening.azsl + Shaders/PostProcessing/ContrastAdaptiveSharpening.shader Shaders/PostProcessing/ConvertToAcescg.azsl Shaders/PostProcessing/ConvertToAcescg.shader Shaders/PostProcessing/DepthDownsample.azsl @@ -415,6 +443,18 @@ set(FILES Shaders/PostProcessing/MSAAResolveCustom.shader Shaders/PostProcessing/MSAAResolveDepth.azsl Shaders/PostProcessing/MSAAResolveDepth.shader + Shaders/PostProcessing/NewDepthOfFieldComposite.azsl + Shaders/PostProcessing/NewDepthOfFieldComposite.shader + Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl + Shaders/PostProcessing/NewDepthOfFieldDownsample.shader + Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl + Shaders/PostProcessing/NewDepthOfFieldFilterLarge.shader + Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl + Shaders/PostProcessing/NewDepthOfFieldFilterSmall.shader + Shaders/PostProcessing/NewDepthOfFieldTile3x3.azsl + Shaders/PostProcessing/NewDepthOfFieldTile3x3.shader + Shaders/PostProcessing/NewDepthOfFieldTileReduce.azsl + Shaders/PostProcessing/NewDepthOfFieldTileReduce.shader Shaders/PostProcessing/OutputTransform.azsl Shaders/PostProcessing/OutputTransform.shader Shaders/PostProcessing/ScreenSpaceSubsurfaceScatteringCS.azsl @@ -431,13 +471,17 @@ set(FILES Shaders/PostProcessing/SMAAUtils.azsli Shaders/PostProcessing/SsaoCompute.azsl Shaders/PostProcessing/SsaoCompute.shader + Shaders/PostProcessing/Taa.azsl + Shaders/PostProcessing/Taa.shader Shaders/PostProcessing/UniformColor.azsl Shaders/PostProcessing/UniformColor.shader Shaders/Reflections/ReflectionCommon.azsli Shaders/Reflections/ReflectionComposite.azsl Shaders/Reflections/ReflectionComposite.shader + Shaders/Reflections/ReflectionComposite_nomsaa.azsl Shaders/Reflections/ReflectionGlobalFullscreen.azsl Shaders/Reflections/ReflectionGlobalFullscreen.shader + Shaders/Reflections/ReflectionGlobalFullscreen_nomsaa.azsl Shaders/Reflections/ReflectionProbeBlendWeight.azsl Shaders/Reflections/ReflectionProbeBlendWeight.shader Shaders/Reflections/ReflectionProbeRenderCommon.azsli @@ -466,6 +510,9 @@ set(FILES Shaders/Shadow/KawaseShadowBlur.shader Shaders/Shadow/Shadowmap.azsl Shaders/Shadow/Shadowmap.shader + Shaders/Shadow/ShadowmapCommon.azsli + Shaders/Shadow/ShadowmapSkin.azsl + Shaders/Shadow/ShadowmapSkin.shader Shaders/SkinnedMesh/LinearSkinningCS.azsl Shaders/SkinnedMesh/LinearSkinningCS.shader Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 22c5f37ff8..a7891b7907 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -248,6 +249,14 @@ namespace AZ passSystem->AddPassCreator(Name("DepthOfFieldReadBackFocusDepthPass"), &DepthOfFieldReadBackFocusDepthPass::Create); passSystem->AddPassCreator(Name("DepthOfFieldWriteFocusDepthFromGpuPass"), &DepthOfFieldWriteFocusDepthFromGpuPass::Create); + 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); passSystem->AddPassCreator(Name("FastDepthAwareBlurVerPass"), &FastDepthAwareBlurVerPass::Create); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp new file mode 100644 index 0000000000..7b9e46f6b1 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp @@ -0,0 +1,196 @@ +/* + * 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 +#include + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + + // Must match the struct in NewDepthOfFieldCommon.azsli + struct NewDepthOfFieldConstants + { + static constexpr uint32_t numberOfLoops = 3; + static constexpr float loopCounts[] = { 8.0f, 16.0f, 24.0f }; + + AZStd::array m_samplePositions; // XY are sample positions (normalized so max lenght is 1) + // Z is the length of XY (0 - 1) + // W is unused + }; + + + // --- Depth of Field Parent Pass --- + + RPI::Ptr NewDepthOfFieldParentPass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew NewDepthOfFieldParentPass(descriptor); + return AZStd::move(pass); + } + + NewDepthOfFieldParentPass::NewDepthOfFieldParentPass(const RPI::PassDescriptor& descriptor) + : RPI::ParentPass(descriptor) + { } + + bool NewDepthOfFieldParentPass::IsEnabled() const + { + if (!ParentPass::IsEnabled()) + { + return false; + } + RPI::Scene* scene = GetScene(); + if (!scene) + { + return false; + } + PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor(); + AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); + if (!fp) + { + return false; + } + PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view); + if (!postProcessSettings) + { + return false; + } + DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings(); + return (dofSettings != nullptr) && dofSettings->GetEnabled(); + } + + void NewDepthOfFieldParentPass::FrameBeginInternal(FramePrepareParams params) + { + RPI::Scene* scene = GetScene(); + PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor(); + AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); + if (fp) + { + PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view); + if (postProcessSettings) + { + DepthOfFieldSettings* dofSettings = postProcessSettings->GetDepthOfFieldSettings(); + if (dofSettings) + { + dofSettings->SetValuesToViewSrg(view->GetShaderResourceGroup()); + } + } + } + + ParentPass::FrameBeginInternal(params); + } + + // --- Tile Reduce Pass --- + + RPI::Ptr NewDepthOfFieldTileReducePass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew NewDepthOfFieldTileReducePass(descriptor); + return AZStd::move(pass); + } + + 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 + m_isFullscreenPass = false; + } + + void NewDepthOfFieldTileReducePass::FrameBeginInternal(FramePrepareParams params) + { + AZ_Assert(GetOutputCount() > 0, "NewDepthOfFieldTileReducePass: No output bindings!"); + RPI::PassAttachment* outputAttachment = GetOutputBinding(0).m_attachment.get(); + + AZ_Assert(outputAttachment != nullptr, "NewDepthOfFieldTileReducePass: Output binding has no attachment!"); + RHI::Size outputSize = outputAttachment->m_descriptor.m_image.m_size; + + // The algorithm outputs the min/max CoC values from a 16x16 region using 8x8 threads + u32 targetThreadCountX = outputSize.m_width * 8; + u32 targetThreadCountY = outputSize.m_height * 8; + SetTargetThreadCounts(targetThreadCountX, targetThreadCountY, 1); + + RPI::ComputePass::FrameBeginInternal(params); + } + + + + // --- Filter Pass --- + + RPI::Ptr NewDepthOfFieldFilterPass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew NewDepthOfFieldFilterPass(descriptor); + return AZStd::move(pass); + } + + NewDepthOfFieldFilterPass::NewDepthOfFieldFilterPass(const RPI::PassDescriptor& descriptor) + : RPI::FullscreenTrianglePass(descriptor) + { } + + void NewDepthOfFieldFilterPass::FrameBeginInternal(FramePrepareParams params) + { + NewDepthOfFieldConstants dofConstants; + + uint32_t sampleIndex = 0; + + for (uint32_t loop = 0; loop < NewDepthOfFieldConstants::numberOfLoops; ++loop) + { + float radius = (loop + 1.0f) / float(NewDepthOfFieldConstants::numberOfLoops); + float loopCount = NewDepthOfFieldConstants::loopCounts[loop]; + + for (float i = 0.0f; i < loopCount; ++i) + { + float angle = Constants::TwoPi * i / loopCount; + Vector2 pos = Vector2::CreateFromAngle(angle); + pos = pos * radius; + + dofConstants.m_samplePositions[sampleIndex][0] = pos.GetX(); + dofConstants.m_samplePositions[sampleIndex][1] = pos.GetY(); + dofConstants.m_samplePositions[sampleIndex][2] = radius; + dofConstants.m_samplePositions[sampleIndex][3] = 0.0f; + ++sampleIndex; + } + + } + + 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 new file mode 100644 index 0000000000..f7a0ee95ca --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.h @@ -0,0 +1,117 @@ +/* + * 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 + * + */ +#pragma once + +#include +#include +#include + +#include + +namespace AZ +{ + namespace Render + { + //! + class NewDepthOfFieldParentPass final + : public RPI::ParentPass + { + AZ_RPI_PASS(NewDepthOfFieldParentPass); + + public: + AZ_RTTI(AZ::Render::NewDepthOfFieldParentPass, "{71F4998B-447C-4BAC-A5BE-2D2850FABB57}", AZ::RPI::ParentPass); + AZ_CLASS_ALLOCATOR(NewDepthOfFieldParentPass, SystemAllocator, 0); + virtual ~NewDepthOfFieldParentPass() = default; + + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + bool IsEnabled() const override; + + protected: + // Behavior functions override... + void FrameBeginInternal(FramePrepareParams params) override; + + private: + NewDepthOfFieldParentPass(const RPI::PassDescriptor& descriptor); + }; + + + + //! + class NewDepthOfFieldTileReducePass final + : public RPI::ComputePass + { + AZ_RPI_PASS(NewDepthOfFieldTileReducePass); + + public: + AZ_RTTI(AZ::Render::NewDepthOfFieldTileReducePass, "{2E072695-0847-43A6-9BE4-D6D85CFFBA41}", AZ::RPI::ComputePass); + AZ_CLASS_ALLOCATOR(NewDepthOfFieldTileReducePass, SystemAllocator, 0); + virtual ~NewDepthOfFieldTileReducePass() = default; + + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + protected: + // Behavior functions override... + void FrameBeginInternal(FramePrepareParams params) override; + + private: + NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor); + }; + + + + //! + class NewDepthOfFieldFilterPass final + : public RPI::FullscreenTrianglePass + { + AZ_RPI_PASS(NewDepthOfFieldFilterPass); + + public: + AZ_RTTI(AZ::Render::NewDepthOfFieldFilterPass, "{F8A98E53-1A50-4178-A6EB-2BD0148C038B}", AZ::RPI::FullscreenTrianglePass); + AZ_CLASS_ALLOCATOR(NewDepthOfFieldFilterPass, SystemAllocator, 0); + virtual ~NewDepthOfFieldFilterPass() = default; + + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + protected: + // Behavior functions override... + void FrameBeginInternal(FramePrepareParams params) override; + + private: + NewDepthOfFieldFilterPass(const RPI::PassDescriptor& descriptor); + + // SRG binding indices... + AZ::RHI::ShaderInputNameIndex m_constantsIndex = "m_dofConstants"; + }; + + + + //! + 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 diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp index 779f02cba0..643d9bb96d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp @@ -168,7 +168,7 @@ namespace AZ::Render // The ImageViewDescriptor must be specified to make sure the frame graph compiler doesn't treat this as a transient image. RHI::ImageViewDescriptor viewDesc = RHI::ImageViewDescriptor::Create(imageDesc.m_format, 0, 0); viewDesc.m_aspectFlags = RHI::ImageAspectFlags::Color; - viewDesc.m_overrideBindFlags = RHI::ImageBindFlags::ShaderReadWrite; + //viewDesc.m_overrideBindFlags = RHI::ImageBindFlags::ShaderReadWrite; // The full path name is needed for the attachment image so it's not deduplicated from accumulation images in different pipelines. AZStd::string imageName = RPI::ConcatPassString(GetPathName(), attachment->m_path); diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 18cdc273d2..23a67ef5db 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -240,6 +240,8 @@ set(FILES Source/PostProcessing/LookModificationTransformPass.h Source/PostProcessing/LuminanceHistogramGeneratorPass.h Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp + Source/PostProcessing/NewDepthOfFieldPasses.cpp + Source/PostProcessing/NewDepthOfFieldPasses.h Source/PostProcessing/PostProcessingShaderOptionBase.cpp Source/PostProcessing/PostProcessingShaderOptionBase.h Source/PostProcessing/SMAABasePass.cpp diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderInputNameIndex.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderInputNameIndex.h index 03062afd52..5e9b1a9c77 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderInputNameIndex.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ShaderInputNameIndex.h @@ -67,6 +67,10 @@ namespace AZ bool IsInitialized() const; void AssetInialized() const; + // Retrieves the underlying name. Should only be used for debug purposes like printing the name when we fail to bind to the SRG. + // All regular functionality should go through the above functions. + const Name& GetNameForDebug() const; + private: enum class IndexType : u32 diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderInputNameIndex.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderInputNameIndex.cpp index 2eb23895f8..b7ed2dbfe7 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderInputNameIndex.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ShaderInputNameIndex.cpp @@ -227,5 +227,11 @@ namespace AZ } + const Name& ShaderInputNameIndex::GetNameForDebug() const + { + AZ_Assert(HasName(), "GetNameForDebug() called on ShaderInputNameIndex that doesn't have a name set. Please initialize it with a name.", m_name.GetCStr()); + return m_name; + } + } } diff --git a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/Math.azsli b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/Math.azsli index 80f8a6cc36..6ffdb6e815 100644 --- a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/Math.azsli +++ b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/Math.azsli @@ -31,6 +31,8 @@ void swap(inout float a, inout float b) b = c; } +// ---------- Power ----------- + float Pow2(float x) { return x * x; @@ -48,6 +50,44 @@ float Pow5(float x) { return x * Pow4(x); } + +// ---------- Min & Max ----------- + +float min3(float a, float b, float c) +{ + return min(min(a, b), c); +} +float min4(float a, float b, float c, float d) +{ + return min(min3(a, b, c), d); +} +float max3(float a, float b, float c) +{ + return max(max(a, b), c); +} +float max4(float a, float b, float c, float d) +{ + return max(max3(a, b, c), d); +} + +float min3(float3 abc) +{ + return min3(abc.x, abc.y, abc.z); +} +float min4(float4 abcd) +{ + return min4(abcd.x, abcd.y, abcd.z, abcd.w); +} +float max3(float3 abc) +{ + return max3(abc.x, abc.y, abc.z); +} +float max4(float4 abcd) +{ + return max4(abcd.x, abcd.y, abcd.z, abcd.w); +} + + // ---------- Intersection ----------- // a simple ray sphere intersection function, didn't take limited precision diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h index babcf752e9..d60a5a8064 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h @@ -10,6 +10,8 @@ #include #include +#include + #include namespace AZ @@ -145,7 +147,11 @@ namespace AZ //! Name of the SRG member this binds to (see PassSlot::m_shaderInputName for more details) Name m_shaderInputName = Name("AutoBind"); - + + //! Name index of the SRG constant to which, if specified, we automatically calculate + //! and bind the image dimensions (if this binding is of type image) + RHI::ShaderInputNameIndex m_shaderImageDimensionsNameIndex; + //! Whether binding is an input, output or inputOutput PassSlotType m_slotType = PassSlotType::Uninitialized; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h index cbff297021..5fb90d044e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h @@ -119,7 +119,7 @@ namespace AZ private: // Helper function that binds a single attachment to the pass shader resource group - void BindAttachment(const RHI::FrameGraphCompileContext& context, const PassAttachmentBinding& binding, int16_t& imageIndex, int16_t& bufferIndex); + void BindAttachment(const RHI::FrameGraphCompileContext& context, PassAttachmentBinding& binding, int16_t& imageIndex, int16_t& bufferIndex); // Helper function to get the query by the scope index and query type RHI::Ptr GetQuery(ScopeQueryType queryType); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/PassAttachmentReflect.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/PassAttachmentReflect.h index 1131f2ff70..0de3676abe 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/PassAttachmentReflect.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/PassAttachmentReflect.h @@ -87,6 +87,13 @@ namespace AZ //! The keyword "NoBind" means the slot will not bind it's attachment to the SRG Name m_shaderInputName = Name("AutoBind"); + //! Name of the shader resource group constant (must be float4) to which the pass can automatically bind the following: + //! X component = image width + //! Y component = image height + //! Z component = 1 / image width + //! W component = 1 / image height + Name m_shaderImageDimensionsName; + //! This is to specify an array index if the shader input is an array. //! e.g. Texture2DMS m_color[4]; uint16_t m_shaderInputArrayIndex = 0; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp index e0831381e7..3b4f10a968 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp @@ -187,6 +187,7 @@ namespace AZ { m_name = slot.m_name; m_shaderInputName = slot.m_shaderInputName; + m_shaderImageDimensionsNameIndex = slot.m_shaderImageDimensionsName; m_shaderInputArrayIndex = slot.m_shaderInputArrayIndex; m_slotType = slot.m_slotType; m_scopeAttachmentUsage = slot.m_scopeAttachmentUsage; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index 318ea7d11f..dad511def1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -272,15 +273,8 @@ namespace AZ } } - void RenderPass::BindAttachment(const RHI::FrameGraphCompileContext& context, const PassAttachmentBinding& binding, int16_t& imageIndex, int16_t& bufferIndex) + void RenderPass::BindAttachment(const RHI::FrameGraphCompileContext& context, PassAttachmentBinding& binding, int16_t& imageIndex, int16_t& bufferIndex) { - if (binding.m_shaderInputIndex == PassAttachmentBinding::ShaderInputNoBind || - binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::RenderTarget || - binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::DepthStencil) - { - return; - } - PassAttachment* attachment = binding.m_attachment.get(); if (attachment) { @@ -293,11 +287,39 @@ namespace AZ inputIndex = imageIndex; } const RHI::ImageView* imageView = context.GetImageView(attachment->GetAttachmentId(), binding.m_attachmentUsageIndex); - m_shaderResourceGroup->SetImageView(RHI::ShaderInputImageIndex(inputIndex), imageView, arrayIndex); - ++imageIndex; + + if (binding.m_shaderImageDimensionsNameIndex.HasName()) + { + RHI::Size size = attachment->m_descriptor.m_image.m_size; + + AZ::Vector4 imageDimensions; + imageDimensions.SetX(float(size.m_width)); + imageDimensions.SetY(float(size.m_height)); + imageDimensions.SetZ(1.0f / float(size.m_width)); + imageDimensions.SetW(1.0f / float(size.m_height)); + + bool success = m_shaderResourceGroup->SetConstant(binding.m_shaderImageDimensionsNameIndex, imageDimensions); + AZ_Assert(success, "Pass [%s] Could not find float4 constant [%s] in Shader Resource Group [%s]", + GetPathName().GetCStr(), + binding.m_shaderImageDimensionsNameIndex.GetNameForDebug().GetCStr(), + m_shaderResourceGroup->GetDatabaseName()); + } + + if (binding.m_shaderInputIndex != PassAttachmentBinding::ShaderInputNoBind && + binding.m_scopeAttachmentUsage != RHI::ScopeAttachmentUsage::RenderTarget && + binding.m_scopeAttachmentUsage != RHI::ScopeAttachmentUsage::DepthStencil) + { + m_shaderResourceGroup->SetImageView(RHI::ShaderInputImageIndex(inputIndex), imageView, arrayIndex); + ++imageIndex; + } } else if (attachment->GetAttachmentType() == RHI::AttachmentType::Buffer) { + if (binding.m_shaderInputIndex == PassAttachmentBinding::ShaderInputNoBind) + { + return; + } + if (inputIndex == PassAttachmentBinding::ShaderInputAutoBind) { inputIndex = bufferIndex; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Pass/PassAttachmentReflect.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Pass/PassAttachmentReflect.cpp index 39be08d299..602793ba19 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Pass/PassAttachmentReflect.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Pass/PassAttachmentReflect.cpp @@ -56,9 +56,10 @@ namespace AZ ; serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("Name", &PassSlot::m_name) ->Field("ShaderInputName", &PassSlot::m_shaderInputName) + ->Field("ShaderImageDimensionsConstant", &PassSlot::m_shaderImageDimensionsName) ->Field("ShaderInputArrayIndex", &PassSlot::m_shaderInputArrayIndex) ->Field("SlotType", &PassSlot::m_slotType) ->Field("ScopeAttachmentUsage", &PassSlot::m_scopeAttachmentUsage) From d04d9883bc3c3f5b63ea1bb99725ee715969d002 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 00:42:48 -0700 Subject: [PATCH 2/9] New Depth Of Field working quite well with a small amount of artefacts Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Common/Assets/Passes/NewDepthOfField.pass | 16 ++- .../NewDepthOfFieldCommon.azsli | 2 + .../NewDepthOfFieldComposite.azsl | 23 ++-- .../NewDepthOfFieldDownsample.azsl | 2 +- .../NewDepthOfFieldFilterLarge.azsl | 101 +++++++++++++++-- ...epthOfFieldFilterLarge.azsl~RF1bf9782e.TMP | 105 ++++++++++++++++++ .../NewDepthOfFieldFilterSmall.azsl | 36 ++++-- 7 files changed, 253 insertions(+), 32 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl~RF1bf9782e.TMP 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) { + // 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 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; + + + PSOutput OUT = (PSOutput)0; - - float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, IN.m_texCoord); - float3 centerColor = centerSample.rgb; - float centerCoc = centerSample.a; - - centerColor /= centerCoc; - - OUT.m_color.rgb = centerColor; - OUT.m_color.a = centerCoc; + 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; } From 60148ccc3975bf8bcd1f18fe3298d04a530ef135 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 01:23:43 -0700 Subject: [PATCH 3/9] New Depth of Field - Minor improvements, optimizations, and now works with auto focus Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Common/Assets/Passes/NewDepthOfField.pass | 13 +++++++++ .../NewDepthOfFieldFilterLarge.azsl | 28 +++++++++++++++---- .../NewDepthOfFieldFilterSmall.azsl | 15 ++++++++-- .../PostProcessing/NewDepthOfFieldPasses.cpp | 8 ++++++ 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass index 483ce0e49a..70cebab5a1 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/NewDepthOfField.pass @@ -18,6 +18,19 @@ } ], "PassRequests": [ + { + "Name": "AutoFocus", + "TemplateName": "DepthOfFieldReadBackFocusDepthTemplate", + "Connections": [ + { + "LocalSlot": "DepthInput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "Depth" + } + } + ] + }, { "Name": "Downsample", "TemplateName": "NewDepthOfFieldDownsampleTemplate", diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl index 497d73444b..6ab47b14ea 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl @@ -85,6 +85,24 @@ PSOutput MainPS(VSOutput IN) float4 backgroundColor = float4(0, 0, 0, 0); + if(minCoc >= 0) + { + 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::LinearSampler, pixelUV + offset.xy).rgba; + + // Calculate weight for sample + float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc); + + // Accumulate + color += weight * sampleColorCoc; + } + } + else { float backgroundMin = min(0, centerCoc); color.rgb /= abs(color.a); @@ -112,17 +130,15 @@ PSOutput MainPS(VSOutput IN) backgroundColor += isBackground * sampleColorCoc; color += !isBackground * sampleColorCoc; } + + backgroundColor.rgb /= max(backgroundColor.a, COC_EPSILON); } - float backgroundRatio = backgroundColor.a / float(SAMPLES_LOOP_TOTAL); + float backgroundRatio = saturate( 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; - + color = lerp(color, backgroundColor, backgroundRatio); PSOutput OUT = (PSOutput)0; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl index 440701ded9..05227cfee7 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterSmall.azsl @@ -31,6 +31,16 @@ ShaderResourceGroup PassSrg : SRG_PerPass AddressV = Clamp; AddressW = Clamp; }; + + Sampler PointSampler + { + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; } float2 GetOffsetUV(uint index, float2 offsetMultiplier) @@ -44,7 +54,7 @@ PSOutput MainPS(VSOutput IN) float2 pixelUV = IN.m_texCoord.xy; // Sample pixel being shaded - float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba; + float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV).rgba; float centerCoc = centerSample.a; // Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w @@ -65,7 +75,7 @@ PSOutput MainPS(VSOutput IN) float2 offsetUV = GetOffsetUV(i, offsetMultiplier); // Get sample - float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offsetUV).rgba; + float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offsetUV).rgba; // Calculate weight float cocDiff = sampleColorCoc.a - centerCoc; @@ -85,4 +95,3 @@ PSOutput MainPS(VSOutput IN) OUT.m_color.a = centerCoc; return OUT; } - diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp index 7b9e46f6b1..b69484297a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/NewDepthOfFieldPasses.cpp @@ -149,6 +149,14 @@ namespace AZ float radius = (loop + 1.0f) / float(NewDepthOfFieldConstants::numberOfLoops); float loopCount = NewDepthOfFieldConstants::loopCounts[loop]; + float angleOffset = 0; + + // Every other loop slightly rotate sample ring so they don't line up + if (loop & 1) + { + angleOffset = Constants::TwoPi * 0.5f / loopCount; + } + for (float i = 0.0f; i < loopCount; ++i) { float angle = Constants::TwoPi * i / loopCount; 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 4/9] 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 From 6e7d2e6dd62bbb26114e20637a1704076553f1fd Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 04:48:45 -0700 Subject: [PATCH 5/9] removing commented line in TAA pass Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp index 643d9bb96d..574d959c07 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp @@ -168,7 +168,6 @@ namespace AZ::Render // The ImageViewDescriptor must be specified to make sure the frame graph compiler doesn't treat this as a transient image. RHI::ImageViewDescriptor viewDesc = RHI::ImageViewDescriptor::Create(imageDesc.m_format, 0, 0); viewDesc.m_aspectFlags = RHI::ImageAspectFlags::Color; - //viewDesc.m_overrideBindFlags = RHI::ImageBindFlags::ShaderReadWrite; // The full path name is needed for the attachment image so it's not deduplicated from accumulation images in different pipelines. AZStd::string imageName = RPI::ConcatPassString(GetPathName(), attachment->m_path); From 58a518ce692f18a1378d6a4d02f252ce56d4ec69 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 04:52:46 -0700 Subject: [PATCH 6/9] removing accidental file Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- ...epthOfFieldFilterLarge.azsl~RF1bf9782e.TMP | 105 ------------------ 1 file changed, 105 deletions(-) delete mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl~RF1bf9782e.TMP 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 deleted file mode 100644 index 7c0f32381b..0000000000 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/NewDepthOfFieldFilterLarge.azsl~RF1bf9782e.TMP +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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; -} - From 7eaf54e48dd272ed2bd34bf03f4f69dbf7c1c213 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 21 Oct 2021 11:52:50 -0700 Subject: [PATCH 7/9] Adding 5361st maybe_unused to the code base to pass AR Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index dad511def1..b8115dff10 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -298,6 +298,7 @@ namespace AZ imageDimensions.SetZ(1.0f / float(size.m_width)); imageDimensions.SetW(1.0f / float(size.m_height)); + [[maybe_unused]] bool success = m_shaderResourceGroup->SetConstant(binding.m_shaderImageDimensionsNameIndex, imageDimensions); AZ_Assert(success, "Pass [%s] Could not find float4 constant [%s] in Shader Resource Group [%s]", GetPathName().GetCStr(), 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 8/9] 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 From ea1284c5810f738f400950bebc24a7d3021db807 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Fri, 22 Oct 2021 12:14:35 -0700 Subject: [PATCH 9/9] fixing up atom_feature_common_asset_files.cmake Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Common/Assets/atom_feature_common_asset_files.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 a33034a1b3..94b711e86c 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 @@ -160,8 +160,6 @@ set(FILES Passes/LutGeneration.pass Passes/MainPipeline.pass Passes/MainPipelineRenderToTexture.pass - Passes/ToolsPipeline.pass - Passes/ToolsPipelineRenderToTexture.pass Passes/MeshMotionVector.pass Passes/ModulateTexture.pass Passes/MorphTarget.pass @@ -211,8 +209,8 @@ set(FILES Passes/SsaoParent.pass Passes/SubsurfaceScattering.pass Passes/Taa.pass - Passes/ThumbnailPipeline.pass - Passes/ThumbnailPipelineRenderToTexture.pass + Passes/ToolsPipeline.pass + Passes/ToolsPipelineRenderToTexture.pass Passes/Transparent.pass Passes/TransparentParent.pass Passes/UI.pass @@ -306,6 +304,7 @@ set(FILES ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli + ShaderLib/Atom/Features/Shadow/NormalOffsetShadows.azsli ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli ShaderLib/Atom/Features/Shadow/ReceiverPlaneDepthBias.azsli ShaderLib/Atom/Features/Shadow/Shadow.azsli