diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpace.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpace.pass index 4972f0f494..d1825be820 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpace.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpace.pass @@ -34,10 +34,6 @@ } ], "PassRequests": [ - { - "Name": "ReflectionScreenSpaceBlurPass", - "TemplateName": "ReflectionScreenSpaceBlurPassTemplate" - }, { "Name": "ReflectionScreenSpaceTracePass", "TemplateName": "ReflectionScreenSpaceTracePassTemplate", @@ -57,18 +53,44 @@ } }, { - "LocalSlot": "DepthStencilInput", + "LocalSlot": "SpecularF0Input", "AttachmentRef": { "Pass": "Parent", - "Attachment": "DepthStencilInput" - + "Attachment": "SpecularF0Input" } }, { - "LocalSlot": "SpecularF0Input", + "LocalSlot": "ReflectionInputOutput", "AttachmentRef": { "Pass": "Parent", - "Attachment": "SpecularF0Input" + "Attachment": "ReflectionInputOutput" + } + } + ] + }, + { + "Name": "ReflectionScreenSpaceBlurPass", + "TemplateName": "ReflectionScreenSpaceBlurPassTemplate", + "Connections": [ + { + "LocalSlot": "DepthInput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "DepthStencilInput" + } + }, + { + "LocalSlot": "ScreenSpaceReflectionInputOutput", + "AttachmentRef": { + "Pass": "ReflectionScreenSpaceTracePass", + "Attachment": "ScreenSpaceReflectionOutput" + } + }, + { + "LocalSlot": "DownsampledDepthInputOutput", + "AttachmentRef": { + "Pass": "ReflectionScreenSpaceTracePass", + "Attachment": "DownsampledDepthOutput" } } ] @@ -76,22 +98,19 @@ { "Name": "ReflectionScreenSpaceCompositePass", "TemplateName": "ReflectionScreenSpaceCompositePassTemplate", - "ExecuteAfter": [ - "ReflectionScreenSpaceBlurPass" - ], "Connections": [ { - "LocalSlot": "TraceInput", + "LocalSlot": "ReflectionInput", "AttachmentRef": { - "Pass": "ReflectionScreenSpaceTracePass", - "Attachment": "Output" + "Pass": "ReflectionScreenSpaceBlurPass", + "Attachment": "ScreenSpaceReflectionInputOutput" } }, { - "LocalSlot": "PreviousFrameBufferInput", + "LocalSlot": "DownsampledDepthInput", "AttachmentRef": { "Pass": "ReflectionScreenSpaceBlurPass", - "Attachment": "PreviousFrameInputOutput" + "Attachment": "DownsampledDepthInputOutput" } }, { @@ -115,6 +134,13 @@ "Attachment": "DepthStencilInput" } }, + { + "LocalSlot": "PreviousFrameInputOutput", + "AttachmentRef": { + "Pass": "ReflectionScreenSpaceTracePass", + "Attachment": "PreviousFrameInputOutput" + } + }, { "LocalSlot": "DepthStencilInput", "AttachmentRef": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass index e2fde2d4ef..a5fd2fdfb1 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass @@ -8,34 +8,19 @@ "PassClass": "ReflectionScreenSpaceBlurPass", "Slots": [ { - "Name": "PreviousFrameInputOutput", - "SlotType": "InputOutput", + "Name": "DepthInput", + "SlotType": "Input", "ScopeAttachmentUsage": "Shader" - } - ], - "ImageAttachments": [ + }, { - "Name": "PreviousFrameImage", - "SizeSource": { - "Source": { - "Pass": "Parent", - "Attachment": "SpecularInput" - } - }, - "ImageDescriptor": { - "Format": "R16G16B16A16_FLOAT", - "SharedQueueMask": "Graphics" - }, - "GenerateFullMipChain": true - } - ], - "Connections": [ + "Name": "ScreenSpaceReflectionInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "Shader" + }, { - "LocalSlot": "PreviousFrameInputOutput", - "AttachmentRef": { - "Pass": "This", - "Attachment": "PreviousFrameImage" - } + "Name": "DownsampledDepthInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "DepthStencil" } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlurVertical.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlurVertical.pass index a616ed4c8e..af3878cf6b 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlurVertical.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlurVertical.pass @@ -7,6 +7,11 @@ "Name": "ReflectionScreenSpaceBlurVerticalPassTemplate", "PassClass": "ReflectionScreenSpaceBlurChildPass", "Slots": [ + { + "Name": "DepthInput", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader" + }, { "Name": "Input", "SlotType": "InputOutput", @@ -16,6 +21,20 @@ "Name": "Output", "SlotType": "InputOutput", "ScopeAttachmentUsage": "RenderTarget" + }, + { + "Name": "DownsampledDepthOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "DepthStencil" + } + ], + "Connections": [ + { + "LocalSlot": "DepthInput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "DepthInput" + } } ], "PassData": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass index 5443c32406..17b58dbc9e 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass @@ -8,12 +8,12 @@ "PassClass": "ReflectionScreenSpaceCompositePass", "Slots": [ { - "Name": "TraceInput", + "Name": "ReflectionInput", "SlotType": "Input", "ScopeAttachmentUsage": "Shader" }, { - "Name": "PreviousFrameBufferInput", + "Name": "DownsampledDepthInput", "SlotType": "Input", "ScopeAttachmentUsage": "Shader" }, @@ -37,6 +37,11 @@ ] } }, + { + "Name": "PreviousFrameInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "Shader" + }, { "Name": "DepthStencilInput", "SlotType": "Input", diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceTrace.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceTrace.pass index 370db1f45a..824d23a046 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceTrace.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceTrace.pass @@ -5,7 +5,7 @@ "ClassData": { "PassTemplate": { "Name": "ReflectionScreenSpaceTracePassTemplate", - "PassClass": "FullScreenTriangle", + "PassClass": "ReflectionScreenSpaceTracePass", "Slots": [ { "Name": "DepthStencilTextureInput", @@ -28,24 +28,52 @@ "ScopeAttachmentUsage": "Shader" }, { - "Name": "DepthStencilInput", + "Name": "ReflectionInputOutput", "SlotType": "Input", - "ScopeAttachmentUsage": "DepthStencil", - "ImageViewDesc": { - "AspectFlags": [ - "Stencil" - ] + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "PreviousFrameInputOutput", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "ScreenSpaceReflectionOutput", + "SlotType": "Output", + "ScopeAttachmentUsage": "RenderTarget", + "LoadStoreAction": { + "ClearValue": { + "Value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "LoadAction": "Clear" } }, { - "Name": "Output", + "Name": "DownsampledDepthOutput", "SlotType": "Output", - "ScopeAttachmentUsage": "RenderTarget" + "ScopeAttachmentUsage": "DepthStencil", + "LoadStoreAction": { + "ClearValue": { + "Type": "DepthStencil", + "Value": [ + 1.0, + {}, + {}, + {} + ] + }, + "LoadAction": "Clear" + } } ], "ImageAttachments": [ { - "Name": "TraceImage", + "Name": "ScreenSpaceReflectionImage", "SizeSource": { "Source": { "Pass": "This", @@ -56,9 +84,40 @@ "HeightMultiplier": 0.5 } }, - "MultisampleSource": { - "Pass": "This", - "Attachment": "SpecularF0Input" + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT", + "MipLevels": "5", + "SharedQueueMask": "Graphics" + } + }, + { + "Name": "DownsampledDepthImage", + "SizeSource": { + "Source": { + "Pass": "Parent", + "Attachment": "DepthStencilInput" + }, + "Multipliers": { + "WidthMultiplier": 0.5, + "HeightMultiplier": 0.5 + } + }, + "FormatSource": { + "Pass": "Parent", + "Attachment": "DepthStencilInput" + }, + "ImageDescriptor": { + "MipLevels": "5", + "SharedQueueMask": "Graphics" + } + }, + { + "Name": "PreviousFrameImage", + "SizeSource": { + "Source": { + "Pass": "Parent", + "Attachment": "SpecularInput" + } }, "ImageDescriptor": { "Format": "R16G16B16A16_FLOAT", @@ -68,15 +127,28 @@ ], "Connections": [ { - "LocalSlot": "Output", + "LocalSlot": "ScreenSpaceReflectionOutput", + "AttachmentRef": { + "Pass": "This", + "Attachment": "ScreenSpaceReflectionImage" + } + }, + { + "LocalSlot": "DownsampledDepthOutput", + "AttachmentRef": { + "Pass": "This", + "Attachment": "DownsampledDepthImage" + } + }, + { + "LocalSlot": "PreviousFrameInputOutput", "AttachmentRef": { "Pass": "This", - "Attachment": "TraceImage" + "Attachment": "PreviousFrameImage" } } ], - "PassData": - { + "PassData": { "$type": "FullscreenTrianglePassData", "ShaderAsset": { "FilePath": "Shaders/Reflections/ReflectionScreenSpaceTrace.shader" diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurCommon.azsli index 1e4d4af8a2..3d38df2816 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurCommon.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurCommon.azsli @@ -6,11 +6,31 @@ * */ -// 7-tap Gaussian Kernel (Sigma 1.1) -static const uint GaussianKernelSize = 7; -static const int2 TexelOffsetsV[GaussianKernelSize] = {{0, -3}, {0, -2}, {0, -1}, {0, 0}, {0, 1}, {0, 2}, {0, 3}}; -static const int2 TexelOffsetsH[GaussianKernelSize] = {{-3, 0}, {-2, 0}, {-1, 0}, {0, 0}, {1, 0}, {2, 0}, {3, 0}}; -static const float TexelWeights[GaussianKernelSize] = {0.010805f, 0.074929f, 0.238727f, 0.351078f, 0.238727f, 0.074929f, 0.010805f}; +// Gaussian Kernel Radius 9, Sigma 1.8 +static const uint GaussianKernelSize = 19; +static const int2 TexelOffsetsV[GaussianKernelSize] = {{0, -9}, {0, -8}, {0, -7}, {0, -6}, {0, -5}, {0, -4}, {0, -3}, {0, -2}, {0, -1}, {0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}}; +static const int2 TexelOffsetsH[GaussianKernelSize] = {{-9, 0}, {-8, 0}, {-7, 0}, {-6, 0}, {-5, 0}, {-4, 0}, {-3, 0}, {-2, 0}, {-1, 0}, {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}; +static const float TexelWeights[GaussianKernelSize] = { + 0.0000011022801820635918f, + 0.000014295732881160677f, + 0.0001370168487067367f, + 0.0009708086495991633f, + 0.005086391900047703f, + 0.019711193240183777f, + 0.056512463228943335f, + 0.11989501853796679f, + 0.18826323520204147f, + 0.21881694875889543f, + 0.18826323520204147f, + 0.11989501853796679f, + 0.056512463228943335f, + 0.019711193240183777f, + 0.005086391900047703f, + 0.0009708086495991633f, + 0.0001370168487067367f, + 0.000014295732881160677f, + 0.0000011022801820635918f +}; float3 GaussianFilter(uint2 screenCoords, int2 texelOffsets[GaussianKernelSize], RWTexture2D inputImage) { diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.azsl index cfc35d10e4..bdc787350e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.azsl @@ -10,12 +10,13 @@ #include #include -#include #include +#include #include "ReflectionScreenSpaceBlurCommon.azsli" ShaderResourceGroup PassSrg : SRG_PerPass { + Texture2DMS m_depth; RWTexture2D m_input; RWTexture2D m_output; uint m_imageWidth; @@ -26,13 +27,39 @@ ShaderResourceGroup PassSrg : SRG_PerPass #include // Pixel Shader +struct PSOutput +{ + float4 m_color : SV_Target0; + float m_depth : SV_Depth; +}; + PSOutput MainPS(VSOutput IN) { // vertical blur uses coordinates from the mip0 input image - uint2 coords = IN.m_position.xy * PassSrg::m_outputScale; - float3 result = GaussianFilter(coords, TexelOffsetsV, PassSrg::m_input); + uint2 halfResCoords = IN.m_position.xy * PassSrg::m_outputScale; + float3 result = GaussianFilter(halfResCoords, TexelOffsetsV, PassSrg::m_input); + + // downsample depth, using fullscreen image coordinates + float downsampledDepth = 0; + if (PassSrg::m_input[halfResCoords].w > 0.0f) + { + uint2 fullScreenCoords = halfResCoords * 2; + + for (int y = -2; y < 2; ++y) + { + for (int x = -2; x < 2; ++x) + { + float depth = PassSrg::m_depth.Load(fullScreenCoords + int2(x, y), 0).r; + if (depth > downsampledDepth) + { + downsampledDepth = depth; + } + } + } + } PSOutput OUT; OUT.m_color = float4(result, 1.0f); + OUT.m_depth = downsampledDepth; return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.shader b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.shader index dcebb4d2ae..92995bd69f 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.shader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceBlurVertical.shader @@ -10,7 +10,8 @@ { "Depth" : { - "Enable" : false + "Enable" : true, // required to bind the depth buffer SRV + "CompareFunc" : "Always" } }, diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl index a0c31442fa..6cd4ce16f5 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl @@ -12,17 +12,19 @@ #include #include #include +#include #include #include #include ShaderResourceGroup PassSrg : SRG_PerPass { - Texture2DMS m_trace; - Texture2D m_previousFrame; + Texture2D m_reflection; + Texture2D m_downsampledDepth; Texture2DMS m_normal; // RGB10 = Normal (Encoded), A2 = Flags Texture2DMS m_specularF0; // RGB8 = SpecularF0, A8 = Roughness Texture2DMS m_depth; + Texture2D m_previousFrame; Sampler LinearSampler { @@ -40,6 +42,49 @@ ShaderResourceGroup PassSrg : SRG_PerPass #include +float3 SampleReflection(float2 reflectionUV, float mip, float depth, float3 normal, uint2 invDimensions) +{ + const float DepthTolerance = 0.001f; + + // attempt to trivially accept the downsampled reflection texel + float downsampledDepth = PassSrg::m_downsampledDepth.SampleLevel(PassSrg::LinearSampler, reflectionUV, floor(mip)).r; + if (abs(depth - downsampledDepth) <= DepthTolerance) + { + // use this reflection sample + float3 reflection = PassSrg::m_reflection.SampleLevel(PassSrg::LinearSampler, reflectionUV, mip).rgb; + return reflection; + } + + // neighborhood search surrounding the downsampled texel, searching for the closest matching depth + float closestDepthDelta = 1.0f; + int2 closestOffsetUV = float2(0.0f, 0.0f); + for (int y = -4; y <= 4; ++y) + { + for (int x = -4; x <= 4; ++x) + { + float2 offsetUV = float2(x * invDimensions.x, y * invDimensions.y); + float downsampledDepth = PassSrg::m_downsampledDepth.SampleLevel(PassSrg::LinearSampler, reflectionUV + offsetUV, floor(mip)).r; + float depthDelta = abs(depth - downsampledDepth); + + if (depthDelta <= DepthTolerance) + { + // depth is within tolerance, use this texel + float3 reflection = PassSrg::m_reflection.SampleLevel(PassSrg::LinearSampler, reflectionUV + offsetUV, mip).rgb; + return reflection; + } + + if (closestDepthDelta > depthDelta) + { + closestDepthDelta = depthDelta; + closestOffsetUV = offsetUV; + } + } + } + + float3 reflection = PassSrg::m_reflection.SampleLevel(PassSrg::LinearSampler, reflectionUV + closestOffsetUV, mip).rgb; + return reflection; +} + // Pixel Shader PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) { @@ -52,11 +97,21 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) // compute trace image coordinates for the half-res image float2 traceCoords = screenCoords * 0.5f; - // load trace data and check w-component to see if there was a hit - float4 traceData = PassSrg::m_trace.Load(traceCoords, sampleIndex); - if (traceData.w <= 0.0f) + // check reflection data mip0 to see if there was a hit + float4 reflectionData = PassSrg::m_reflection.Load(uint3(traceCoords, 0)); + if (reflectionData.w <= 0.0f) + { + // fallback to the cubemap reflections currently in the reflection buffer + discard; + } + + // load specular and roughness + float4 specularF0 = PassSrg::m_specularF0.Load(screenCoords, sampleIndex); + float roughness = specularF0.a; + const float MaxRoughness = 0.5f; + if (roughness > MaxRoughness) { - // no hit, fallback to the cubemap reflections currently in the reflection buffer + // fallback to the cubemap reflections currently in the reflection buffer discard; } @@ -65,8 +120,9 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) float depth = PassSrg::m_depth.Load(screenCoords, sampleIndex).r; float2 ndcPos = float2(UV.x, 1.0f - UV.y) * 2.0f - 1.0f; float4 projectedPos = float4(ndcPos, depth, 1.0f); - float4 positionWS = mul(ViewSrg::m_viewProjectionInverseMatrix, projectedPos); - positionWS /= positionWS.w; + float4 positionVS = mul(ViewSrg::m_projectionMatrixInverse, projectedPos); + positionVS /= positionVS.w; + float3 positionWS = mul(ViewSrg::m_viewMatrixInverse, positionVS).xyz; // compute ray from camera to surface position float3 cameraToPositionWS = normalize(positionWS.xyz - ViewSrg::m_worldPosition); @@ -74,42 +130,16 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) // retrieve surface normal float4 encodedNormal = PassSrg::m_normal.Load(screenCoords, sampleIndex); float3 normalWS = DecodeNormalSignedOctahedron(encodedNormal.rgb); - - // compute surface specular - float4 specularF0 = PassSrg::m_specularF0.Load(screenCoords, sampleIndex); - float roughness = specularF0.a; float NdotV = dot(normalWS, -cameraToPositionWS); - float3 specular = FresnelSchlickWithRoughness(NdotV, specularF0.rgb, roughness); - - // reconstruct the world space position of the trace coordinates - float2 traceUV = saturate(traceData.xy / dimensions); - float traceDepth = PassSrg::m_depth.Load(traceData.xy, sampleIndex).r; - float2 traceNDC = float2(traceUV.x, 1.0f - traceUV.y) * 2.0f - 1.0f; - float4 traceProjectedPos = float4(traceNDC, traceDepth, 1.0f); - float4 tracePositionVS = mul(ViewSrg::m_projectionMatrixInverse, traceProjectedPos); - tracePositionVS /= tracePositionVS.w; - float4 tracePositionWS = mul(ViewSrg::m_viewMatrixInverse, tracePositionVS); - - // reproject to the previous frame image coordinates - float4 tracePrevNDC = mul(ViewSrg::m_viewProjectionPrevMatrix, tracePositionWS); - tracePrevNDC /= tracePrevNDC.w; - float2 tracePrevUV = float2(tracePrevNDC.x, -1.0f * tracePrevNDC.y) * 0.5f + 0.5f; - - // compute the roughness mip to use in the previous frame image + + // compute the roughness mip to use in the reflection image // remap the roughness mip into a lower range to more closely match the material roughness values - const float MaxRoughness = 0.5f; float mip = saturate(roughness / MaxRoughness) * PassSrg::m_maxMipLevel; - // sample reflection value from the roughness mip - float4 reflectionColor = float4(PassSrg::m_previousFrame.SampleLevel(PassSrg::LinearSampler, tracePrevUV, mip).rgb, 1.0f); - - // fade rays close to screen edge - const float ScreenFadeDistance = 0.95f; - float2 fadeAmount = max(max(0.0f, traceUV - ScreenFadeDistance), max(0.0f, 1.0f - traceUV - ScreenFadeDistance)); - fadeAmount /= (1.0f - ScreenFadeDistance); - float alpha = 1.0f - max(fadeAmount.x, fadeAmount.y); - + // sample reflection color from the mip chain + float3 reflectionColor = SampleReflection(IN.m_texCoord, mip, depth, normalWS, 1.0f / dimensions); + PSOutput OUT; - OUT.m_color = float4(reflectionColor.rgb * specular, alpha); + OUT.m_color = float4(reflectionColor, reflectionData.w); return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.azsl index c95befce05..7c18b7f5de 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.azsl @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -20,6 +20,18 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2DMS m_depth; Texture2DMS m_normal; // RGB10 = Normal (Encoded), A2 = Flags Texture2DMS m_specularF0; // RGB8 = SpecularF0, A8 = Roughness + Texture2DMS m_reflection; + Texture2D m_previousFrame; + + Sampler LinearSampler + { + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; } #include @@ -49,6 +61,12 @@ VSOutput MainVS(VSInput input) } // Pixel Shader +struct PSOutput +{ + float4 m_color : SV_Target0; + float m_depth : SV_Depth; +}; + PSOutput MainPS(VSOutput IN) { // compute screen coords based on a half-res render target @@ -83,16 +101,83 @@ PSOutput MainPS(VSOutput IN) // reflect view ray around surface normal float3 reflectDirVS = normalize(reflect(cameraToPositionVS, normalVS)); + // check to see if the reflected direction is approaching the camera + float rdotv = dot(reflectDirVS, -cameraToPositionVS); + bool fallbackEdge = false; + if (rdotv >= -0.05f) + { + if (rdotv >= 0.0f) + { + // ray points back to camera, fallback to cubemaps + discard; + } + + // ray is approaching the camera direction, but not there yet - trace the reflection and set this + // as a non-reflected pixel, which will prevent artifacts at the boundary + fallbackEdge = true; + } + // trace screenspace rays against the depth buffer to find the screenspace intersection coordinates float4 result = float4(0.0f, 0.0f, 0.0f, 0.0f); float2 hitCoords = float2(0.0f, 0.0f); if (TraceRayScreenSpace(positionVS, reflectDirVS, dimensions, hitCoords)) { - float rdotv = dot(reflectDirVS, cameraToPositionVS); - result = float4(hitCoords, 0.0f, rdotv); + // reconstruct the world space position of the trace coordinates + float2 traceUV = saturate(hitCoords / dimensions); + float traceDepth = PassSrg::m_depth.Load(hitCoords, 0).r; + float2 traceNDC = float2(traceUV.x, 1.0f - traceUV.y) * 2.0f - 1.0f; + float4 traceProjectedPos = float4(traceNDC, traceDepth, 1.0f); + float4 tracePositionVS = mul(ViewSrg::m_projectionMatrixInverse, traceProjectedPos); + tracePositionVS /= tracePositionVS.w; + float4 tracePositionWS = mul(ViewSrg::m_viewMatrixInverse, tracePositionVS); + + // reproject to the previous frame image coordinates + float4 tracePrevNDC = mul(ViewSrg::m_viewProjectionPrevMatrix, tracePositionWS); + tracePrevNDC /= tracePrevNDC.w; + float2 tracePrevUV = float2(tracePrevNDC.x, -1.0f * tracePrevNDC.y) * 0.5f + 0.5f; + + // sample the previous frame image + result.rgb = PassSrg::m_previousFrame.SampleLevel(PassSrg::LinearSampler, tracePrevUV, 0).rgb; + + // apply surface specular + float3 specularF0 = PassSrg::m_specularF0.Load(screenCoords, 0).rgb; + result.rgb *= specularF0; + + // fade rays close to screen edge + const float ScreenFadeDistance = 0.95f; + float2 fadeAmount = max(max(0.0f, traceUV - ScreenFadeDistance), max(0.0f, 1.0f - traceUV - ScreenFadeDistance)); + fadeAmount /= (1.0f - ScreenFadeDistance); + result.a = fallbackEdge ? 0.0f : 1.0f - max(fadeAmount.x, fadeAmount.y); + } + else + { + // ray miss, add in the IBL/probe reflections from the specular pass + float4 positionWS = mul(ViewSrg::m_viewMatrixInverse, positionVS); + float3 cameraToPositionWS = normalize(positionWS - ViewSrg::m_worldPosition); + float3 reflectDirWS = normalize(reflect(cameraToPositionWS, normalWS)); + + result.rgb += PassSrg::m_reflection.Load(screenCoords, 0).rgb; + result.a = fallbackEdge ? 0.0f : 1.0f; + } + + // downsample depth + float downsampledDepth = 0.0f; + for (int y = -2; y < 2; ++y) + { + for (int x = -2; x < 2; ++x) + { + float depth = PassSrg::m_depth.Load(screenCoords + int2(x, y), 0).r; + + // take the closest depth sample (larger depth value due to reverse depth) + if (depth > downsampledDepth) + { + downsampledDepth = depth; + } + } } PSOutput OUT; OUT.m_color = result; + OUT.m_depth = downsampledDepth; return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.shader b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.shader index 563e0e3276..3ceabd404a 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.shader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceTrace.shader @@ -10,7 +10,8 @@ { "Depth" : { - "Enable" : false + "Enable" : true, // required to bind the depth buffer SRV + "CompareFunc" : "Always" } }, diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 2e5db39880..c3c189eb62 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -292,6 +293,7 @@ namespace AZ passSystem->AddPassCreator(Name("DeferredFogPass"), &DeferredFogPass::Create); // Add Reflection passes + passSystem->AddPassCreator(Name("ReflectionScreenSpaceTracePass"), &Render::ReflectionScreenSpaceTracePass::Create); passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurPass"), &Render::ReflectionScreenSpaceBlurPass::Create); passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurChildPass"), &Render::ReflectionScreenSpaceBlurChildPass::Create); passSystem->AddPassCreator(Name("ReflectionScreenSpaceCompositePass"), &Render::ReflectionScreenSpaceCompositePass::Create); diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp index a1858a7e9d..8c5e36e706 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp @@ -7,7 +7,7 @@ */ #include "ReflectionCopyFrameBufferPass.h" -#include "ReflectionScreenSpaceBlurPass.h" +#include "ReflectionScreenSpaceTracePass.h" #include #include @@ -28,16 +28,16 @@ namespace AZ void ReflectionCopyFrameBufferPass::BuildInternal() { - RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceTracePass"), GetRenderPipeline()); RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); - Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); + Render::ReflectionScreenSpaceTracePass* tracePass = azrtti_cast(pass); + Data::Instance& frameBufferAttachment = tracePass->GetPreviousFrameImageAttachment(); RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); - return RPI::PassFilterExecutionFlow::StopVisitingPasses; + return RPI::PassFilterExecutionFlow::StopVisitingPasses; }); FullscreenTrianglePass::BuildInternal(); diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index edd7ad1013..c0b25697a3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -79,7 +80,7 @@ namespace AZ horizontalBlurChildDesc.m_passTemplate = blurHorizontalPassTemplate; // add child passes to perform the vertical and horizontal Gaussian blur for each roughness mip level - for (uint32_t mip = 0; mip < m_numBlurMips; ++mip) + for (uint32_t mip = 0; mip < NumMipLevels - 1; ++mip) { // create Vertical blur child passes { @@ -114,35 +115,15 @@ namespace AZ RemoveChildren(); m_flags.m_createChildren = true; - Data::Instance pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); - - // retrieve the image attachment from the pass - AZ_Assert(m_ownedAttachments.size() == 1, "ReflectionScreenSpaceBlurPass must have exactly one ImageAttachment defined"); - RPI::Ptr reflectionImageAttachment = m_ownedAttachments[0]; - - // update the image attachment descriptor to sync up size and format - reflectionImageAttachment->Update(); - - // change the lifetime since we want it to live between frames - reflectionImageAttachment->m_lifetime = RHI::AttachmentLifetimeType::Imported; - - // set the bind flags - RHI::ImageDescriptor& imageDesc = reflectionImageAttachment->m_descriptor.m_image; - imageDesc.m_bindFlags |= RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite; - - // create the image attachment - RHI::ClearValue clearValue = RHI::ClearValue::CreateVector4Float(0, 0, 0, 0); - m_frameBufferImageAttachment = RPI::AttachmentImage::Create(*pool.get(), imageDesc, Name(reflectionImageAttachment->m_path.GetCStr()), &clearValue, nullptr); - - reflectionImageAttachment->m_path = m_frameBufferImageAttachment->GetAttachmentId(); - reflectionImageAttachment->m_importedResource = m_frameBufferImageAttachment; - - uint32_t mipLevels = reflectionImageAttachment->m_descriptor.m_image.m_mipLevels; + // retrieve the reflection, downsampled normal, and downsampled depth attachments + RPI::PassAttachment* reflectionImageAttachment = GetInputOutputBinding(0).m_attachment.get(); RHI::Size imageSize = reflectionImageAttachment->m_descriptor.m_image.m_size; + RPI::PassAttachment* downsampledDepthImageAttachment = GetInputOutputBinding(1).m_attachment.get(); + // create transient attachments, one for each blur mip level AZStd::vector transientPassAttachments; - for (uint32_t mip = 1; mip <= mipLevels - 1; ++mip) + for (uint32_t mip = 1; mip <= NumMipLevels - 1; ++mip) { RHI::Size mipSize = imageSize.GetReducedMip(mip); @@ -160,8 +141,6 @@ namespace AZ m_ownedAttachments.push_back(transientPassAttachment); } - m_numBlurMips = mipLevels - 1; - // call ParentPass::BuildInternal() first to configure the slots and auto-add the empty bindings, // then we will assign attachments to the bindings ParentPass::BuildInternal(); @@ -170,13 +149,27 @@ namespace AZ uint32_t attachmentIndex = 0; for (auto& verticalBlurChildPass : m_verticalBlurChildPasses) { + // mip0 source input RPI::PassAttachmentBinding& inputAttachmentBinding = verticalBlurChildPass->GetInputOutputBinding(0); inputAttachmentBinding.SetAttachment(reflectionImageAttachment); inputAttachmentBinding.m_connectedBinding = &GetInputOutputBinding(0); + // mipN transient output RPI::PassAttachmentBinding& outputAttachmentBinding = verticalBlurChildPass->GetInputOutputBinding(1); outputAttachmentBinding.SetAttachment(transientPassAttachments[attachmentIndex]); + // setup downsampled depth output + // Note: this is a vertical pass output only, and each vertical child pass writes a specific mip level + uint32_t mipLevel = attachmentIndex + 1; + + // downsampled depth output + RPI::PassAttachmentBinding& downsampledDepthAttachmentBinding = verticalBlurChildPass->GetInputOutputBinding(2); + RHI::ImageViewDescriptor downsampledDepthOutputViewDesc; + downsampledDepthOutputViewDesc.m_mipSliceMin = static_cast(mipLevel); + downsampledDepthOutputViewDesc.m_mipSliceMax = static_cast(mipLevel); + downsampledDepthAttachmentBinding.m_unifiedScopeDesc.SetAsImage(downsampledDepthOutputViewDesc); + downsampledDepthAttachmentBinding.SetAttachment(downsampledDepthImageAttachment); + attachmentIndex++; } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h index b7ea98ae25..9548665c8a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h @@ -29,12 +29,8 @@ namespace AZ //! Creates a new pass without a PassTemplate static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); - //! Returns the frame buffer image attachment used by the ReflectionFrameBufferCopy pass - //! to store the previous frame image - Data::Instance& GetFrameBufferImageAttachment() { return m_frameBufferImageAttachment; } - - //! Returns the number of mip levels in the blur - uint32_t GetNumBlurMips() const { return m_numBlurMips; } + //! The total number of mip levels in the blur (including mip0) + static const uint32_t NumMipLevels = 5; private: explicit ReflectionScreenSpaceBlurPass(const RPI::PassDescriptor& descriptor); @@ -47,9 +43,6 @@ namespace AZ AZStd::vector> m_verticalBlurChildPasses; AZStd::vector> m_horizontalBlurChildPasses; - - Data::Instance m_frameBufferImageAttachment; - uint32_t m_numBlurMips = 0; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp index 1362191691..d27d4d90c9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp @@ -26,6 +26,19 @@ namespace AZ { } + bool ReflectionScreenSpaceCompositePass::IsEnabled() const + { + // delay for a few frames to ensure that the previous frame texture is populated + static const uint32_t FrameDelay = 10; + if (m_frameDelayCount < FrameDelay) + { + m_frameDelayCount++; + return false; + } + + return true; + } + void ReflectionScreenSpaceCompositePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context) { if (!m_shaderResourceGroup) @@ -33,22 +46,8 @@ namespace AZ return; } - RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); - - RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); - - // compute the max mip level based on the available mips in the previous frame image, and capping it - // to stay within a range that has reasonable data - const uint32_t MaxNumRoughnessMips = 8; - uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; - - auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); - m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); - - return RPI::PassFilterExecutionFlow::StopVisitingPasses; - }); + auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); + m_shaderResourceGroup->SetConstant(constantIndex, ReflectionScreenSpaceBlurPass::NumMipLevels - 1); FullscreenTrianglePass::CompileResources(context); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h index c70a21cd1e..03b2834633 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h @@ -34,6 +34,9 @@ namespace AZ // Pass Overrides... void CompileResources(const RHI::FrameGraphCompileContext& context) override; + bool IsEnabled() const override; + + mutable uint32_t m_frameDelayCount = 0; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.cpp new file mode 100644 index 0000000000..7f6bce8a00 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.cpp @@ -0,0 +1,58 @@ +/* + * 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 "ReflectionScreenSpaceTracePass.h" +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + RPI::Ptr ReflectionScreenSpaceTracePass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew ReflectionScreenSpaceTracePass(descriptor); + return AZStd::move(pass); + } + + ReflectionScreenSpaceTracePass::ReflectionScreenSpaceTracePass(const RPI::PassDescriptor& descriptor) + : RPI::FullscreenTrianglePass(descriptor) + { + } + + void ReflectionScreenSpaceTracePass::BuildInternal() + { + Data::Instance pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + + // retrieve the previous frame image attachment from the pass + AZ_Assert(m_ownedAttachments.size() == 3, "ReflectionScreenSpaceTracePass must have the following attachment images defined: ReflectionImage, DownSampledDepthImage, and PreviousFrameImage"); + RPI::Ptr previousFrameImageAttachment = m_ownedAttachments[2]; + + // update the image attachment descriptor to sync up size and format + previousFrameImageAttachment->Update(); + + // change the lifetime since we want it to live between frames + previousFrameImageAttachment->m_lifetime = RHI::AttachmentLifetimeType::Imported; + + // set the bind flags + RHI::ImageDescriptor& imageDesc = previousFrameImageAttachment->m_descriptor.m_image; + imageDesc.m_bindFlags |= RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite; + + // create the image attachment + RHI::ClearValue clearValue = RHI::ClearValue::CreateVector4Float(0, 0, 0, 0); + m_previousFrameImageAttachment = RPI::AttachmentImage::Create(*pool.get(), imageDesc, Name(previousFrameImageAttachment->m_path.GetCStr()), &clearValue, nullptr); + + previousFrameImageAttachment->m_path = m_previousFrameImageAttachment->GetAttachmentId(); + previousFrameImageAttachment->m_importedResource = m_previousFrameImageAttachment; + } + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.h new file mode 100644 index 0000000000..b03418bbac --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.h @@ -0,0 +1,43 @@ +/* + * 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 + { + //! This pass traces screenspace reflections from the previous frame image. + class ReflectionScreenSpaceTracePass + : public RPI::FullscreenTrianglePass + { + AZ_RPI_PASS(DiffuseProbeGridDownsamplePass); + + public: + AZ_RTTI(Render::ReflectionScreenSpaceTracePass, "{70FD45E9-8363-4AA1-A514-3C24AC975E53}", FullscreenTrianglePass); + AZ_CLASS_ALLOCATOR(Render::ReflectionScreenSpaceTracePass, SystemAllocator, 0); + + //! Creates a new pass without a PassTemplate + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + Data::Instance& GetPreviousFrameImageAttachment() { return m_previousFrameImageAttachment; } + + private: + explicit ReflectionScreenSpaceTracePass(const RPI::PassDescriptor& descriptor); + + // Pass behavior overrides... + virtual void BuildInternal() override; + + Data::Instance m_previousFrameImageAttachment; + }; + } // namespace RPI +} // namespace AZ 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 184460b210..3ed2ec8755 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -275,6 +275,8 @@ set(FILES Source/RayTracing/RayTracingPassData.h Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp Source/ReflectionProbe/ReflectionProbe.cpp + Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.cpp + Source/ReflectionScreenSpace/ReflectionScreenSpaceTracePass.h Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp