Merge pull request #4865 from aws-lumberyard-dev/Atom/antonmic/DepthOfField01

Atom/antonmic/depth of field01
This commit is contained in:
antonmic
2021-10-22 13:41:36 -07:00
committed by GitHub
38 changed files with 1876 additions and 30 deletions
@@ -0,0 +1,170 @@
{
"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": "AutoFocus",
"TemplateName": "DepthOfFieldReadBackFocusDepthTemplate",
"Connections": [
{
"LocalSlot": "DepthInput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "Depth"
}
}
]
},
{
"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": "Tile5x5",
"TemplateName": "NewDepthOfFieldTile3x3Template",
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "Tile3x3",
"Attachment": "Output"
}
}
]
},
{
"Name": "LargeFilter",
"TemplateName": "NewDepthOfFieldFilterLargeTemplate",
"Connections": [
{
"LocalSlot": "ColorAndCoc",
"AttachmentRef": {
"Pass": "Downsample",
"Attachment": "OutputColorAndCoC"
}
},
{
"LocalSlot": "CocTile",
"AttachmentRef": {
"Pass": "Tile5x5",
"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"
}
}
]
}
]
}
}
}
@@ -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"
}
}
}
}
@@ -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"
}
}
}
}
@@ -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"
}
}
}
}
@@ -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"
}
}
}
}
@@ -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"
}
}
}
}
@@ -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"
}
}
}
}
@@ -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"
},
@@ -112,20 +112,42 @@
}
]
},
// Todo: remove the old depth of field implementation and rename NewDepthOfField -> DepthOfField
//{
// "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 +164,7 @@
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "DepthOfFieldPass",
"Attachment": "DoFOutput"
"Attachment": "LightingBuffer"
}
}
]
@@ -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.
@@ -0,0 +1,27 @@
/*
* 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 <viewsrg.srgi>
#define COC_EPSILON 0.0001
#define SAMPLES_LOOP_1 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
{
float4 samplePositions[60]; // XY are sample positions (normalized so max lenght is 1)
// Z is the length of XY (0 - 1)
// W is unused
};
@@ -0,0 +1,120 @@
/*
* 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 <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include <Atom/RPI/Math.azsli>
#include "NewDepthOfFieldCommon.azsli"
#include "DepthOfField.azsli"
#include <viewsrg.srgi>
#define COC_EPSILON 0.0001
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float4> m_depth;
Texture2D<float4> 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;
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);
// --- Weights based on CoC similarity ---
// Gather CoCs
float4 cocGather = PassSrg::m_halfResColorAndCoc.GatherAlpha(PassSrg::LinearSampler, halfResUV);
// Calculate differences
float4 diff = saturate(cocGather - coc);
// 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/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)
? ( (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);
// --- Alpha ---
// 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);
PSOutput OUT;
OUT.m_color.rgb = color.rgb;
OUT.m_color.a = alpha;
return OUT;
}
@@ -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"
}
]
}
}
@@ -0,0 +1,101 @@
/*
* 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 <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include <Atom/RPI/Math.azsli>
#include "NewDepthOfFieldCommon.azsli"
#include "DepthOfField.azsli"
#include <viewsrg.srgi>
#define COC_EPSILON 0.0001
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float4> m_colorTexture;
Texture2D<float4> 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;
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);
// 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);
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;
}
@@ -0,0 +1,22 @@
{
"Source" : "NewDepthOfFieldDownsample",
"DepthStencilState" : {
"Depth" : { "Enable" : false }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -0,0 +1,170 @@
/*
* 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 <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include "DepthOfField.azsli"
#include "NewDepthOfFieldCommon.azsli"
#include <viewsrg.srgi>
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float4> m_colorAndCoc;
Texture2D<float2> 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;
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
Sampler PointSampler
{
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
}
float3 GetOffset(uint index, float2 offsetUVMultiplier)
{
float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz;
offset.xy *= offsetUVMultiplier;
return offset;
}
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));
// 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 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
float2 pixelUV = IN.m_texCoord;
float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba;
float centerCoc = color.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 = max( abs(centerCoc), -minCoc);
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 = GetOffset(i, offsetMultiplier);
// Get sample
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offset.xy).rgba;
// Calculate weight for sample
float weight = CalculateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc);
// Accumulate
color += weight * sampleColorCoc;
}
}
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 = GetOffset(i, offsetMultiplier);
// Get sample + unpack
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba;
sampleColorCoc.rgb /= abs(sampleColorCoc.a);
// Calculate weight for sample
float weight = CalculateWeight(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;
}
// 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;
return OUT;
}
@@ -0,0 +1,22 @@
{
"Source" : "NewDepthOfFieldFilterLarge",
"DepthStencilState" : {
"Depth" : { "Enable" : false }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -0,0 +1,121 @@
/*
* 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 <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include "DepthOfField.azsli"
#include "NewDepthOfFieldCommon.azsli"
#include <viewsrg.srgi>
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float4> m_colorAndCoc;
Texture2D<float2> 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;
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
Sampler PointSampler
{
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
}
float3 GetOffset(uint index, float2 offsetUVMultiplier)
{
float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz;
offset.xy *= offsetUVMultiplier;
return offset;
}
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));
// 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)
{
// Get center sample
float2 pixelUV = IN.m_texCoord.xy;
float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV).rgba;
float centerCoc = color.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 = 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);
// Weight accumulation. Start with 1 for center pixel.
float totalWeight = 1;
for(uint i = 0; i < SAMPLES_LOOP_1; ++i)
{
// Calculate sample offset
float3 offset = GetOffset(i, offsetMultiplier);
// Get sample
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba;
// Calculate weight
float weight = CalculateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc);
// Accumulate sample and weight
color.rgb += sampleColorCoc.rgb * weight;
totalWeight += weight;
}
// Normalize accumulated sample
color.rgb /= totalWeight;
PSOutput OUT;
OUT.m_color.rgb = color.rgb;
OUT.m_color.a = centerCoc;
return OUT;
}
@@ -0,0 +1,22 @@
{
"Source" : "NewDepthOfFieldFilterSmall",
"DepthStencilState" : {
"Depth" : { "Enable" : false }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -0,0 +1,68 @@
/*
* 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 <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include "NewDepthOfFieldCommon.azsli"
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float2> 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
{
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
}
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 pixelSizeInUV = PassSrg::m_textureDimensions.zw;
float2 startUV = startPixelPos * pixelSizeInUV;
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), 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;
return output;
}
@@ -0,0 +1,22 @@
{
"Source" : "NewDepthOfFieldTile3x3",
"DepthStencilState" : {
"Depth" : { "Enable" : false }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -0,0 +1,87 @@
/*
* 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 <Atom/Features/SrgSemantics.azsli>
#include <Atom/RPI/Math.azsli>
#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<float4> m_colorAndCoC;
// Tiled min/max CoC values
RWTexture2D<float2> 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;
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];
// 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)
{
// 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;
}
// 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
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);
}
}
@@ -0,0 +1,14 @@
{
"Source" : "NewDepthOfFieldTileReduce",
"ProgramSettings" :
{
"EntryPoints":
[
{
"name" : "MainCS",
"type" : "Compute"
}
]
}
}
@@ -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
@@ -161,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
@@ -170,6 +167,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
@@ -205,11 +209,17 @@ set(FILES
Passes/SsaoParent.pass
Passes/SubsurfaceScattering.pass
Passes/Taa.pass
Passes/ToolsPipeline.pass
Passes/ToolsPipelineRenderToTexture.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
@@ -218,6 +228,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
@@ -225,8 +237,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
@@ -284,17 +294,23 @@ set(FILES
ShaderLib/Atom/Features/PostProcessing/GlyphRender.azsli
ShaderLib/Atom/Features/PostProcessing/HDRColorGradingCommon.azsl
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/NormalOffsetShadows.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
@@ -305,6 +321,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
@@ -321,14 +339,20 @@ set(FILES
Shaders/ColorGrading/LutGeneration.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
@@ -348,6 +372,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
@@ -362,6 +389,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
@@ -418,6 +447,19 @@ 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
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
@@ -434,13 +476,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
@@ -469,6 +515,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
@@ -51,6 +51,7 @@
#include <PostProcessing/DepthOfFieldParentPass.h>
#include <PostProcessing/DepthOfFieldReadBackFocusDepthPass.h>
#include <PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.h>
#include <PostProcessing/NewDepthOfFieldPasses.h>
#include <PostProcessing/EyeAdaptationPass.h>
#include <PostProcessing/LuminanceHistogramGeneratorPass.h>
#include <PostProcessing/FastDepthAwareBlurPasses.h>
@@ -250,6 +251,10 @@ 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);
// Add FastDepthAwareBlur passes
passSystem->AddPassCreator(Name("FastDepthAwareBlurHorPass"), &FastDepthAwareBlurHorPass::Create);
passSystem->AddPassCreator(Name("FastDepthAwareBlurVerPass"), &FastDepthAwareBlurVerPass::Create);
@@ -0,0 +1,176 @@
/*
* 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 <AzCore/Math/MathUtils.h>
#include <PostProcess/PostProcessFeatureProcessor.h>
#include <PostProcess/DepthOfField/DepthOfFieldSettings.h>
#include <PostProcessing/NewDepthOfFieldPasses.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/View.h>
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<float[4], 60> 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> NewDepthOfFieldParentPass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<NewDepthOfFieldParentPass> 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<PostProcessFeatureProcessor>();
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<PostProcessFeatureProcessor>();
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> NewDepthOfFieldTileReducePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<NewDepthOfFieldTileReducePass> pass = aznew NewDepthOfFieldTileReducePass(descriptor);
return AZStd::move(pass);
}
NewDepthOfFieldTileReducePass::NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor)
: RPI::ComputePass(descriptor)
{
// 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;
}
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> NewDepthOfFieldFilterPass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<NewDepthOfFieldFilterPass> 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;
// 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 angleStep = Constants::TwoPi / loopCount;
// Every other loop slightly rotate sample ring so they don't line up
float angle = (loop & 1) ? (angleStep * 0.5f) : 0;
for (float i = 0.0f; i < loopCount; ++i)
{
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;
angle += angleStep;
}
}
m_shaderResourceGroup->SetConstant(m_constantsIndex, dofConstants);
RPI::FullscreenTrianglePass::FrameBeginInternal(params);
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,119 @@
/*
* 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 <Atom/RPI.Public/Pass/ComputePass.h>
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
#include <Atom/RPI.Public/Pass/ParentPass.h>
#include <PostProcessing/PostProcessingShaderOptionBase.h>
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
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<NewDepthOfFieldParentPass> Create(const RPI::PassDescriptor& descriptor);
bool IsEnabled() const override;
protected:
// Behavior functions override...
void FrameBeginInternal(FramePrepareParams params) override;
private:
NewDepthOfFieldParentPass(const RPI::PassDescriptor& descriptor);
};
//! Need a class for the tile reduce pass because it dispatches a non-trivial number of threads
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<NewDepthOfFieldTileReducePass> Create(const RPI::PassDescriptor& descriptor);
protected:
// Behavior functions override...
void FrameBeginInternal(FramePrepareParams params) override;
private:
NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor);
};
//! 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
{
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<NewDepthOfFieldFilterPass> 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";
};
} // namespace Render
} // namespace AZ
@@ -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);
@@ -243,6 +243,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
@@ -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
@@ -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;
}
}
}
@@ -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
@@ -10,6 +10,8 @@
#include <AtomCore/Instance/Instance.h>
#include <AtomCore/Instance/InstanceData.h>
#include <Atom/RHI.Reflect/ShaderInputNameIndex.h>
#include <Atom/RPI.Reflect/Pass/PassAttachmentReflect.h>
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;
@@ -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<Query> GetQuery(ScopeQueryType queryType);
@@ -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<float4> m_color[4];
uint16_t m_shaderInputArrayIndex = 0;
@@ -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;
@@ -16,6 +16,7 @@
#include <Atom/RHI.Reflect/ImageScopeAttachmentDescriptor.h>
#include <Atom/RPI.Reflect/Pass/RenderPassData.h>
#include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
#include <Atom/RHI.Reflect/Size.h>
#include <Atom/RPI.Public/GpuQuery/Query.h>
#include <Atom/RPI.Public/Pass/PassUtils.h>
@@ -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,40 @@ 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));
[[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(),
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;
@@ -56,9 +56,10 @@ namespace AZ
;
serializeContext->Class<PassSlot>()
->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)