From 5f7a30f8dafac41bc02af4d315661be183e86132 Mon Sep 17 00:00:00 2001 From: dmcdiarmid-ly <63674186+dmcdiarmid-ly@users.noreply.github.com> Date: Sat, 29 Jan 2022 19:37:46 -0700 Subject: [PATCH] Added DiffuseProbeGrid Visualization passes, shaders, and editor controls. Changed the DiffuseGI passes to override IsEnabled() instead of exiting early from FrameBeginInternal. Signed-off-by: dmcdiarmid-ly <63674186+dmcdiarmid-ly@users.noreply.github.com> --- .../Assets/Models/DiffuseProbeSphere.fbx | 3 + .../Passes/DiffuseGlobalIllumination.pass | 37 ++- ...ridVisualizationAccelerationStructure.pass | 13 + ...iffuseProbeGridVisualizationComposite.pass | 40 +++ .../DiffuseProbeGridVisualizationPrepare.pass | 13 + ...ffuseProbeGridVisualizationRayTracing.pass | 54 ++++ .../Common/Assets/Passes/MainPipeline.pass | 31 +- .../Common/Assets/Passes/OpaqueParent.pass | 11 + .../Assets/Passes/PassTemplates.azasset | 16 + ...iffuseProbeGridVisualizationComposite.azsl | 67 ++++ ...fuseProbeGridVisualizationComposite.shader | 42 +++ ...GridVisualizationPrepare.precompiledshader | 34 ++ ...dVisualizationRayTracing.precompiledshader | 34 ++ ...tionRayTracingClosestHit.precompiledshader | 35 ++ ...ualizationRayTracingMiss.precompiledshader | 35 ++ .../diffuseprobegridrelocation.azshader | Bin 79904 -> 79904 bytes ...probegridrelocation_dx12_0.azshadervariant | Bin 7994 -> 7974 bytes ...probegridrelocation_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridrelocation_vulkan_0.azshadervariant | Bin 11362 -> 11306 bytes ...fuseprobegridvisualizationprepare.azshader | Bin 0 -> 78689 bytes ...isualizationprepare_dx12_0.azshadervariant | Bin 0 -> 7346 bytes ...isualizationprepare_null_0.azshadervariant | Bin 0 -> 486 bytes ...ualizationprepare_vulkan_0.azshadervariant | Bin 0 -> 6554 bytes ...eprobegridvisualizationraytracing.azshader | Bin 0 -> 205596 bytes ...alizationraytracing_dx12_0.azshadervariant | Bin 0 -> 18458 bytes ...alizationraytracing_null_0.azshadervariant | Bin 0 -> 486 bytes ...izationraytracing_vulkan_0.azshadervariant | Bin 0 -> 12596 bytes ...visualizationraytracingclosesthit.azshader | Bin 0 -> 205606 bytes ...aytracingclosesthit_dx12_0.azshadervariant | Bin 0 -> 11774 bytes ...aytracingclosesthit_null_0.azshadervariant | Bin 0 -> 486 bytes ...tracingclosesthit_vulkan_0.azshadervariant | Bin 0 -> 1372 bytes ...begridvisualizationraytracingmiss.azshader | Bin 0 -> 205600 bytes ...ationraytracingmiss_dx12_0.azshadervariant | Bin 0 -> 10726 bytes ...ationraytracingmiss_null_0.azshadervariant | Bin 0 -> 486 bytes ...ionraytracingmiss_vulkan_0.azshadervariant | Bin 0 -> 1108 bytes ...iffuseProbeGridFeatureProcessorInterface.h | 3 + .../Code/Source/CommonSystemComponent.cpp | 8 + .../DiffuseProbeGrid.cpp | 97 +++++- .../DiffuseProbeGrid.h | 44 ++- .../DiffuseProbeGridBlendDistancePass.cpp | 31 +- .../DiffuseProbeGridBlendDistancePass.h | 3 +- .../DiffuseProbeGridBlendIrradiancePass.cpp | 31 +- .../DiffuseProbeGridBlendIrradiancePass.h | 3 +- .../DiffuseProbeGridBorderUpdatePass.cpp | 31 +- .../DiffuseProbeGridBorderUpdatePass.h | 3 +- .../DiffuseProbeGridClassificationPass.cpp | 39 +-- .../DiffuseProbeGridClassificationPass.h | 3 +- .../DiffuseProbeGridFeatureProcessor.cpp | 150 ++++++++- .../DiffuseProbeGridFeatureProcessor.h | 32 +- .../DiffuseProbeGridRayTracingPass.cpp | 77 ++++- .../DiffuseProbeGridRayTracingPass.h | 1 + .../DiffuseProbeGridRelocationPass.cpp | 105 +++--- .../DiffuseProbeGridRelocationPass.h | 3 +- .../DiffuseProbeGridRenderPass.cpp | 29 +- .../DiffuseProbeGridRenderPass.h | 3 +- ...VisualizationAccelerationStructurePass.cpp | 192 +++++++++++ ...idVisualizationAccelerationStructurePass.h | 53 ++++ ...useProbeGridVisualizationCompositePass.cpp | 62 ++++ ...ffuseProbeGridVisualizationCompositePass.h | 39 +++ ...ffuseProbeGridVisualizationPreparePass.cpp | 270 ++++++++++++++++ ...DiffuseProbeGridVisualizationPreparePass.h | 52 +++ ...seProbeGridVisualizationRayTracingPass.cpp | 300 ++++++++++++++++++ ...fuseProbeGridVisualizationRayTracingPass.h | 67 ++++ .../RayTracing/RayTracingFeatureProcessor.h | 2 + .../Code/atom_feature_common_files.cmake | 8 + .../RHI/RayTracingAccelerationStructure.h | 1 + .../Include/Atom/RHI/RayTracingBufferPools.h | 2 +- .../Code/Source/RHI/RayTracingBufferPools.cpp | 2 +- .../DX12/Code/Source/RHI/RayTracingTlas.cpp | 2 +- .../RHI/DX12/Code/Source/RHI/RayTracingTlas.h | 3 +- .../RHI/Null/Code/Source/RHI/RayTracingTlas.h | 3 +- .../Vulkan/Code/Source/RHI/CommandList.cpp | 20 ++ .../Code/Source/RHI/RayTracingBufferPools.h | 4 +- .../Vulkan/Code/Source/RHI/RayTracingTlas.cpp | 2 +- .../Vulkan/Code/Source/RHI/RayTracingTlas.h | 3 +- .../DiffuseProbeGridComponentConstants.h | 1 + .../DiffuseProbeGridComponentController.cpp | 41 ++- .../DiffuseProbeGridComponentController.h | 7 + .../EditorDiffuseProbeGridComponent.cpp | 37 ++- .../EditorDiffuseProbeGridComponent.h | 6 + 80 files changed, 2185 insertions(+), 155 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Models/DiffuseProbeSphere.fbx create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationAccelerationStructure.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationComposite.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationPrepare.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationRayTracing.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPrepare.precompiledshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracing.precompiledshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingClosestHit.precompiledshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingMiss.precompiledshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare.azshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing.azshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit.azshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss.azshader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h diff --git a/Gems/Atom/Feature/Common/Assets/Models/DiffuseProbeSphere.fbx b/Gems/Atom/Feature/Common/Assets/Models/DiffuseProbeSphere.fbx new file mode 100644 index 0000000000..0fdf350c1f --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Models/DiffuseProbeSphere.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18a2bfdeeabfbbf6397daab7c89f9f7321e4863b54a4669fa87e457cb113322c +size 78256 diff --git a/Gems/Atom/Feature/Common/Assets/Passes/DiffuseGlobalIllumination.pass b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseGlobalIllumination.pass index 45278cd511..a70f4446a4 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/DiffuseGlobalIllumination.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseGlobalIllumination.pass @@ -42,6 +42,22 @@ }, "LoadAction": "Clear" } + }, + { + "Name": "VisualizationOutput", + "SlotType": "Output", + "ScopeAttachmentUsage": "RenderTarget", + "LoadStoreAction": { + "ClearValue": { + "Value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "LoadAction": "Clear" + } } ], "ImageAttachments": [ @@ -73,7 +89,14 @@ "AttachmentRef": { "Pass": "This", "Attachment": "IrradianceImage" - } + } + }, + { + "LocalSlot": "VisualizationOutput", + "AttachmentRef": { + "Pass": "DiffuseProbeGridVisualizationRayTracingPass", + "Attachment": "Output" + } } ], "PassRequests": [ @@ -193,6 +216,18 @@ } } ] + }, + { + "Name": "DiffuseProbeGridVisualizationPreparePass", + "TemplateName": "DiffuseProbeGridVisualizationPreparePassTemplate" + }, + { + "Name": "DiffuseProbeGridVisualizationAccelerationStructurePass", + "TemplateName": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate" + }, + { + "Name": "DiffuseProbeGridVisualizationRayTracingPass", + "TemplateName": "DiffuseProbeGridVisualizationRayTracingPassTemplate" } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationAccelerationStructure.pass b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationAccelerationStructure.pass new file mode 100644 index 0000000000..78d4c82dcf --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationAccelerationStructure.pass @@ -0,0 +1,13 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": + { + "PassTemplate": + { + "Name": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate", + "PassClass": "DiffuseProbeGridVisualizationAccelerationStructurePass" + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationComposite.pass b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationComposite.pass new file mode 100644 index 0000000000..9f19fde4af --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationComposite.pass @@ -0,0 +1,40 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "DiffuseProbeGridVisualizationCompositePassTemplate", + "PassClass": "DiffuseProbeGridVisualizationCompositePass", + "Slots": [ + { + "Name": "VisualizationInput", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "Depth", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader", + "ImageViewDesc": { + "AspectFlags": [ + "Depth" + ] + } + }, + { + "Name": "ColorInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget" + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.shader" + }, + "PipelineViewTag": "MainCamera" + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationPrepare.pass b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationPrepare.pass new file mode 100644 index 0000000000..aa95128a2e --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationPrepare.pass @@ -0,0 +1,13 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": + { + "PassTemplate": + { + "Name": "DiffuseProbeGridVisualizationPreparePassTemplate", + "PassClass": "DiffuseProbeGridVisualizationPreparePass" + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationRayTracing.pass b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationRayTracing.pass new file mode 100644 index 0000000000..bdfba0d478 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/DiffuseProbeGridVisualizationRayTracing.pass @@ -0,0 +1,54 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "DiffuseProbeGridVisualizationRayTracingPassTemplate", + "PassClass": "DiffuseProbeGridVisualizationRayTracingPass", + "Slots": [ + { + "Name": "Output", + "SlotType": "Output", + "ShaderInputName": "m_output", + "ScopeAttachmentUsage": "Shader", + "LoadStoreAction": { + "ClearValue": { + "Value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "LoadAction": "Clear" + } + } + ], + "ImageAttachments": [ + { + "Name": "VisualizationImage", + "SizeSource": { + "Source": { + "Pass": "Parent", + "Attachment": "NormalInput" + } + }, + "ImageDescriptor": { + "Format": "R32G32B32A32_FLOAT", + "SharedQueueMask": "Graphics" + } + } + ], + "Connections": [ + { + "LocalSlot": "Output", + "AttachmentRef": { + "Pass": "This", + "Attachment": "VisualizationImage" + } + } + ] + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass index 314d999e4d..f0c1c212c0 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass @@ -357,6 +357,33 @@ } ] }, + { + "Name": "DiffuseProbeGridVisualizationCompositePass", + "TemplateName": "DiffuseProbeGridVisualizationCompositePassTemplate", + "Connections": [ + { + "LocalSlot": "VisualizationInput", + "AttachmentRef": { + "Pass": "OpaquePass", + "Attachment": "DiffuseProbeGridVisualization" + } + }, + { + "LocalSlot": "Depth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "ColorInputOutput", + "AttachmentRef": { + "Pass": "PostProcessPass", + "Attachment": "Output" + } + } + ] + }, { "Name": "AuxGeomPass", "TemplateName": "AuxGeomPassTemplate", @@ -365,8 +392,8 @@ { "LocalSlot": "ColorInputOutput", "AttachmentRef": { - "Pass": "PostProcessPass", - "Attachment": "Output" + "Pass": "DiffuseProbeGridVisualizationCompositePass", + "Attachment": "ColorInputOutput" } }, { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass index 752d565234..dcf5ef3550 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass @@ -46,6 +46,10 @@ "Name": "Output", "SlotType": "Output" }, + { + "Name": "DiffuseProbeGridVisualization", + "SlotType": "Output" + }, // SwapChain here is only used to reference the frame height and format { "Name": "SwapChainOutput", @@ -59,6 +63,13 @@ "Pass": "DiffuseSpecularMergePass", "Attachment": "Output" } + }, + { + "LocalSlot": "DiffuseProbeGridVisualization", + "AttachmentRef": { + "Pass": "DiffuseGlobalIlluminationPass", + "Attachment": "VisualizationOutput" + } } ], "PassRequests": [ diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset index 96cf769690..16e6a7ee72 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset +++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset @@ -476,6 +476,22 @@ "Name": "DiffuseCompositePassTemplate", "Path": "Passes/DiffuseComposite.pass" }, + { + "Name": "DiffuseProbeGridVisualizationPreparePassTemplate", + "Path": "Passes/DiffuseProbeGridVisualizationPrepare.pass" + }, + { + "Name": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate", + "Path": "Passes/DiffuseProbeGridVisualizationAccelerationStructure.pass" + }, + { + "Name": "DiffuseProbeGridVisualizationRayTracingPassTemplate", + "Path": "Passes/DiffuseProbeGridVisualizationRayTracing.pass" + }, + { + "Name": "DiffuseProbeGridVisualizationCompositePassTemplate", + "Path": "Passes/DiffuseProbeGridVisualizationComposite.pass" + }, { "Name": "DiffuseGlobalFullscreenPassTemplate", "Path": "Passes/DiffuseGlobalFullscreen.pass" diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.azsl new file mode 100644 index 0000000000..2151541c06 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.azsl @@ -0,0 +1,67 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_visualization; + Texture2D m_depth; + + Sampler LinearSampler + { + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; +} + +#include + +// Vertex Shader +VSOutput MainVS(VSInput input) +{ + VSOutput OUT; + + float4 posTex = GetVertexPositionAndTexCoords(input.m_vertexID); + OUT.m_position = float4(posTex.x, posTex.y, 0.0, 1.0); + + return OUT; +} + +// Pixel Shader +PSOutput MainPS(VSOutput IN) +{ + uint2 screenCoords = IN.m_position.xy; + float depth = PassSrg::m_depth.Load(uint3(screenCoords, 0)).r; + float4 visualization = PassSrg::m_visualization.Load(uint3(screenCoords, 0)); + + if (!any(visualization)) + { + discard; + } + + if (depth > visualization.a) + { + discard; + } + + PSOutput OUT; + OUT.m_color = float4(visualization.rgb, 1.0f); + return OUT; +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.shader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.shader new file mode 100644 index 0000000000..8d758b9b6d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationComposite.shader @@ -0,0 +1,42 @@ +{ + "Source" : "DiffuseProbeGridVisualizationComposite.azsl", + + "RasterState" : + { + "CullMode" : "Back" + }, + + "DepthStencilState" : + { + "Depth" : + { + "Enable" : false + } + }, + + "DrawList" : "forward", + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + }, + + "Supervariants": + [ + { + "Name": "NoMSAA", + "PlusArguments": "--no-ms", + "MinusArguments": "" + } + ] +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPrepare.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPrepare.precompiledshader new file mode 100644 index 0000000000..d77b7fcb0e --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPrepare.precompiledshader @@ -0,0 +1,34 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PrecompiledShaderAssetSourceData", + "ClassData": + { + "ShaderAssetFileName": "diffuseprobegridvisualizationprepare.azshader", + "PlatformIdentifiers": [ + "pc", + "linux" + ], + "Supervariants": + [ + { + "Name": "", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationprepare_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationprepare_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationprepare_null_0.azshadervariant" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracing.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracing.precompiledshader new file mode 100644 index 0000000000..ff38bfd843 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracing.precompiledshader @@ -0,0 +1,34 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PrecompiledShaderAssetSourceData", + "ClassData": + { + "ShaderAssetFileName": "diffuseprobegridvisualizationraytracing.azshader", + "PlatformIdentifiers": [ + "pc", + "linux" + ], + "Supervariants": + [ + { + "Name": "", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracing_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracing_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracing_null_0.azshadervariant" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingClosestHit.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingClosestHit.precompiledshader new file mode 100644 index 0000000000..1f0d0f7e11 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingClosestHit.precompiledshader @@ -0,0 +1,35 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PrecompiledShaderAssetSourceData", + "ClassData": + { + "ShaderAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit.azshader", + "PlatformIdentifiers": + [ + "pc", + "linux" + ], + "Supervariants": + [ + { + "Name": "", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingclosesthit_null_0.azshadervariant" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingMiss.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingMiss.precompiledshader new file mode 100644 index 0000000000..905006d92a --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingMiss.precompiledshader @@ -0,0 +1,35 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PrecompiledShaderAssetSourceData", + "ClassData": + { + "ShaderAssetFileName": "diffuseprobegridvisualizationraytracingmiss.azshader", + "PlatformIdentifiers": + [ + "pc", + "linux" + ], + "Supervariants": + [ + { + "Name": "", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingmiss_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingmiss_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridvisualizationraytracingmiss_null_0.azshadervariant" + } + ] + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader index 4186489303247e4a509e74262c354526a7d79b23..69507ebd96867eda93f0b06b368b928d6e0735e3 100644 GIT binary patch delta 170 zcmZ4Rfn~u5mJM<&Ec45!hHqA431Vb*E04%7-R!8hU465GE)RnLRf}Vdws!ZU=%3Fw z+eHQlLljPS)Kl7AJ9Vo1WCLC4$*EI5q6lBs;`lVLTrlgOz=h2(BW(mXPq~;0H4&`w n#_#FslXw66hNS7n@2grIEZcjhsUKLzzWG(8wczv*=8OgapVCJE delta 170 zcmZ4Rfn~u5mJM<&ELojz?rv6M31VaoFH4GY+3cvdU465GE)RnLRg2?5=!#>aZ986W zwu=l9hA5ousHe2KcIs61$p*U8lT)XBL=nEM#i2Uce8c5=#|k&UjI^oO$*a`G~yY0STNSJGrAPhfPDk@@2i;pBY#+2#)~W!YC3>-}doAfscainSG3CUZFns@du?3#Tf{YV0%g8+gb z9Bhgb5RGl|CsYj*5%k8Q1W5t)by6d=*C9gMNab4F0FQE z9bC0;JYozi2Neou)=0J_2sAzHSPEQnSsG2!qbNds7wH;@(57e$@#!NMIHu* zcbj$jm$NZCZ@wz}g1x@uAY+4qM9%9?+Lb|ii#Zt+8vPHXTO6`ydN@0kgV~Tn$M=$p z-88jKC3#_{A2VjH=&bSKcwn5Az@Wgv#=Eb@J3%!`?4zWi1%m)fb838+s(?=DBNe-4 zT7^RL(Nirt&vzVT0-CR)uvxEJfXB%IqVeqhIo=6wit^kn^*<$&P8?@)vRfweY2$$j z{h~EY^2$G0?94uJ)}(PBNm#%-QQV8)ZpWt{g9dE_i44alt(Thp*V!oZJmKPDixQ|@ z_~pT3?eiSWyO@}zy;|+erf}8fXo&vmk(P=V#JAma{!`z6dpS_eVI zArR5byVglwO*#swX$x1an{ZaDgkb^58>iBqw8j)X4fAP}Xik*KGxNZbupzFkM^kX5*%f-{Nu;1II7He6LDK9b?r|*(?=i(Oi*&d9)&7mBM zTg>N$fR6`r_*{Nr8wTvt{4+=Wx)_+}gI<*lB^D#`7AJkFnd0s}&l*tfWzy delta 660 zcmX|f6dIkBMw+Q&jS%{I^6+Z_3OwGv6+5 zU%at_FtDVJ0M?-m_-1UvYON8!0Ta(sqkNP2)A0vbA8`mQmaFEgZNF|lu} ziQ}A`wGE@sj|VndUHpMuv^>}z?jZ46Kc=!A7Ba4re3y6uuMXvVO2Kj370ooe2iqU9WQ83gI9umD% zb%&`!9Rcf(;*ZF6>j4;mx#rCh-dglpi7+s zBvkFv-RcY`O@nm@eLRVe$oX6Rf4oet+IiRly*~b&Ty=BAdZsNM^9oFwdTQZGi)M%Y RbhWe+Ef3$M77MRWXn!~TSd#z% diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare.azshader new file mode 100644 index 0000000000000000000000000000000000000000..3d9904c607985ec54782fd08e575f79ecb494b62 GIT binary patch literal 78689 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..84b6226022cf56a8f1fde48be591ed8d5a4fdb36 GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha S`cngok&Jco%bzO%^#K4Nn#NfG literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationprepare_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..9ad3c0deb1fcfbb8e36eef4d5d19d6cf71f47757 GIT binary patch literal 6554 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing.azshader new file mode 100644 index 0000000000000000000000000000000000000000..0b8181e53f31fae3874a0a65b2c19f3dea59ce84 GIT binary patch literal 205596 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%0A{0#B9tkdjRf@wzpb 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 b`s_VZqs^Jn%30Uyt$8pkai=sQ{@4ElE~XAa literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..99c5a3791b8e291d4b3874e0e239db55cbd8eed6 GIT binary patch literal 18458 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..6c9bcb846b2a2ece4f1a74435d0a02edc8b7ae98 GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3^Wow0kVv7S8VC@od2$hTP*giP40{T0SVgcHyAE@iTKzr zf3hhh(EQi2N`LW)nb#sKjor`spV%pw{Q1#_nN}Ro&|qYU(KNsL8A}kefK^oHoBq_m OqM5O7$t0E&KqUZQHO4;x literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracing_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..8d0eb8a2a8c303f553819c108b2b9eed7e8a9033 GIT binary patch literal 12596 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
iZDucNBBNL_R9uFKzSZmB;)7=O- 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�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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..4f3437ccda3c4a254763c049f669f8845c137d8a GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3^Wow0kVv7S8VC@od2$hTP*giP40{T0SVgcHyAE@iTKzr zf3hhh(EQi2N`LW)nb#sKjor`spV%pw{Q1#_nN}Ro&|qYU(KNsL8A}kefK^oHoBq_m OqM5O7$;7XsKqUZS7{+`6 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingclosesthit_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..918e729d99fd2df91ef0140f5e25563e4d1b7f59 GIT binary patch literal 1372 zcmcIjYe|3E&ikC_ob6?dF_}ZM zxz(eH_oM_n`y(%p6m!k)7q0Dbl50r^mMP-bET|Z$n-!UpUBle1#|oE7dUAE?4R-AY z$GsC@?Gepmvsg&NB?)IgDIlZ?#&!78|wr;;BB{^?J!?XHc*GW!&rqSA%RvMMT{!`SA zX3~rP>dLCV(2|4MOy8uoQ1b>Rtv8) zns!m8OsK@EDJ+OR3}pOMr%6G1qgNEFW^edmVCX|Tx7Hw&8FWu^eW(trXnkE(iu`sdP6BO z$psDjM1G;)pBmLv1C2psPiO{U=mmyeU}y(^;P7~wO%%KkS z^9g<;aexy$0xvK)p#i+W;Kbac7@U}UEXLfx@svRi_;}FgJF(OCVylP+I;WF?9~e5R zt-!yZzA>l57egMpXON-aC{~h>ekUl3d>9#G;I;c=;pF2Sa$4b^z*q$Ns6h@rR+9?M zjrcGrUJlinK-}Uo({`_T zRVtOL#ANl@z&R__XO%(LZ-z zGdF8ONa@q}#sM)Ol_oxa+tCr5&pg**g?8fjjhE(TKFnB`7ZRM%)~CfchW|XjyqkX8 z@4J5pI=y&I#;VCjy1sg3R*mXc5>L)=dE?l?Ddl$gs^K$5{?WWM^1~CAKM%Q+e!ti3 z4HL$WYE-}_;l?d=L@=l)Xv-#YEF@#poF zPXYWqfBT+I+R>0#_BO2SC;Vk(c_~3s4{w1kDLEx z|BS%M<300sRZ9Bxo80;B%9d*X{ibW(Qk$wY?_S;gPUzKpi5nKgP1xr%Ao#8BnsCkG zoIA(rolT$c%K7+L_dK`$jio6I$2(U0P-|Pv=N$(QS#Uk!tL{4=Jse2ebOqeaw5O`M znMF1SorIP~BF&Z#>xZJ?+=80-GUxf+OCIl^8X5oT)=Q_Cn@*i-Ax!z%x2C4AGb<9{l+%l}eMoG~WN>$-w>FOT;yws7`8kA?MV6$EPQh zZTRz+)X3;rch)3?q#xNCM_W#n=J01XPaZj2Tits{{Hza4AN{V{_J`kSh=6%q>d5K( zGZJddxK%bVX3zCV;j3k9&-%3Y!f|04>$TD9U$%TQB9SH|`Wp1ZV{ECajBW3=EL&pT z`cB%&_>?7k&)$#P8k66qb2~qfif`zX((Hbgz+}B&NSehIqcd5Jdh&;Qn_tXeU9#TR z-7v^+82rF)OKlGSGpICo_I*G7^xnu&AzZ}z0;`zt&%BGKf-FUr`z;l7IT`-VssJqbskC?ffIw6Kv`2_vOWm}D-*Ym ziiI1{p>YQ@aRVC=xGS3y?FO>yy(|WET6aV0;51K7fzA4Is3|<}oI;G%;@KJaGZ&#e zY6cZdiB^xZpAEhO3Oumi>X0P*WFj*x!#%ZutW5S-M9rXjp&3LNjA?pXFP%+i^3*ig z=ioWiG-`kdGT1<(gG#6~3P;(a>*2$eNxrCwkjubsvUe6I;~}BSUWrPm36v)*VISgA zY075)^C;}knG%z9R(rZp?@{<{X;c{nA6P#$U6<@p>}=LoL172hTP??zHgjT4ll5;KE7>d>ce z_{+N*Rqq-~bN+ z_9@sqPYk$)hX9w53vi%^0GE^ta7zyXE`WyI{MqgO^o z%$_=ZWo5+dsRQ_ojF>%j2A?I@VUyFLs!P3nZrIlLxw}5L%B@EC|2IRWx!a=uh0M^$ zFU_nPb9aAW(D5G*tba?T3Ay=_U-w%R{~J9wuGZ`yrc_G#X~P1QX7u%AW3y)5+?d%c zrqc4utIp1Oa41u_P}Q63=0B=gKeFzkjzccD*1Zy@edA2_If{7&F2TNEEuBsoaT;E@ zKLz#^#;2T@5cj9RNW=J)^LpU^R0-y%oPwMCQ=m#PP&q{^_oqrRKjoBk+@C7V{FGAw zaet}|^HWZ_!2PMR%uhLwEBB|KVSWlu5pK6X%lwqn*2Rsg9P?97qZ9Y1$}>OZGy!pc zssi&{T8*v{>XjF61)^78wB_Dy{|DuTN^>x-(kRz60B^+MrSDTN!HO#Ffwl{- zQ$|3P^f2e2r;NardjIvvvGkF}JM25DBbwC%%1v97@JiS2wPG!sr-nD}r`ml*@Ce?H zUQ}-Rf%q0HH2u#cZXP~F5P3ew?eTNJYaC;kyy&f$9)6`-Nc9L({5cM<;OcJ&UyrkE z-&xslb-j0W?drPo3L@yyjLSpDNtbHAI&#DU%a}<^uqoHeu=$jAKkn& z<>#~8gj;0K*)JQ+Zx;Rjs(^*#bIX78i-YC=Ze8cbkg z1tBonsbyXr7!o}{^Ov@X8M)1@tSd#7v@#G6L=qPlL>&QK zPx|bNh*tOC+czO=%7zZPAAB(4O#yS(j7%uMA*z1(o9(Bagx|e<>|DbY9YS)} zFO6@xV91o+`#$b{PWas_haao9TKgqV9I|=g+`Fc+@VhZVdm1;?-#B-2TU?VZdSAO{ z^Vd1T?^X?8RrRBDy|v4J7+T6&IT7TG=2=za4JWpiT(GK6-@Hw`KVLhpWMGi61=T4( z<+K>?-?P-F#aoX)H!$n6rpv8cxrv`>Cw%P}U1R3d9}kTlo!nda)e?CZM>jjRG+_R(5A~Iy-MhENCCW%J({blKKYWPb z1|x`y!2#41#sT`dh@*>nnBE4Vwk)<}Dh@|{7Ztxq2NXvGkEVi9p+C_S!y=GnO0QTg z*S%Z-$^BMRE5DUqa0S-OrXN-eD&=<+DBZ&?He+%xi{0P|KBu2~HG4aO*^%Mp#+~`b zrbM$|XNylvasDgTVA9)r{Q0vegE`&t|FVvt`g7*~VuuvqP{R8;-7Ic<2yeBg>C7a` zlEJvkibEoAG!m>DW=S`vF>%~v;sAeyEDH#GDa~LMGBf%alG6q=q1;v+3apZA9ISip z{H{18xMUrW{)}sNkLaP|h~QZ&#;Ljm1DYU9Zp*cKz_wu*!c9#&Yeb-!vLnH7cvx2|{GpUN=SU`y^9E0f|&c76g1FZQorqVr@nu=oq))bDBbPuPF;&A>2yT+2z zoUE5gZ_^2J<9Y}nXWs5U{!C1AsYNe4F1=!* znE2!plu~>VmZWsM5HIRP+J`9#f)&RnuBjy{))JFs)9WEu6m(rCrp}6EBGL)=Sz@A9 zmz=0eYXRXxbnVec!^8sj4OVL#NJ}gepfKsP_cxqIHhq;Q^z5o?qrbnhQ#&tl6~rz%qo$WpdB zjCh?UmYrR@U*D>;jl^iwo)4>@WiJD9j)EQCbAC4l4h(_?R zm>U~M8*&jav{@=Jj;QFta$Q9#i$Rg2YfU(+kTQaqsvFw~j;`ox;+m~g8arih;oAZS z;a|9^GhfI!s-mr*YvPp042~WNY(ktPse*|k2YE0UauPcYj+*E!<6@?C7t!u?9E2LU z2^X~h<4B1v6Rz1(^>Z9W$PB`)W-&%e9Bt7Z$TeHGK7=Ft0&dD8Sy$B>N47eSEUc~6 zfRCdny1}^k>(0)LBP_aFxd<0E1L8=D!4q7hq)$j3ImkrA92cf721garRxwm*&K4X& z(T&N)Rf+u+M~y^oATBVBxg7^Y436NMHp}~nBMOtp%${y;#F2!2ZVXA-#dMoAjw%UF z19R+^h1HHp9k4#V7^PPp$FtGN z1hPKD^8vZgVR9ALov4l*d(K1M9 zWY$cXD5;qesW;h$!YO_cdL79O^$W9@Oct|Wh~2J-!YafV47MP@f?QF@_q!O4=_Z3& zC_&{M0Y|#q0#%OBHrI``8yOW?gmbK3dHQfpwU>L2m=jjR?PTq`6)XuxmCXTv{THjS;8_`F)j>#{5a%0`T zKC`2SPC7gIxBPpP$HOu~j?RNOAFQK~9r;NZxTCwKaj8OkG73Pl*jm;g@?9_=K z)=>BwjC@t*SoTMiKD6yR)cx_;M%SJ>w8GdLeh!i0sT1mE&wZ;x^N9N0vbSnmOuy!z zZFl_5qp8*g^pPp=25+U0?0h~T{aVwGS)2BEKC`yM{Y@FW?*%!&HokVnrmiC)R)XzH zy;xt@5y#)mxjkz8JE?82#!QQRm^CDmJ%F98J1(E&^rExVP{{{|&5>ee05$?dIP-v}0 z7UQUiwjr+2Qc-5%$cRrrE;2=AH;xi9Pr%atvm#c7=bL4C7qbrPV-0gugk?HGfjvrx z8#rtQ4yC`j#b!t~Kp9uMOHaiPevr#$O!9=BPmty|OPcUFVdAO7bsBSebE0s$eFsg=}AFR zhFExAaeVb?_?%CgV$dZkjt)|0T)3ynutV&P-fmzs4Ps0c4kW8Bffc120UOQ9H|Ba8 z6^AC}n4_RlsDW4q7~9OMI4p}XRA=x6r2DQ5hLg!IovTv&503mnS z<#vEbK8w-VGbM%C=9$Q{n8@VPM5M^b?Ep5o2vXgSEmjsWk;$cxNM)XQEQ$fQRB>?9 z^AN2!T9SmPO1N1!$f##ayp@WhYbe=nVPJHz8&V8>2-hf%P^y##LJRsAR`X?djvK_|-D#R44R@F@e3|SyS$au&i%Z8&=3#Kb<5J{LcHNe*GGXzIjEW5)M zIl?vq;K(AQBi%f3aCDK8%|1Rljh=kOBqyGNfC2q@@}Q4gfNi zQTj}zJ;QJikTG%6vtGzZgQJWLIh1bx!Zu_aY0){uC1!Y)K^zEVR6X6}fg=fW9V6K3 zZUh`j;+;a=B{V+@j-cq@<62wknG)Yf;=>#V0T~y_@l3`<(kwofdha{3z9x% zTuiJu>c}`)>D5;B{f;A!jBGBV!4&a8;mG2%gj}pCG*1N%0y64Xy6c_V@t+1+9DQW| z4%4TFql%2tmu~e!kGui!{=`vdCp1zub@$Z4W`LuP%;<4X9n1na>iGNwP0Df=StiT>O5$6>697+dOVECJ2R_atCF{}UU+V=_{Q~F%| z<$sIrX`0}n{=E&9>64l-I$lh5YFZS&^|45^2zm3vrG|SVC z@!pP@k`BcXpY~S*UA-MKsp0XE0Op!?0p0>e{HeT6J?k({U(PN8eBD$*DR!wG zGiTszPQW(%p;h*`9Sr>ENT;gYk!a4yv7 z1lONy&rwhH+S7%xv%#q4czHf)SJ##v0t~hR1Yj^cO16ZzBWBiw zkkY5`jRR8zsG5w80sdOq`0T0E2j)@PFnj6%Ldbz^m_2m{iCgjSpY$oPmAgM0oCHS0 zNarQQ{V8upO#ZfX-j103yz+L$^mfE7rbV#Z9B!OI1U-`>5S=O*w?Kqy8H`VXKLm&B zpDiztS@_oOuI4NOKpdCCe&!AB)}W`q%?hUguw_YheF+N>^#Lt04}ODrw(qKViX$}K~gutV$4Xjn1$N> z*y)L(xm?tsZi4W*#gY-jx46iV5Vb;+5{iyvNs3XpTqH@EMT33FUt*#d!_7qsmaK5& z0PMuX2um(%E>1e!W)uUExM)Gq5WU@GFVrvsS)B8S!qDfjG87qbT@gAdc-H5IfIUviF-Z{k-n`Z%ojjQmMc2_B#g(_2VRG@TwJ7O02eYmQ7!TZ_U5tH6n8TOL5 zBc{8y(=KtXZu`HfA2QEA*n=6aV%%*)YFSzg<}~4P?-mT$m{{UbE-*sIpDx)loU8pL zP-Tc~x$wX__jbfAwwHP_{k0hPnzth+vrvwYw<9J?qxGqy_@RdcMQ=w;xI{1t5#$s* zc=l(7-Es+XaZSA)G3oskVELG54g$Fu7cHDdwicpHsT*%cOiJ4lWd3_G zH@3qP&08i2nfmVSh-tIyk%_;etBJS5gNrnV7;H)ZWZWtvYj-eT$T+H^t)FY+l*bH? z9x|ie+YuAFk&*fH;KLMK86ruEE)%Y;@?$53JNqFiE^&81|cYS?FyQg>eC6xCN zn5xLC}X7IJ|i(XRZUU@I4nQn$;6f)tzNN8x4%$+lR;Hph>Mn(HCc=_0y6KN2^*k!{bA zw+}xe_oqv?BQK;&b1O8Iuzi`9i`3%gXAV3ZpqL{iWk)77D0#!ae}On69@Zhky& zHnVIBAIY)eM^rRtMkb~ZR|`J`m+TgqFp%6KmA2{L<}E4ju0NI0C#ZZ$uW1Msieqg; zSI9`CWsuGoV@p+KYOd7&7FPUPd~jk^3|Zr{g%Cd`QqbwXTD0$BXUQ* z^7P@HYA^R3F(<6zYZqtVo=KfC2%bR(qrnWlZDMpLt5I)L8e5{o$#&|gO}gqQ zy=`o8@@8bBcHV_Hag?=yRq|amwh?`#>zMq~CpXsZ>oYrQ=%llQf6Ko&c|5EulwEl6 z=7V+gk=&uT^^_5yvtrG+8KM4XD$E}r8k;+)*{Ksftf6F^sI*^|IhOrVr4Mbp4t0M# zw$Zg`4y`b@hM$*FX;UZE&7S*Kh2|0UyJc_HwwQj+KbzEwg}-?;)!KkQGUeUit@M$d z&j+MmYuYhu)Bet9)>gQ`DP#A&Ajj9n*RI&qbtJ?}=v=86>+3q=_?tPmM{R#6we8iI zX^{`J28ZwcV8^$IU<7uz8?%B+bE$g5nU(sI{v~(CEtp@sTj!wTb*>33E~#^tKzG6m zZLV3RA|Y*?Q6%-RR48Ou*CH&?9I8-%dDg-!=i}@3U%9MR4|_`UX5)mZl;EmNL>zJC zu!xoAne~VuN1ib);5NJPBE!4`ON4+)v{VAqS%=$0AmJuKfONLCAr00%1Q7H#1VDH- zThi04=@8GxC^E}lW4BwEvBts%ZE`wPb*Z<{4cpp2ch|>Oxz*_Y|7NH(cU$zokQw^; zrI}S@?(Po^I{w3f^>4wAdGjT|?zblXH+pVdt=T_Jsg&~5h6O6k=>_1ZT3l@T@lgh{(Ji-WKG%7A@_qX=Hv=Xd)yQ-XU)ij@*AS+ zhrii=+DZ7`%g4?&T+tyUXZ_OnmJ5bV*}d=M-sgnht#bIWYOA$h;>01F7tXzF8VkQ0 z6SSvsL;a0&C%45l*`oKgYc_wKBm8dF@KsemI@epf?1!PHtd$eN?4x;B)p)~+ttA(% zs?#@b)9%mLjw=}$B=B0D@>5QW;r=~KZCbqb=yLWBn3-rm zqhg?utM4lD^EjU%&25%6;rYSDQ-_Jit?q|dE%yzoSgXd4CY1{pyTuF(Q!tZPa_yud zn1oeyHsfGn>deF>*M4%?lnS>k7kts|1J_G&NK!UIn;v*!voUFznB-bIX~Qg9>mb%L zzOFbvX*Vlr<4qR2WW~{eX-*Vc!haR&pT~kVSaDd=);um9xLDAPibIof%uypZ)ByS+ z3zk)JSZ;cNvOvL$kZ~o-bv8MAYO%nLP#m08aESI0vC|$4->9d6kJeq2g)dWae2pZc zL*!q$Imwc2FsDZ9OeQdkFf_#Rier=tUui2r7P`rbqvPxg%>p=8ae(0SbGaRgcG+bi z%VHvvOF5DvE7~NHg=`TMnQ}5uJQfian@Pt^ELAO49Gvt#NLvQ8ShrGfbi93SSqRrC zj!>$X6mFLY4GUS&a-T9Z=w`@*cHk*PgC>(KXrC(%P5MYKw4h8}?A3hPoev7}cz2qn zB5j6bCJbLDdk(pSp-ko{=Vj(Fv+-sxlGr$bYd&1z`BL#FeQV(WAXD6mEE|qeE!}aQL8%J7n z&TySOUS$vm0+}dH_juq)!dhb%o9;%yktE(J#QviBQE&uB{~p)cO3#$|MiNagI0(p8 zFR5utgi!EI!_h|;d63FAsbvBO09oll`jl}ovEryBQyZmMThaGBjyQ=sN9^|^8jQ&@ zOmEVg(_%BM$`^icv8K>G6}Xv;Rj#=Xo^;ncgR8r30%!fo%raK`d^j8P342) z@^Y^J5qbM+#Rl4AjnE5{!uZ&{rqwEy&-S^N65wd zTW8c#LXBh!Ru|&%xN|+kpdgvZlP#s;ChvUO3xS?8A;4weP-4zy!olQ30xiY5AQnz( z+SK%JNgSF?D1>+}R^9|*k4h7}_-6Yjh_gai-Pn?jB}@c_j(=$~4?aBHDeg$e&pIV8 zUKgN?h);@!#(bp0?Nc&WSb0r_azvSMsUC_y}P$;`d>d^Cq9_bwxdDVx@{N_X+=e z+@OOsH(72h)SPN{wM|*;j+b&uYfogCn;PA1sH!gP+s=o3d~%|3nU(V^^_;ivrNEiz zE9x6+>~*$(HgxH}@2~EO?Y=MRnQ@hNXy(F)JB{4mP#s;%cJ`7XEc3(H79BhvxwuK* z)e0YtSNA)!zt@l7blsn|GJoN%Yhe$x`R7L6u$6c(^v5<)q02TL9enrljXS~?)Q-QI z@C7|}W7pp0J?SIA-`cWkS@QO%XVZF)n(}LjWj5VfX7 zj_^Cbse-{iAnN^jOFlBcVC^8hTGUgIPHNorpl06sB_B7ao>O~g|EU+NjkE0vUNHIv zO~9f@54YaG)Uu&U)&If28&;M6*zxr7exxv~ygc#llYipbQE9bphrGfNV<&%Kd`tb# zw%)#FUg=UlbKb65#_CfZ<=tOV)1XdlQKfGwzmQ+{wQAP#Xv0g3wZAUSYeD%8NYGjr zrf;g0Tdq>hn4VL&d=>x9o~T*dK_0`%g*T>$Qql=Q&Ck31pLKWC&rIJqZpE*m)*U%H zrz)rH*~KCPLVv~8_VXy@A3MlXNAiNp9OYug*w)@$)>%3+Cwv_zgxn&vJAD7g~r|=8rzt(1HM;*~@3VW&Y^rh2gzSAmU zPENPpy|=yj<*$yLs_ECNN4lua4`*e6x4nGJ2_xJr;k5(1H|?wP*|MPg2r~%) z;`)baN5e*?Sj-9IMo zpp3xR_KtZmmi{%ehbdDB8?twr6utm2y{qZnwBEDn6+vD}OTC`h7YbZonqOb7^I@8* zV~ybh2l#HDZtk_Fy6L!JCz$fa_xn0E7??9*x%Cxw&dWy}_DBVOs=AjyxO`oo;mZ~W zPYQ_YkQMS`SV?=z%C`L*J@{=%`~G*w)$%=9`8)HZV4;qJaODdB>b?Jb)z;@jDrViR zz4r02#NFZu{Fmdd{Is>L>Fc{fYvyd2+v}sGuCHjuzE<}8>>j0?mtGoiX2RE(FT5Wy zx}CPx@Hk0Hk_JZ~_5|*vFOB!VcrtMR_7ZW;C#sX$UC23g-|^`QWgGsyB{ed7)}1v8 zA?ZhU#?ex9Rhq+}-8^~ZY;AS#9r3e1EPeF5YTF-vBe3^zsUxTB&q$~-<5th&U&u=K2Ziac6m+n?_V_o7Vo-+}XGoNOV%d@u*Pu=S zZ2JY>xmmcu+{3^PGh!E_VBijB;&yIpKHSuTVV;=+oAuy|N3fn&-qABN@MkUpL?j|+ z;8IEHX@iIOLIikPJx9;Xz{+GlIQ0=TVAekK%rw~N!1x{K5Ur;;ev?u z05_p)D|?SjK*e4Oi1|cJplES6&tPXWAHu2-*ug)Uq_f)7je4PFBV>d!itfmJpRq+L zM9?GP7cCI&8SHGr*fz7F{a_vM)~Taxd9yDA;1ui zAnctd2He6!fN@31+;BM1Lx7<&usj@Y=^?-n1BU<%0k)Du=O|PV1^1Ju&K*Rz$%ffe zN00b&$jg=Q=(*>!r%oS)0n3KjQwI=I>tw_1sWT{4r~ca)Hx$^)T_+LjCyY9Y&P#~< zQ=rr`KIOa~xIYC&DH)$~3U2OCfhxiHlvAW~e+sI+GCt*$bljgR&HR*80C9f`>h&^E zIpqTPr^+%vz^XPdSZF+@FG477VsKO+ehAs=)k| z(3HbltF-Q-C#hA6+ihNX(UyDTdP-g(tIbwqR+|M;^0%rsn?ZAF5fh$EKPpGQ%<69k zUyrkE-&xslb-j0W?drNoU~!08Np)K)J(>|3N021w2&asXpc`W=jxLE2M$o1DYj70B z+}h*z__^OTjxkJL^wvuczfvuvvX*Hb$5AC|LWp_NoH{syVzxHdG$qD295t~71s65Z zU5FzCW*`g~=_WZGNwL}l*UXCAzHy|)S|wbhB&KQ{HL;Qa7d00r9gY^L{Frs4ctCLU z#H?DbxfQjV<4BRbX)v)WQ6s!K(}V*kZ^3X;(sI?-c27L8AnlZwxVRuP5cfwC7wi+>KQi%X4xl9QWOmQpPe|yd$2JatkE4Ma|+#DPxb9c-cQG zW$X?kk{!g~KdX*@HB%x93hU+QgJrOoqjYID15~_a)JX-87o$)w+jr_bKYW$_;RYj! ziopTY6vhGixrn2Sc^EYQ(lgnTsW=?*T~z!c9Z(#NqXHUfGWaK&Vps&SOz9P?<+_&( zAi3X4YUQ`m3$DO=+4RGTL8bhT0;PMn#b!+IWw9H`GO{+en!TOmDxurhlt|jw#V4jX z{}pR6>FquK{8^O2obLF4nJ7PJ?k{#o0ZuZ(`#IeVHAD)wJ+$Yxr|E>q2)eLTUsfCv zd86r*bVi{a1Cup3nK;0{$Ou!wu?F^1n!%_iB|`fdlG6q=q1;v+3apadK-wS*VJkxX zjeG9=t~eyPWF3%Vtd=wmL=P251kX|{iRvjH3}}KZxh>b`5h~m1k}bncI%^2&Z53k} z$-HWPfGXqWmkSTqD(po^c5M6up(J-;VeS_872GSDC1Sm}U?EMX=kxd^_T*_fp z@+xPqO**PnbKWEyVG$Hkac2aQEqcd$WII74l7c^%Jj-cqqDPE(m1LlG!4wL^wQ%#y%?2fAIG)X^~~7cGT~2grN`lRQM~l{;0-q` z+b{JauL%vwbmA+MLM_};8QM0)+H^^z*Qe1kNM~f$OqnRDnG&ft+5Jf26u$_)j%0@V zg;`7{i`g&4Zr7*T3reWi{R(nL9pCR_G^U#jW}&&da|9gejyBnS4fb@M(J)dN6_GhU z+gvx&Ze&zo5gx_rm8TEqRC~GSh&f>uU%NQ__Dt%GLGc}AFdB&K%u(>grpnuN&@{G0 ziIeTrQ=4?vPkP(f;N;E7MD4r_ZQ>|3Q(%F8SB-5%AL%+Kzx2tCb^H3vjv6}Y?BL(> z?@b;L%LF+(58iyRjy{q*^tPTd0(4fa`8Ffe|4fDX<3nR}2Q@o&qK7pUz6K*-l{uD8 ztz)Q7olrM>?pqa_N7V0@y;a*{`ZfP-Qa~U6=FwDZ1Nz96cZ0XmM|M6RkWMf7JHB?s zrmiC)Rzl}Wy;xt@5eI@fw?}P%C$;U>m}!v@vj&In{b0wphhT)bx!u`DE>%xBvr=Eu zzvQmC1@min>l}2v&NX4hC6yr(=oTB|A7N&BLQas3m1)3K?`|rGD%4+|weZUM_xMZkNWfxD3%JcLxWfPsON4+4H?siK*_^~fAVKp) zfGpAwfR)BBFBd_!pRCg9PzEvm#=V{%3{fBWP}mByP*^<>#p$Xp!QN(b65xK6q6 zz$Nmx%Ed{bTcri*?@$_7Bl2$)it46_a0fQtSZZ=i1u5dg73?XI#W-rBZHSASD6?>6 z#HSw@nIf_qM~Rpx{&5kj!t>2Cyo*@}!H2{2g2K&of&zP#4mWVv3LHv*bBoQ8YG6jv zso22}a=DC2o{;ki(%k0kj>&K_s_HPg<5u@`T>N<#M>jjRG8`mW3E;AolKGbM%C=9vqd z#Y85TCL%=!Y6xk{SB;2eUWYmMo z!Pssq6-U=lvfaYKOEFDcwZ8oD^Mn3wyMp+Sph7PJFT85(rnW^bBPhB9HooR^uy%*Go#jEvWliZ|(7 z3kLuh4_Rc{aFl9+!OUTh^TM;aNY zE>&`hs$V$b$Y@D^^&STU8PY91(o&5D2LKt%D19cC$ktB{HgkYz;5pX1t!Lu|!3XY)Y-{V?a>6sGW zNTTTl2LTxu$ni|W(MM(kN#&Zd1^9_te2GfTNDjKXKXePQNOSEXlS}vBIxa zXBgqvn*-bDe5$KY0#|Y2*M!yu_5GhH(Ms^C3Hhfws<~vuWB5nK0Qd99+4qLL{U5TG zRhk!v8v;5kn6ji=%f77_cWGO@gRyN-L1!rWLU?l3I*mfVT|HE{^h(WN7w4Us)vr~_ zTUjqWH&@l=hvg}KF8=brMfWt#ZX}<*a`s~XDmD5X&0Jlr%_VbWYYmC&ZhK_!tdJM` zcAbBu(Y4=3X*HVV>Be}zP;YNX%zNX=>bMJZWptLT!?eFRLtrIA$J7`O2!!%>#4JrY zh7eAOX1%jZ03Yi?DR!wG1pW?2n<`JWadS2&;G2Ozn7f1BPKtuyd5zsgl5gSxiPa@Or_=pwW5y&W+NlqygM&WXiBxM$zodvL@#29WaQm|x&8wX&ii4m4u)Lfi&xOEc)kho|;(Gb1e zWG~b(0(r*8Xd^CquxNkwJixNi+YxhMNc8;7U)m;S zTzw%{OtWqCb03GLsY! zD2~QW*9QiRK;Kn*#fm95&jP0WR&rMJ2dsxfm&%`8G#U;qu^>)N867Gw;<-|4hcEqIjSAgxs6i4j+4X2T< zg(y?%#@i8-l6Qd2e=p|7c37ghk}TmEB2(X4Dlm?y=)vNuc>s!>t83TMco|0(Sw6*$ zZ3IVGbTx6!mhZN}K|t2-V7`!XR7G1q*TgB085})iM!mNqCNhH^nLl6D0*qTq(XGz4 zb-W!h9Ua1POvYCvV5rtOvdAh@R0BSaqUZ+W+D-24yg0(5tCfo|3DwXi>5PBnb`ygq zxJY?BV$QDJuW!{^N7^jxGI-=7R+NC~#^mCv#D0p~F33ti-j0}qb;*|DCY?2ev>1vp zjKr29LRP*4y~s7z@2?!y|Ia&OwjULA`BCbZYx{j4oc`Xuj((kkUOcVYF#oeFO&Z*v zTlbUj)EVkGlJD;N`i^!_@9s+|?;(}Dcc~`ir}sMtE*fDve5n7J8Ihlqnp=PMAq}b5 z^4^H}js2JOnUwRvbDvpDg(hc^dM!asW|d#^NATHom%pxDGpI{|+kg@cf&SzuiSoja zh#nFs6BHrYmYX?6qt0Z4K#FJbbHja{Re(w+P$bBg9~6oHgCbvcXt5dwCFX4wqg*&} zTg5$d{N(~gv=)Bm&;o;HS|uVV`GJTbyfTpo>Im|Z;8&SYkV4M%B-)i96l~?fQR;TNP>^Di{3zV)AlVj+ z*yi{VQFA?HI$cEf=SSj(H?r*+^7i3JNsv61FeXauH)PKXc&W0L2_B zDLXQuA@3M|G;UI*WWqzLbo1kJvzcX6_=pLJ9}zLch&eMdF@?BV_#wDtx5$KncwSW6 zrhA*Wq`bTSR7Rhm@+GwvV`ZpN9Bb1hk+xPw%OIUG#+Ite*!Et_vL)87@1%{4Pg%0} z?ER>%G5HfaxAW`eI4O2NOJK6zFH&!^`-P-gOnwo1T^eZMeqk1q$zt{kv6Dthek93H zZ?pRq6sK`~zl+hBZZepK<~+_3_^hMHTVI1cU1v0m6h=j4j?XsNjkFsLD$SjJ-%mfi zH}ch>%l($UfBE9$d1t;#&m(e2z4G+ooN6!k95E-X;%gUY-=0aGF$kVP2BX2O*V$rp zCaY0zQ{`SoVN*l) zC3LRTi}iIKas17k+oQI>liK!b%(TddS%bs(ez4=)Lofon+pW9%QuTy0EA=J)OYVwW zFu!)U&OyiPToYDYQgtzb?t~ZGT(b)IK-zZq`x)yf>j|rt-~0itQYX8*7GZ(rP=)%- zvld=CA78Kk%4My3*i)J}8z)SKuQCyF#F4`yR+eYhBPzk17I2$AEk@V@ED-`G(NYOa zXB}=2frOg`0n*vlhBR375J1q|5CGxTY)MbErbEycqvjNQjooft#u^J7w8`mE)urA( zH*9PB++81AKm8R8bZ-I=CLoT=0y%MH<<4pEBisXWg!KeTtJgW}I zRT|~GL?AAPm%dN=7Hp*hZ5Ldpj6ke(4|D!`$_R*<`>#iirH?G$Vc$s|(X1X&ZrYlJ zSGsnu6>Hf%HN0s*)$S{r!#Q`3-Hu*VZux=u7ArLU&m?XhK14W0l5z(L3H8U6b~P(Q z+&p+7kU7ERD1fy7#^;My_n2PTzrZiC_w1vacc%P&cAJ1_&)F{<%x@O`{;Gh5<8#Y@ z^NRxyS3Vs@ggabOy!m?s8G@cf7UQT9%@aXQlvy}3qBoC=iA7{LjuLrpz|v-)^w|{= zt?s|KZ$j3T4IOen_+n13u(Zcb0dv-jOenu0s($#J?WdiD-@Sb7T*DO|LUPtGjc>VN z$dujtKJI-^_}wapAFH-n`z1~svU%a$yQZ=5yD>p~8aLG6ICpYeT$3$&U%O`W*Ez!P zRt;ZO^`mpWwab1OTFP2E5zIcCXH|_ioY-1&!Kyla^EU1NeC@cBfk6VV)hR#av>5K+ zv(%==TaP|BFzd3W%dK0viJxdEeC-!qW9HN!4~-t3+*|n75?m>N^p-!2xLaTkE0IjD z>&Gv>uhrL)M9aLgyP_& zfCJ25Ux=ip;Rv^+%6Fs7P6q_K4oao&5#A{z*B|>O(t2; zK35!?^pRX>L7BMNtNF4!9~9#8?lesiy_^Zdm&u+(?qDdB`N?^iIm~Rl*^4ALPT-mk zS9rcuyh-0$H~`2Lw<61iqf`qwRkzO&9A&YRDi@R4MgSaHu?{a6SvL#!@AxsQQH?PU5r?XNh0E$H72m=}M2ZRAa#bK&GcjpNX_*7!CpnpF%8!^sE;$ z(%>i~v&f{IAJpty^0Da8Jw z`B88LMgJbx+Dgxq_(l>A5(R-EE8X=pPX%t~VwG#IgD2hf z&fuzW$bT{e8<0XBS(1V2)56UfnRYGR>V+P81K|CMqy8dp+1*nIn*okGvPgq_>R=YY zQOB1Qa5W%Wg)m_xS&|5(f|$^S)s9hOe$J>edRC8{|7HJ-z{ul0^LABA`t_UK`R&SX z4s4(EsjfZ=T+K_J_~?}SUzNg5<%8n#a<2XndHZU`2CS@bLhFM1{!bKI@Tm#;r#h;+ zUa*hh9~A@K&mU*s8}jylgj~G8bw({E)JUdab)q$BxN|+kpdgvZ19b#>=hI#Y^ppt! zE(3=Wb1oAOCMObTDb@wCa7xprrgux?&}2d(#B;IoCJ1{}n%KoR+dn~^6~gMqmUJv( zA|Q19OOtu<;o(kkM>>AiDRJ?-fZeax4Ns5Kl2b;JW)PLh7y%4_;}M2Ty)*HdP4iao zOe37gn|!L*74@izl`6j6C;anqgAUf*WVx|WbE?(VHf60lUdk!0J&|2*YIL`us=Bba zoe%f;umpQ=+b@PU)>YieP7Zu<0|dY%!Lnk8o9rr zI=Yta>?K23=7+B>I(R;Eag)5O6+RlT?ssN?uOGkZx<6}W{=!?=!X9Yz&yBiaEAd|F zk8Pqtmu)yY`0nK!cZ7A)j=!1k1wFrE*WTql=_9}2+Olg|^7g1_(|V4Y@@t7^Lx%i9 ztZ1-SzQ(Sp>-OJhJ99$UMGMc>TfA=Lhgoz%GLLCw7N zOFnK;J*W20{!=ej8)w@UykPVTnt(-*9&WvVsbxczs{ez3H>@iCu|rY!exxv~ygc#l zlYipbQE9bphrGfNV<&%Kd`tb#w%)#FUg=UlbKb65#_CfZ<=tOV)1XdlQKfGwzmQ+{ zwQAP#Xv0g3wZAUSYeD%8NYGjrrf;g0Tdq>hn4VL&d=>x9o~T*dK_0`%g*T>$QgZG< z7tXu5%QCb-E~$}E;TQ0D zt0M3lruCjp zuL$x=TI%)0zEI%u(){{roe$Gg9cv69IKX%FbaSsY)lJ6*>)@0(zTelW!N8me%dM}d zb6!5;Fxn~bQ`Nov!R71v3}3c5cv3)Ahpdnn!%EsyR<`Zm=)rG8+V{UZu9ok?%HNqM z0a{|Z{PUmQ`_ETxeLkdO*3H^$9}i31{pSGr564~kX=_{4*LQ{1%-Jxv*GEZRU(t+x zt?c*NJxVt(y)@#?gs(4Oct2uvJ8iAuagw?n`>V!-nNX9yG~WN>$-w>FOT;yws7`8k zA?MV6$EPQhZTRz+)X3;rch)3?q#xNCN6TMTX%2sO^W>4Uwbi|M#LxP$^wICCZGZTU zz~0BDj-0MPBcaBOTV(@d_FRt?zFM~StWSF{92b_cUK_3cWy>cc5@|INNQwco)JGdh zsSi@+!%;1R{Gr}fP}`%sVUXW2_<`M)+8qAJD9)kM@E34kmF#dW^2f@E2Zf1I%mFTW zcGUyhYma}UC2v8vJm`Uq&KFgwhv@mFiIYg(7z|G$ptaKf^rwDA3=)Xh1hJmjDnJPux}aqUP-3D zr*fz7F{VLG(8TAPDNWo5(csRIc4XR=}T)EN{?IREV{ z019kXZ?2pFsAm1hx{Hb_g$MQ%Mkze!CB*$HFw!tS<-8uaKjpSSA8vx6N-$74MJhKc zD22-SlvC1if2uU|Q%(WI{V6DF%RuFn3*4V7%lwq{xN?8$8Rn~slwk~c| z<(Qvx8lAX51qB}%YO^#fa)!z=j9%t9Sv$EsrdhhDm)pe8Q;SjNs60lTyG$S;QAjx78 zWI7)~H^x>RUAQYTbgBLt97Qn!^|(EL?stu243ihV_0q$yR12xBWm?B^R7oxkg1=C{y=?kn#h_AtM}g8k++s5(_p;ax zWEokTTg~21>^if!GvC;hNP4`*C#E?66>Bi*?LGedS(L$??)ZP1C_iWJFLp=)4kf&w z)6Gz5qhQ-Z4{LjxPKb=43rqE7#UYV5nm$Qq6nYjgS#y(#1N;$;Fa;cIU@xT^jCxW> zv!5Y34NBKDSaMr&D6mR)1L+kggslkiH}1LfyW)`Gl663ev0BnN5Is~J5j;z+B&w%) zFrW#t8v570aT1(B=f5E0ji9fUoJebgAC?jq$4ILB=A%z4=LGT zb6mGNBgd+NWL6jw+_rXsMP1Cv`VpO7(6I!74+vw0f%$?=batI}d-8p%D2@e`$igw0 z?&17PaX7%5q3OD0j{Q?paV)@^!a;`aSyM-GI8d!F*^<(ntd~h|)AiEX;Qyw9($Cz< z{!C1AsYOuA&Vk9QHzyg45G@69i%AxXEjiW_W=V?HB^%P&_&PB0$t5VI_#!Mx>2~4b zbt3J<lCsM*>-P znkxTr6p_VHi@C9Jw2^gCSt>A&sOZ7s+BBfZ(X}QVRb(w~H?|QRUD4IVHCw4PcFN$w zw*?LYvXC?Lg^Z&r+WNUBPI=7W=poCiN)=2TIb^#9iJb;VO>~xVF;lvWXm>ge0yr|XP{k;15m%<5&l+o`8E>8hXfwz0vo{@J9; zJp9e0sn!Pckty#6Z>5jyd_EwZUhsE(?TSrZM?$QG&XszxzOEw<1aoeW+Wt;z+p96t zA|GZA4&VF1j&Bda2yt^WY$HTjLsZvEpj&K+e}tLk2{}PBR;B?{J!2|_1y7oaO7O$P|&?I7-Ak z0ZaSOidYq%ZBO>#k! zvI!de!3&#>Nz23}*V2L4#Dz_?rh}|yd|h#T(mt5dmfb9L$%>Pz zC~fNJ(z}xd&8RpuDaRZIl|l`~IzSI7QCSs-<#2r$+=aq{=nJVFZb79f4vM22CyQf{ z2cz&FlL`*e9wPSWW#Jq36!6jdabqh)Ay%wk^dQ-%h8kXg_UJY{Imo|*;ibH$-a zAIXIll!=SInlCdQH#h~@X__KwT}&9hO!gdd2Sb@KVb06UVP@lv9Y)6MNyVG=t%U=C zjE5|;Y&c4_z+mPu$a2MRxP6A;D2ruxxG1xY064P9=twsY92{L_B(r-7fg_EKQY0oem1Y}H{^sH+#?2sU(w;SvQ)kSy( zDl+6yy7@uPj&|C%ag!FEGhAYZR~f{CKt|QmJsvoc#8HG0>~uE*jwCX8mgYyn5fuG< zTx%;mQ{o#*G`-*;Amai#o@qGx$c!MVT$5TRZ~%~LLDHv;i-{FS9T^8Jz1oVt-*Lo| zke3eR*~ zo$>OQMlvzYi^B~89TrSkQmtj*){DEet=+-cwx^&ol)RPo!gF&~U4B@e(&yqY|66oV z)9gm_*(+x+_ODW-&(X}))!JM#N4D0G`0chw_Rb1bkXCQ+OKJ=bq8V%^l3p;@D%I4y)Qka zOMoklk7e5;nJ|cL@sG`SdcO5sqTBYv@AD(1DSiiq^#L^V7?M`OulS9 zH-Mp#7DM5e7cf`>5P-qNDA^L;-k0JX1{qllkq4ex+4$_K(+7r7*)V(R077tqY?wWD z28jdl@1Nc&u$8+L8k_`13qR*2#QiC6?@Rs$bl%>V{Jiq^zN`?MHRI;S%w{o_mS0|V zcFu!CnYcp^#$CoCcUC3fKIC3`!M}06y>j_^<+fKYGT+|Y`?5f};%h}ImK_s~&<+>n zYR+VT;-VBJ5+6YbXLK!)>NK|E=!#*KTwUs@{u&%bF}jG0qQmF!uLkSc*jmp48rB21{D&7$1RqO7^uZXh6JM( znv_sp97|G+x8)*93Mx8#2w+Kx(b`<3V95%%2*6SkV=1|)xj5-?n^6ok;-UrRLG*T$ zy-;h2f;bP}(p+lo;X{4x;7b|w@h3KwxVMpAF@%i=e=s98KIw*w309q$eoFZ(B@jNM^G zvj5{M39+irvJwH|@y@6Qz;;{X+Nc$+e9poF)D*@+EuGDRlc_iy@m=(1w@GF?;sM3c zxase}U=irMO0QTkW#w7Gl;2A3YNE4HDZisY>Gt-%Eb#kqRXKzAv$yvpy#O5SC2#Lb zW_dhT;~&=9f5;S-;KpaTigA}LsaomneaWb12_LzBvAgYwGQNN$;cp+lzVT z*!vq!BU=kmrl^g#_a!Co0Ga7t%#H1^M02H6f}ISR4A){!;~y9^$=h!rIu zx-q%9DzTs9whOZ6kGJ>bU|q6hxJhRXAfmT-A}?(XQmk9`YUh@NSBWPR7wNc5ti64>s z(-SBcC}Q=H3seiaK#^!yeo(NL3rDHj5MV9R8_{d_ga=Mv2J}QZDf4PlD%i|M{SMCpV+ybUoS`T zI=i1GFj?;xsW;jELeeZIzX-i94K#4SFpJ4#G5dwsNy{WZlH{ki+5HNN(>T80#b``7 z8O%Z(9_I*r*3r$aufd+KGa5z;qarfLXPfIr+KmR4=FYzFr=Q*%`D)PRe#_p!eDU$T zGhe0W5xJvYdHQfpwU>L2m=jjhVUmIV$VpG?V5G%oUrCzMB>xkoT=G-2& z{hiddS7W9{KFk^%zW0M2-yVVy61mJUD+qezrRoW1R_aUom)sS%V1Dgxor8|oxhAZ* zr0QY<-3c!=v}P6Vfwb-J_cPW}))Q7OzxjjG^btmpRCaYO!UD~q3iX#~Exd9*zFz;8 z%UboYr!;RiPM8W`Wg_B;BZoz-A1oz8T$C8nN?%%?hgz){=&M0_SieH0X*JqgAfw}u%dK^0v3+XE&t6g4m@1>bQBTp za7FRv?-6VWdJ01F7tXzF8VkQ06SSvsL;a0&C%45l*`oKgYc_wKBm8dF@KsemI@epf z?1!PHtd$eN?4x;B)p)~+ttA(%s?#@b)9%mLjw=}$B=B0D@>5QW;r=~KZCbqb=yL?!$c4Hl-(Oib*ka@_hkY)XY2lncISsP#_IOHlPv9Fmkx(2xgS*lbK%CMLO- zPTCra)+C6lYa|gJBLBk8NtR?{4c3`VU>0FqSmPDPC>6farhzPUlNCqD z*#VjbaH`?}!RP04I~47w%R-jLL?)MVBt=%V9U=?aA|^8BWS)2|A}ltOj+t1hTB3NVg2WGKurQ+y#JJ_-iu2CGJR4*yq7!g_%vY_QYWoXd1kOl3)Q-%iZBw5ftR~(x3 zkz8m&nYh@i`7+Z7g?s!tO;bcKXTtDhvgeRH7|LXRa$aT*GaGOAB8iQ2*bTYD^QGcV z`qsh$K&H4ASvDM{TDYmYeTLvDifJ{%5J`-urFdPIDK7|l#(z9O3NQ0w{%p#L+ zeo(WcEonk%4Klk_bk1;{cV1->H-BWJG~MHYBMEDbS!}u+0Y{Q}rx5##=10L16#aW# zYb!ld;u}dcz2G1qQ@y07DG@@!GYv-{S>!<~*QAyS8~|jc2kBGB#l(uEj!bQoUTsC+ z?>OQl?i{h-i)b(=%P_r3Z%&KNuwt_dNfZQvtaR7YJQcW^i&d_<4xV(^JA|Gu>8a zy!@pRXbG|33T4#7QF+3QT1u#qOu_0zYtV4#dWbl*zWt1o*7qZhh{E(xYNk}4b{=L zY-cYS!ZJU6ZPCH=k&Bz;U9IrZcy+%s`+NQPP1pTdEAtoLx)%08n}2T94O@x#LVs)% z6}oK0(ZP2w-?$?zlXm>ggfHmn4ZHR(?@1r|{nnOU%aXT8J)72Z)RbRKG#fJH7h*(% zrSdg)OWC_D?X4Mu)WhuO&ma7EMB`uHXfuU(f_Bdh~GX{Yxzys#N_S{JUXQ>5m=iqW2?(S>@%4cc1(d z&yGr~Z9C)@h8R2f`{G;bceeHRE%Qp3`kC`~%`#S>@+j~Aikb#>Vv8z$OZkQTvaeOM zmPZ?2TCDwbXn$Wy5+0*XZA$R+79v$j!k56>;j(EhljMm~jKF#okS zOFQa_W>eTpm8UPAHuIfU33GC~_3pjx%`bm-+*D1!Rz1>1b$&Q2`@8MsTTU3^W(lty z*u80AmCu$1E zZR=R9tL5syM)@1qb?^Q$aR+4tzP5MFi?Q^tkv&YAI@npg)1>ePc@k9H@@H3slmXU3CpdosB>OE z;;j{K4hx`V3#TICxS(REMmP7sE>0Q&zU^-{`?_L)!PhJFb@R!OGv6CuIt? h281hD_*d`!=c~3pA5t;vX6?0)hb8V7M;!n4{{RBT6jT5J literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..db77503c25021445dbb32d008d162bb3cc9e9230 GIT binary patch literal 10726 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridvisualizationraytracingmiss_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..b44637279f342f92e439868f6067153d7c81f3b4 GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3^Wow0kVv7S8VC@od2$hTP*giP40{T0SVgcHyAE@iTKzr zf3hhh(EQi2N`LW)nb#sKjor`spV%pw{Q1#_nN}Ro&|qYU(KNsL8A}kefK^oHoBq_m OqM5O7$;5MKfJy*kF~aHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3^Wow0kVu~8Jm08^p_60%gZ|672P`a6B4x7Z!lc+67jKL z{$x{1p!u(3mHy%pGp|Kf8oQtMKe1CV`SYU=Y0rqm?lwaP*=9yy$WRY+P{(6h2^1=(}VUn_CL`~W_-cSq|DC1$_NZ( zJ_cBT3oDceJntiF)-W%`V*u^7-$;@kX8ipIDs^X zZ4FcjQUh`yNS!v24>E%bh#43f_L~8DAax-7K>(!h2T(OPkhTS?1)0kO#322FK(!#d zd7)w;Js>fVTlk=2AawyiRUm!*Kn$`6q#h)12NVU#gT(&=ZL|Q{8i6hTfoWxn{E7B} z#@>Z`aRCM!vQn$wK4Se3R?EC #include #include +#include +#include +#include +#include #include #include #include @@ -278,6 +282,10 @@ namespace AZ passSystem->AddPassCreator(Name("DiffuseProbeGridClassificationPass"), &Render::DiffuseProbeGridClassificationPass::Create); passSystem->AddPassCreator(Name("DiffuseProbeGridDownsamplePass"), &Render::DiffuseProbeGridDownsamplePass::Create); passSystem->AddPassCreator(Name("DiffuseProbeGridRenderPass"), &Render::DiffuseProbeGridRenderPass::Create); + passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationPreparePass"), &Render::DiffuseProbeGridVisualizationPreparePass::Create); + passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationAccelerationStructurePass"), &Render::DiffuseProbeGridVisualizationAccelerationStructurePass::Create); + passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationRayTracingPass"), &Render::DiffuseProbeGridVisualizationRayTracingPass::Create); + passSystem->AddPassCreator(Name("DiffuseProbeGridVisualizationCompositePass"), &Render::DiffuseProbeGridVisualizationCompositePass::Create); passSystem->AddPassCreator(Name("LuminanceHistogramGeneratorPass"), &LuminanceHistogramGeneratorPass::Create); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index 798ebc502b..b04078c893 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -43,10 +43,15 @@ namespace AZ m_irradianceImageAttachmentId = AZStd::string::format("ProbeIrradianceImageAttachmentId_%s", uuidString.c_str()); m_distanceImageAttachmentId = AZStd::string::format("ProbeDistanceImageAttachmentId_%s", uuidString.c_str()); m_probeDataImageAttachmentId = AZStd::string::format("ProbeDataImageAttachmentId_%s", uuidString.c_str()); + m_visualizationTlasAttachmentId = AZStd::string::format("ProbeVisualizationTlasAttachmentId_%s", uuidString.c_str()); + m_visualizationTlasInstancesAttachmentId = AZStd::string::format("ProbeVisualizationTlasInstancesAttachmentId_%s", uuidString.c_str()); // setup culling m_cullable.m_cullData.m_scene = m_scene; m_cullable.SetDebugName(AZ::Name("DiffuseProbeGrid Volume")); + + // create the visualization TLAS + m_visualizationTlas = AZ::RHI::RayTracingTlas::CreateRHIRayTracingTlas(); } void DiffuseProbeGrid::Simulate(uint32_t probeIndex) @@ -253,6 +258,23 @@ namespace AZ return m_cullable.m_isVisible; } + void DiffuseProbeGrid::SetVisualizationEnabled(bool visualizationEnabled) + { + m_visualizationEnabled = visualizationEnabled; + m_visualizationTlasUpdateRequired = true; + } + + void DiffuseProbeGrid::SetVisualizationSphereRadius(float visualizationSphereRadius) + { + m_visualizationSphereRadius = visualizationSphereRadius; + m_visualizationTlasUpdateRequired = true; + } + + bool DiffuseProbeGrid::GetVisualizationTlasUpdateRequired() const + { + return m_visualizationTlasUpdateRequired || m_remainingRelocationIterations > 0; + } + uint32_t DiffuseProbeGrid::GetTotalProbeCount() const { return m_probeCountX * m_probeCountY * m_probeCountZ; @@ -348,8 +370,8 @@ namespace AZ // textures have changed so we need to update the render Srg to bind the new ones m_updateRenderObjectSrg = true; - // we need to clear the irradiance texture - m_irradianceClearRequired = true; + // we need to clear the Irradiance, Distance, and ProbeData textures + m_textureClearRequired = true; } void DiffuseProbeGrid::ComputeProbeCount(const AZ::Vector3& extents, const AZ::Vector3& probeSpacing, uint32_t& probeCountX, uint32_t& probeCountY, uint32_t& probeCountZ) @@ -753,6 +775,77 @@ namespace AZ UpdateCulling(); } + void DiffuseProbeGrid::UpdateVisualizationPrepareSrg(const Data::Instance& shader, const RHI::Ptr& layout) + { + if (!m_visualizationPrepareSrg) + { + m_visualizationPrepareSrg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), layout->GetName()); + AZ_Error("DiffuseProbeGrid", m_visualizationPrepareSrg.get(), "Failed to create VisualizationPrepare shader resource group"); + } + + RHI::ShaderInputConstantIndex constantIndex; + RHI::ShaderInputImageIndex imageIndex; + RHI::ShaderInputBufferIndex bufferIndex; + + // TLAS instances + bufferIndex = layout->FindShaderInputBufferIndex(AZ::Name("m_tlasInstances")); + uint32_t tlasInstancesBufferByteCount = aznumeric_cast(m_visualizationTlas->GetTlasInstancesBuffer()->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, tlasInstancesBufferByteCount / RayTracingTlasInstanceElementSize, RayTracingTlasInstanceElementSize); + m_visualizationPrepareSrg->SetBufferView(bufferIndex, m_visualizationTlas->GetTlasInstancesBuffer()->GetBufferView(bufferViewDescriptor).get()); + + // probe data + imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeData")); + m_visualizationPrepareSrg->SetImageView(imageIndex, GetProbeDataImage()->GetImageView(m_renderData->m_probeDataImageViewDescriptor).get()); + + // probe sphere radius + constantIndex = layout->FindShaderInputConstantIndex(Name("m_probeSphereRadius")); + m_visualizationPrepareSrg->SetConstant(constantIndex, m_visualizationSphereRadius); + + SetGridConstants(m_visualizationPrepareSrg); + } + + void DiffuseProbeGrid::UpdateVisualizationRayTraceSrg(const Data::Instance& shader, const RHI::Ptr& layout, const RHI::ImageView* outputImageView) + { + if (!m_visualizationRayTraceSrg) + { + m_visualizationRayTraceSrg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), shader->GetSupervariantIndex(), layout->GetName()); + AZ_Error("DiffuseProbeGrid", m_visualizationRayTraceSrg.get(), "Failed to create VisualizationRayTrace shader resource group"); + } + + RHI::ShaderInputConstantIndex constantIndex; + RHI::ShaderInputImageIndex imageIndex; + RHI::ShaderInputBufferIndex bufferIndex; + + // TLAS + uint32_t tlasBufferByteCount = aznumeric_cast(m_visualizationTlas->GetTlasBuffer()->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(tlasBufferByteCount); + + bufferIndex = layout->FindShaderInputBufferIndex(AZ::Name("m_tlas")); + m_visualizationRayTraceSrg->SetBufferView(bufferIndex, m_visualizationTlas->GetTlasBuffer()->GetBufferView(bufferViewDescriptor).get()); + + // probe irradiance + imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeIrradiance")); + m_visualizationRayTraceSrg->SetImageView(imageIndex, GetIrradianceImage()->GetImageView(m_renderData->m_probeIrradianceImageViewDescriptor).get()); + + // probe distance + imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeDistance")); + m_visualizationRayTraceSrg->SetImageView(imageIndex, GetDistanceImage()->GetImageView(m_renderData->m_probeDistanceImageViewDescriptor).get()); + + // probe data + imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_probeData")); + m_visualizationRayTraceSrg->SetImageView(imageIndex, GetProbeDataImage()->GetImageView(m_renderData->m_probeDataImageViewDescriptor).get()); + + // show inactive probes + constantIndex = layout->FindShaderInputConstantIndex(Name("m_showInactiveProbes")); + m_visualizationRayTraceSrg->SetConstant(constantIndex, m_visualizationShowInactiveProbes); + + // output + imageIndex = layout->FindShaderInputImageIndex(AZ::Name("m_output")); + m_visualizationRayTraceSrg->SetImageView(imageIndex, outputImageView); + + SetGridConstants(m_visualizationRayTraceSrg); + } + void DiffuseProbeGrid::UpdateCulling() { if (!m_drawPacket) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h index 8c8470cdad..3f65d6083a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -98,6 +99,15 @@ namespace AZ DiffuseProbeGridMode GetMode() const { return m_mode; } void SetMode(DiffuseProbeGridMode mode); + bool GetVisualizationEnabled() const { return m_visualizationEnabled; } + void SetVisualizationEnabled(bool visualizationEnabled); + + bool GetVisualizationShowInactiveProbes() const { return m_visualizationShowInactiveProbes; } + void SetVisualizationShowInactiveProbes(bool visualizationShowInactiveProbes) { m_visualizationShowInactiveProbes = visualizationShowInactiveProbes; } + + float GetVisualizationSphereRadius() const { return m_visualizationSphereRadius; } + void SetVisualizationSphereRadius(float visualizationSphereRadius); + uint32_t GetRemainingRelocationIterations() const { return aznumeric_cast(m_remainingRelocationIterations); } void DecrementRemainingRelocationIterations() { m_remainingRelocationIterations = AZStd::max(0, m_remainingRelocationIterations - 1); } void ResetRemainingRelocationIterations() { m_remainingRelocationIterations = DefaultNumRelocationIterations; } @@ -125,6 +135,8 @@ namespace AZ const Data::Instance& GetRelocationSrg() const { return m_relocationSrg; } const Data::Instance& GetClassificationSrg() const { return m_classificationSrg; } const Data::Instance& GetRenderObjectSrg() const { return m_renderObjectSrg; } + const Data::Instance& GetVisualizationPrepareSrg() const { return m_visualizationPrepareSrg; } + const Data::Instance& GetVisualizationRayTraceSrg() const { return m_visualizationRayTraceSrg; } // Srg updates void UpdateRayTraceSrg(const Data::Instance& shader, const RHI::Ptr& srgLayout); @@ -135,6 +147,8 @@ namespace AZ void UpdateRelocationSrg(const Data::Instance& shader, const RHI::Ptr& srgLayout); void UpdateClassificationSrg(const Data::Instance& shader, const RHI::Ptr& srgLayout); void UpdateRenderObjectSrg(); + void UpdateVisualizationPrepareSrg(const Data::Instance& shader, const RHI::Ptr& srgLayout); + void UpdateVisualizationRayTraceSrg(const Data::Instance& shader, const RHI::Ptr& srgLayout, const RHI::ImageView* outputImageView); // textures const RHI::Ptr GetRayTraceImage() { return m_rayTraceImage[m_currentImageIndex]; } @@ -151,12 +165,14 @@ namespace AZ const RHI::AttachmentId GetIrradianceImageAttachmentId() const { return m_irradianceImageAttachmentId; } const RHI::AttachmentId GetDistanceImageAttachmentId() const { return m_distanceImageAttachmentId; } const RHI::AttachmentId GetProbeDataImageAttachmentId() const { return m_probeDataImageAttachmentId; } + const RHI::AttachmentId GetProbeVisualizationTlasAttachmentId() const { return m_visualizationTlasAttachmentId; } + const RHI::AttachmentId GetProbeVisualizationTlasInstancesAttachmentId() const { return m_visualizationTlasInstancesAttachmentId; } const DiffuseProbeGridRenderData* GetRenderData() const { return m_renderData; } - // the irradiance image needs to be manually cleared after it is resized in the editor - bool GetIrradianceClearRequired() const { return m_irradianceClearRequired; } - void ResetIrradianceClearRequired() { m_irradianceClearRequired = false; } + // the Irradiance, Distance, and ProbeData images need to be manually cleared after certain operations, e.g., changing the grid size + bool GetTextureClearRequired() const { return m_textureClearRequired; } + void ResetTextureClearRequired() { m_textureClearRequired = false; } // texture readback DiffuseProbeGridTextureReadback& GetTextureReadback() { return m_textureReadback; } @@ -168,7 +184,16 @@ namespace AZ static constexpr uint32_t DefaultNumDistanceTexels = 14; static constexpr int32_t DefaultNumRelocationIterations = 100; + // visualization TLAS + const RHI::Ptr& GetVisualizationTlas() const { return m_visualizationTlas; } + RHI::Ptr& GetVisualizationTlas() { return m_visualizationTlas; } + + bool GetVisualizationTlasUpdateRequired() const; + void ResetVisualizationTlasUpdateRequired() { m_visualizationTlasUpdateRequired = false; } + private: + + // helper functions void UpdateTextures(); void ComputeProbeCount(const AZ::Vector3& extents, const AZ::Vector3& probeSpacing, uint32_t& probeCountX, uint32_t& probeCountY, uint32_t& probeCountZ); bool ValidateProbeCount(const AZ::Vector3& extents, const AZ::Vector3& probeSpacing); @@ -248,7 +273,7 @@ namespace AZ RHI::Ptr m_probeDataImage[ImageFrameCount]; uint32_t m_currentImageIndex = 0; bool m_updateTextures = false; - bool m_irradianceClearRequired = true; + bool m_textureClearRequired = true; // baked textures Data::Instance m_bakedIrradianceImage; @@ -281,6 +306,17 @@ namespace AZ RHI::AttachmentId m_irradianceImageAttachmentId; RHI::AttachmentId m_distanceImageAttachmentId; RHI::AttachmentId m_probeDataImageAttachmentId; + + // probe visualization + bool m_visualizationEnabled = false; + bool m_visualizationShowInactiveProbes = false; + float m_visualizationSphereRadius = 0.5f; + RHI::Ptr m_visualizationTlas; + bool m_visualizationTlasUpdateRequired = false; + RHI::AttachmentId m_visualizationTlasAttachmentId; + RHI::AttachmentId m_visualizationTlasInstancesAttachmentId; + Data::Instance m_visualizationPrepareSrg; + Data::Instance m_visualizationRayTraceSrg; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index a5da79a482..0b2f74191f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -75,27 +75,34 @@ namespace AZ } } - void DiffuseProbeGridBlendDistancePass::FrameBeginInternal(FramePrepareParams params) + bool DiffuseProbeGridBlendDistancePass::IsEnabled() const { - RPI::Scene* scene = m_pipeline->GetScene(); - DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + if (!RenderPass::IsEnabled()) { - // no diffuse probe grids - return; + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; } RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); - AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBlendDistancePass requires the RayTracingFeatureProcessor"); - - if (!rayTracingFeatureProcessor->GetSubMeshCount()) + if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount()) { // empty scene - return; + return false; } - RenderPass::FrameBeginInternal(params); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + return true; } void DiffuseProbeGridBlendDistancePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h index 942f90eb10..6d9d26f9b3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h @@ -42,8 +42,7 @@ namespace AZ void LoadShader(); // Pass overrides - void FrameBeginInternal(FramePrepareParams params) override; - + bool IsEnabled() const override; void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index 7a12fc5415..4e29339a38 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -75,27 +75,34 @@ namespace AZ } } - void DiffuseProbeGridBlendIrradiancePass::FrameBeginInternal(FramePrepareParams params) + bool DiffuseProbeGridBlendIrradiancePass::IsEnabled() const { - RPI::Scene* scene = m_pipeline->GetScene(); - DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + if (!RenderPass::IsEnabled()) { - // no diffuse probe grids - return; + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; } RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); - AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBlendIrradiancePass requires the RayTracingFeatureProcessor"); - - if (!rayTracingFeatureProcessor->GetSubMeshCount()) + if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount()) { // empty scene - return; + return false; } - RenderPass::FrameBeginInternal(params); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + return true; } void DiffuseProbeGridBlendIrradiancePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h index 77dba9745c..a9bf9bfc31 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h @@ -42,8 +42,7 @@ namespace AZ void LoadShader(); // Pass overrides - void FrameBeginInternal(FramePrepareParams params) override; - + bool IsEnabled() const override; void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp index c4fcb49c17..ee2b638cb7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp @@ -83,27 +83,34 @@ namespace AZ } } - void DiffuseProbeGridBorderUpdatePass::FrameBeginInternal(FramePrepareParams params) + bool DiffuseProbeGridBorderUpdatePass::IsEnabled() const { - RPI::Scene* scene = m_pipeline->GetScene(); - DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + if (!RenderPass::IsEnabled()) { - // no diffuse probe grids - return; + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; } RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); - AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBorderUpdatePass requires the RayTracingFeatureProcessor"); - - if (!rayTracingFeatureProcessor->GetSubMeshCount()) + if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount()) { // empty scene - return; + return false; } - RenderPass::FrameBeginInternal(params); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + return true; } void DiffuseProbeGridBorderUpdatePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h index ee49c66f78..415231c281 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h @@ -40,8 +40,7 @@ namespace AZ RHI::DispatchDirect& dispatchArgs); // Pass overrides - void FrameBeginInternal(FramePrepareParams params) override; - + bool IsEnabled() const override; void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index 1d1e6f745f..acb5b73c1a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -79,27 +79,34 @@ namespace AZ } } - void DiffuseProbeGridClassificationPass::FrameBeginInternal(FramePrepareParams params) + bool DiffuseProbeGridClassificationPass::IsEnabled() const { - RPI::Scene* scene = m_pipeline->GetScene(); - DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + if (!RenderPass::IsEnabled()) { - // no diffuse probe grids - return; + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; } RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); - AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridClassificationPass requires the RayTracingFeatureProcessor"); - - if (!rayTracingFeatureProcessor->GetSubMeshCount()) + if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount()) { // empty scene - return; + return false; } - RenderPass::FrameBeginInternal(params); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + return true; } void DiffuseProbeGridClassificationPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) @@ -160,15 +167,11 @@ namespace AZ const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetClassificationSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); - uint32_t probeCountX; - uint32_t probeCountY; - diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY); - RHI::DispatchItem dispatchItem; dispatchItem.m_arguments = shader.m_dispatchArgs; dispatchItem.m_pipelineState = shader.m_pipelineState; - dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX; - dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY; + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = diffuseProbeGrid->GetTotalProbeCount(); + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; commandList->Submit(dispatchItem); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h index 3ec76fd0f0..894e9df098 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h @@ -43,8 +43,7 @@ namespace AZ void LoadShader(); // Pass overrides - void FrameBeginInternal(FramePrepareParams params) override; - + bool IsEnabled() const override; void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index d690c57dea..84c066604a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -39,6 +40,7 @@ namespace AZ void DiffuseProbeGridFeatureProcessor::Activate() { RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get(); + RHI::Ptr device = rhiSystem->GetDevice(); m_diffuseProbeGrids.reserve(InitialProbeGridAllocationSize); m_realTimeDiffuseProbeGrids.reserve(InitialProbeGridAllocationSize); @@ -49,7 +51,7 @@ namespace AZ m_bufferPool = RHI::Factory::Get().CreateBufferPool(); m_bufferPool->SetName(Name("DiffuseProbeGridBoxBufferPool")); - [[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(*rhiSystem->GetDevice(), desc); + [[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(*device, desc); AZ_Error("DiffuseProbeGridFeatureProcessor", resultCode == RHI::ResultCode::Success, "Failed to initialize buffer pool"); // create box mesh vertices and indices @@ -61,7 +63,7 @@ namespace AZ imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead; m_probeGridRenderData.m_imagePool = RHI::Factory::Get().CreateImagePool(); - [[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_imagePool->Init(*rhiSystem->GetDevice(), imagePoolDesc); + [[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_imagePool->Init(*device, imagePoolDesc); AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize output image pool"); } @@ -90,6 +92,22 @@ namespace AZ AZ_Error("DiffuseProbeGridFeatureProcessor", m_probeGridRenderData.m_srgLayout != nullptr, "Failed to find ObjectSrg layout"); } + // initialize the buffer pools for the DiffuseProbeGrid visualization + m_visualizationBufferPools = RHI::RayTracingBufferPools::CreateRHIRayTracingBufferPools(); + m_visualizationBufferPools->Init(device); + + // load probe visualization model, the BLAS will be created in OnAssetReady() + m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( + "Models/DiffuseProbeSphere.azmodel", + AZ::RPI::AssetUtils::TraceLevel::Assert); + + if (!m_visualizationModelAsset.IsReady()) + { + m_visualizationModelAsset.QueueLoad(); + } + + Data::AssetBus::MultiHandler::BusConnect(m_visualizationModelAsset.GetId()); + EnableSceneNotification(); } @@ -106,6 +124,8 @@ namespace AZ { m_bufferPool.reset(); } + + Data::AssetBus::MultiHandler::BusDisconnect(); } void DiffuseProbeGridFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet) @@ -186,13 +206,19 @@ namespace AZ void DiffuseProbeGridFeatureProcessor::OnEndPrepareRender() { - // re-build the list of visible real-time diffuse probe grids + // re-build the list of visible diffuse probe grids + m_visibleDiffuseProbeGrids.clear(); m_visibleRealTimeDiffuseProbeGrids.clear(); - for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids) + for (auto& diffuseProbeGrid : m_diffuseProbeGrids) { if (diffuseProbeGrid->GetIsVisible()) { - m_visibleRealTimeDiffuseProbeGrids.push_back(diffuseProbeGrid); + if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::RealTime) + { + m_visibleRealTimeDiffuseProbeGrids.push_back(diffuseProbeGrid); + } + + m_visibleDiffuseProbeGrids.push_back(diffuseProbeGrid); } } } @@ -237,6 +263,17 @@ namespace AZ m_realTimeDiffuseProbeGrids.erase(itEntry); } + // remove from side list of visible grids + itEntry = AZStd::find_if(m_visibleDiffuseProbeGrids.begin(), m_visibleDiffuseProbeGrids.end(), [&](AZStd::shared_ptr const& entry) + { + return (entry == probeGrid); + }); + + if (itEntry != m_visibleDiffuseProbeGrids.end()) + { + m_visibleDiffuseProbeGrids.erase(itEntry); + } + // remove from side list of visible real-time grids itEntry = AZStd::find_if(m_visibleRealTimeDiffuseProbeGrids.begin(), m_visibleRealTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr const& entry) { @@ -449,6 +486,24 @@ namespace AZ probeGrid->SetBakedTextures(bakedTextures); } + void DiffuseProbeGridFeatureProcessor::SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled) + { + AZ_Assert(probeGrid.get(), "SetVisualizationEnabled called with an invalid handle"); + probeGrid->SetVisualizationEnabled(visualizationEnabled); + } + + void DiffuseProbeGridFeatureProcessor::SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes) + { + AZ_Assert(probeGrid.get(), "SetVisualizationShowInactiveProbes called with an invalid handle"); + probeGrid->SetVisualizationShowInactiveProbes(visualizationShowInactiveProbes); + } + + void DiffuseProbeGridFeatureProcessor::SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius) + { + AZ_Assert(probeGrid.get(), "SetVisualizationSphereRadius called with an invalid handle"); + probeGrid->SetVisualizationSphereRadius(visualizationSphereRadius); + } + void DiffuseProbeGridFeatureProcessor::CreateBoxMesh() { // vertex positions @@ -613,6 +668,71 @@ namespace AZ } } + void DiffuseProbeGridFeatureProcessor::OnVisualizationModelAssetReady(Data::Asset asset) + { + Data::Asset modelAsset = asset; + + m_visualizationModel = RPI::Model::FindOrCreate(modelAsset); + AZ_Assert(m_visualizationModel.get(), "Failed to load DiffuseProbeGrid visualization model"); + + const AZStd::span>& modelLods = m_visualizationModel->GetLods(); + AZ_Assert(!modelLods.empty(), "Invalid DiffuseProbeGrid visualization model"); + if (modelLods.empty()) + { + return; + } + + const Data::Instance& modelLod = modelLods[0]; + AZ_Assert(!modelLod->GetMeshes().empty(), "Invalid DiffuseProbeGrid visualization model asset"); + if (modelLod->GetMeshes().empty()) + { + return; + } + + const RPI::ModelLod::Mesh& mesh = modelLod->GetMeshes()[0]; + + // setup a stream layout and shader input contract for the position vertex stream + static const char* PositionSemantic = "POSITION"; + static const RHI::Format PositionStreamFormat = RHI::Format::R32G32B32_FLOAT; + + RHI::InputStreamLayoutBuilder layoutBuilder; + layoutBuilder.AddBuffer()->Channel(PositionSemantic, PositionStreamFormat); + RHI::InputStreamLayout inputStreamLayout = layoutBuilder.End(); + + RPI::ShaderInputContract::StreamChannelInfo positionStreamChannelInfo; + positionStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(PositionSemantic)); + positionStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(PositionStreamFormat); + + RPI::ShaderInputContract shaderInputContract; + shaderInputContract.m_streamChannels.emplace_back(positionStreamChannelInfo); + + // retrieve vertex/index buffers + RPI::ModelLod::StreamBufferViewList streamBufferViews; + [[maybe_unused]] bool result = modelLod->GetStreamsForMesh( + inputStreamLayout, + streamBufferViews, + nullptr, + shaderInputContract, + 0); + AZ_Assert(result, "Failed to retrieve DiffuseProbeGrid visualization mesh stream buffer views"); + + m_visualizationVB = streamBufferViews[0]; + m_visualizationIB = mesh.m_indexBufferView; + + // create the BLAS object + RHI::RayTracingBlasDescriptor blasDescriptor; + blasDescriptor.Build() + ->Geometry() + ->VertexFormat(PositionStreamFormat) + ->VertexBuffer(m_visualizationVB) + ->IndexBuffer(m_visualizationIB) + ; + + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + m_visualizationBlas = AZ::RHI::RayTracingBlas::CreateRHIRayTracingBlas(); + m_visualizationBlas->CreateBuffers(*device, &blasDescriptor, *m_visualizationBufferPools); + } + void DiffuseProbeGridFeatureProcessor::HandleAssetNotification(Data::Asset asset, DiffuseProbeGridTextureNotificationType notificationType) { for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification) @@ -633,14 +753,28 @@ namespace AZ void DiffuseProbeGridFeatureProcessor::OnAssetReady(Data::Asset asset) { - HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready); + if (asset.GetId() == m_visualizationModelAsset.GetId()) + { + OnVisualizationModelAssetReady(asset); + } + else + { + HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready); + } } void DiffuseProbeGridFeatureProcessor::OnAssetError(Data::Asset asset) { - AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str()); + if (asset.GetId() == m_visualizationModelAsset.GetId()) + { + AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load probe visualization model asset [%s]", asset.GetHint().c_str()); + } + else + { + AZ_Error("DiffuseProbeGridFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str()); - HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Error); + HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Error); + } } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h index d0df7dfbfe..239de5ea27 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h @@ -9,6 +9,9 @@ #pragma once #include +#include +#include +#include #include namespace AZ @@ -46,6 +49,9 @@ namespace AZ void SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl) override; void SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode) override; void SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures) override; + void SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled) override; + void SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes) override; + void SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius) override; void BakeTextures( const DiffuseProbeGridHandle& probeGrid, @@ -76,9 +82,19 @@ namespace AZ // retrieve the side list of probe grids that are using real-time (raytraced) mode DiffuseProbeGridVector& GetRealTimeProbeGrids() { return m_realTimeDiffuseProbeGrids; } - // retrieve the side list of probe grids that are using real-time (raytraced) mode and visible (on screen) + // retrieve the side list of probe grids that are visible (on screen), both real-time (raytraced) and baked + DiffuseProbeGridVector& GetVisibleProbeGrids() { return m_visibleDiffuseProbeGrids; } + + // retrieve the side list of probe grids that are real-time (raytraced) and visible (on screen) DiffuseProbeGridVector& GetVisibleRealTimeProbeGrids() { return m_visibleRealTimeDiffuseProbeGrids; } + // returns the RayTracingBufferPool used for the DiffuseProbeGrid visualization + RHI::RayTracingBufferPools& GetVisualizationBufferPools() { return *m_visualizationBufferPools; } + + // returns the RayTracingBlas for the visualization model + const RHI::Ptr& GetVisualizationBlas() const { return m_visualizationBlas; } + RHI::Ptr& GetVisualizationBlas() { return m_visualizationBlas; } + private: AZ_DISABLE_COPY_MOVE(DiffuseProbeGridFeatureProcessor); @@ -108,6 +124,9 @@ namespace AZ void UpdatePipelineStates(); void UpdatePasses(); + // loads the probe visualization model and creates the BLAS + void OnVisualizationModelAssetReady(Data::Asset asset); + // list of all diffuse probe grids const size_t InitialProbeGridAllocationSize = 64; DiffuseProbeGridVector m_diffuseProbeGrids; @@ -115,6 +134,9 @@ namespace AZ // side list of diffuse probe grids that are in real-time mode (subset of m_diffuseProbeGrids) DiffuseProbeGridVector m_realTimeDiffuseProbeGrids; + // side list of diffuse probe grids that are visible, both real-time and baked modes (subset of m_diffuseProbeGrids) + DiffuseProbeGridVector m_visibleDiffuseProbeGrids; + // side list of diffuse probe grids that are in real-time mode and visible (subset of m_realTimeDiffuseProbeGrids) DiffuseProbeGridVector m_visibleRealTimeDiffuseProbeGrids; @@ -157,6 +179,14 @@ namespace AZ }; typedef AZStd::vector NotifyTextureAssetVector; NotifyTextureAssetVector m_notifyTextureAssets; + + // visualization + RHI::Ptr m_visualizationBufferPools; + Data::Asset m_visualizationModelAsset; + RHI::Ptr m_visualizationBlas; + Data::Instance m_visualizationModel; + RHI::StreamBufferView m_visualizationVB; + RHI::IndexBufferView m_visualizationIB; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp index 7af6f4c8ec..3fa4837a23 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp @@ -107,14 +107,39 @@ namespace AZ m_rayTracingPipelineState->Init(*device.get(), &descriptor); } + bool DiffuseProbeGridRayTracingPass::IsEnabled() const + { + if (!RenderPass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); + if (!rayTracingFeatureProcessor) + { + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + return true; + } + void DiffuseProbeGridRayTracingPass::FrameBeginInternal(FramePrepareParams params) { RPI::Scene* scene = m_pipeline->GetScene(); RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); - if (!rayTracingFeatureProcessor) - { - return; - } if (!m_initialized) { @@ -131,13 +156,6 @@ namespace AZ m_rayTracingShaderTable->Init(*device.get(), rayTracingBufferPools); } - DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) - { - // no diffuse probe grids - return; - } - RenderPass::FrameBeginInternal(params); } @@ -156,9 +174,16 @@ namespace AZ // TLAS { AZ::RHI::AttachmentId tlasAttachmentId = rayTracingFeatureProcessor->GetTlasAttachmentId(); - if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(tlasAttachmentId)) + const RHI::Ptr& rayTracingTlasBuffer = rayTracingFeatureProcessor->GetTlas()->GetTlasBuffer(); + if (rayTracingTlasBuffer) { - uint32_t tlasBufferByteCount = aznumeric_cast(rayTracingFeatureProcessor->GetTlas()->GetTlasBuffer()->GetDescriptor().m_byteCount); + if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(tlasAttachmentId)) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(tlasAttachmentId, rayTracingTlasBuffer); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import ray tracing TLAS buffer with error %d", result); + } + + uint32_t tlasBufferByteCount = aznumeric_cast(rayTracingTlasBuffer->GetDescriptor().m_byteCount); RHI::BufferViewDescriptor tlasBufferViewDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, tlasBufferByteCount); RHI::BufferScopeAttachmentDescriptor desc; @@ -191,10 +216,10 @@ namespace AZ RHI::ImageScopeAttachmentDescriptor desc; desc.m_attachmentId = diffuseProbeGrid->GetIrradianceImageAttachmentId(); desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeIrradianceImageViewDescriptor; - if (diffuseProbeGrid->GetIrradianceClearRequired()) + + if (diffuseProbeGrid->GetTextureClearRequired()) { desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear; - diffuseProbeGrid->ResetIrradianceClearRequired(); } else { @@ -212,7 +237,15 @@ namespace AZ RHI::ImageScopeAttachmentDescriptor desc; desc.m_attachmentId = diffuseProbeGrid->GetDistanceImageAttachmentId(); desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDistanceImageViewDescriptor; - desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare; + + if (diffuseProbeGrid->GetTextureClearRequired()) + { + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear; + } + else + { + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + } frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite); } @@ -225,10 +258,20 @@ namespace AZ RHI::ImageScopeAttachmentDescriptor desc; desc.m_attachmentId = diffuseProbeGrid->GetProbeDataImageAttachmentId(); desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDataImageViewDescriptor; - desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + if (diffuseProbeGrid->GetTextureClearRequired()) + { + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear; + } + else + { + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + } frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite); } + + diffuseProbeGrid->ResetTextureClearRequired(); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h index f5775f7624..13063b57a7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h @@ -45,6 +45,7 @@ namespace AZ void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; // Pass overrides + bool IsEnabled() const override; void FrameBeginInternal(FramePrepareParams params) override; // revision number of the ray tracing TLAS when the shader table was built diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp index fd23dadf6f..70b54d70cc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp @@ -74,49 +74,71 @@ namespace AZ } } + bool DiffuseProbeGridRelocationPass::IsEnabled() const + { + if (!RenderPass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); + if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount()) + { + // empty scene + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + // check TLAS version + uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision(); + if (rayTracingDataRevision != m_rayTracingDataRevision) + { + return true; + } + + // check to see if any grids need relocation + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) + { + if (diffuseProbeGrid->GetRemainingRelocationIterations() > 0) + { + return true; + } + } + + return false; + } + void DiffuseProbeGridRelocationPass::FrameBeginInternal(FramePrepareParams params) { RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) - { - // no diffuse probe grids - return; - } - RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridRelocationPass requires the RayTracingFeatureProcessor"); - if (!rayTracingFeatureProcessor->GetSubMeshCount()) - { - // empty scene - return; - } - - // create the Relocation Srgs for each DiffuseProbeGrid, and check to see if any grids need relocation - bool needRelocation = false; + // reset the relocation iterations on the grids if the TLAS was updated + uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision(); for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) - { - uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision(); + { if (rayTracingDataRevision != m_rayTracingDataRevision) { // the TLAS changed, relocate probes - m_rayTracingDataRevision = rayTracingDataRevision; diffuseProbeGrid->ResetRemainingRelocationIterations(); } - - if (diffuseProbeGrid->GetRemainingRelocationIterations() > 0) - { - needRelocation = true; - } } - if (!needRelocation) - { - // no diffuseProbeGrids require relocation, this pass can be skipped entirely - return; - } + m_rayTracingDataRevision = rayTracingDataRevision; RenderPass::FrameBeginInternal(params); } @@ -160,11 +182,7 @@ namespace AZ // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) diffuseProbeGrid->UpdateRelocationSrg(m_shader, m_srgLayout); - diffuseProbeGrid->GetRelocationSrg()->Compile(); - - // relocation stops after a limited number of iterations - diffuseProbeGrid->DecrementRemainingRelocationIterations(); } } @@ -180,19 +198,30 @@ namespace AZ const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetRelocationSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); - uint32_t probeCountX; - uint32_t probeCountY; - diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY); - RHI::DispatchItem dispatchItem; dispatchItem.m_arguments = m_dispatchArgs; dispatchItem.m_pipelineState = m_pipelineState; - dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX; - dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY; + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = diffuseProbeGrid->GetTotalProbeCount(); + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; commandList->Submit(dispatchItem); } } + + void DiffuseProbeGridRelocationPass::FrameEndInternal() + { + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + // submit the DispatchItems for each DiffuseProbeGrid + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) + { + // relocation stops after a limited number of iterations + diffuseProbeGrid->DecrementRemainingRelocationIterations(); + } + + RenderPass::FrameEndInternal(); + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h index a6ede22ee6..121c51050d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h @@ -42,11 +42,12 @@ namespace AZ void LoadShader(); // Pass overrides + bool IsEnabled() const override; void FrameBeginInternal(FramePrepareParams params) override; - void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; + void FrameEndInternal() override; // shader Data::Instance m_shader; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp index f444c0c6ba..db95e17a9e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp @@ -51,18 +51,35 @@ namespace AZ AZ_Assert(m_shaderResourceGroup, "[DiffuseProbeGridRenderPass '%s']: Failed to create SRG", GetPathName().GetCStr()); } + bool DiffuseProbeGridRenderPass::IsEnabled() const + { + if (!RenderPass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty()) + { + // no diffuse probe grids + return false; + } + + return true; + } + void DiffuseProbeGridRenderPass::FrameBeginInternal(FramePrepareParams params) { RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty()) - { - // no diffuse probe grids - return; - } - // get output attachment size AZ_Assert(GetInputOutputCount() > 0, "DiffuseProbeGridRenderPass: Could not find output bindings"); RPI::PassAttachment* m_outputAttachment = GetInputOutputBinding(0).m_attachment.get(); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h index 6f4a91d9c6..c3612649fa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h @@ -36,7 +36,8 @@ namespace AZ explicit DiffuseProbeGridRenderPass(const RPI::PassDescriptor& descriptor); // Pass behavior overrides... - virtual void FrameBeginInternal(FramePrepareParams params) override; + bool IsEnabled() const override; + void FrameBeginInternal(FramePrepareParams params) override; // Scope producer functions... void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp new file mode 100644 index 0000000000..29e50fb158 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + RPI::Ptr DiffuseProbeGridVisualizationAccelerationStructurePass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr diffuseProbeGridVisualizationAccelerationStructurePass = aznew DiffuseProbeGridVisualizationAccelerationStructurePass(descriptor); + return AZStd::move(diffuseProbeGridVisualizationAccelerationStructurePass); + } + + DiffuseProbeGridVisualizationAccelerationStructurePass::DiffuseProbeGridVisualizationAccelerationStructurePass(const RPI::PassDescriptor& descriptor) + : Pass(descriptor) + { + // disable this pass if we're on a platform that doesn't support raytracing + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + if (device->GetFeatures().m_rayTracing == false || !AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED) + { + SetEnabled(false); + } + } + + bool DiffuseProbeGridVisualizationAccelerationStructurePass::ShouldUpdate(const AZStd::shared_ptr& diffuseProbeGrid) const + { + return (diffuseProbeGrid->GetVisualizationEnabled() && diffuseProbeGrid->GetVisualizationTlasUpdateRequired()); + } + + bool DiffuseProbeGridVisualizationAccelerationStructurePass::IsEnabled() const + { + if (!Pass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (diffuseProbeGridFeatureProcessor) + { + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (ShouldUpdate(diffuseProbeGrid)) + { + return true; + } + } + } + + return false; + } + + void DiffuseProbeGridVisualizationAccelerationStructurePass::BuildInternal() + { + SetScopeId(RHI::ScopeId(GetPathName())); + } + + void DiffuseProbeGridVisualizationAccelerationStructurePass::FrameBeginInternal(FramePrepareParams params) + { + params.m_frameGraphBuilder->ImportScopeProducer(*this); + } + + void DiffuseProbeGridVisualizationAccelerationStructurePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) + { + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + // import and attach the visualization TLAS buffers + RHI::Ptr& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas(); + const RHI::Ptr& tlasBuffer = visualizationTlas->GetTlasBuffer(); + const RHI::Ptr& tlasInstancesBuffer = visualizationTlas->GetTlasInstancesBuffer(); + if (tlasBuffer && tlasInstancesBuffer) + { + // TLAS buffer + { + AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId(); + if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasBuffer); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS buffer with error %d", result); + } + + uint32_t byteCount = aznumeric_cast(tlasBuffer->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(byteCount); + + RHI::BufferScopeAttachmentDescriptor desc; + desc.m_attachmentId = attachmentId; + desc.m_bufferViewDescriptor = bufferViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Write); + } + + // TLAS Instances buffer + { + AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasInstancesAttachmentId(); + if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasInstancesBuffer); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS Instances buffer with error %d", result); + } + + uint32_t byteCount = aznumeric_cast(tlasInstancesBuffer->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, byteCount / RayTracingTlasInstanceElementSize, RayTracingTlasInstanceElementSize); + + RHI::BufferScopeAttachmentDescriptor desc; + desc.m_attachmentId = attachmentId; + desc.m_bufferViewDescriptor = bufferViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read); + } + } + } + } + + void DiffuseProbeGridVisualizationAccelerationStructurePass::BuildCommandList(const RHI::FrameGraphExecuteContext& context) + { + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + // build the visualization BLAS from the DiffuseProbeGridFeatureProcessor + // Note: the BLAS is used by all DiffuseProbeGrid visualization TLAS objects + if (m_visualizationBlasBuilt == false) + { + context.GetCommandList()->BuildBottomLevelAccelerationStructure(*diffuseProbeGridFeatureProcessor->GetVisualizationBlas()); + m_visualizationBlasBuilt = true; + } + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + if (!diffuseProbeGrid->GetVisualizationTlas()->GetTlasBuffer()) + { + continue; + } + + // build the TLAS object + context.GetCommandList()->BuildTopLevelAccelerationStructure(*diffuseProbeGrid->GetVisualizationTlas()); + } + } + + void DiffuseProbeGridVisualizationAccelerationStructurePass::FrameEndInternal() + { + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + // TLAS is now updated + diffuseProbeGrid->ResetVisualizationTlasUpdateRequired(); + } + } + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h new file mode 100644 index 0000000000..b353b9a41a --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h @@ -0,0 +1,53 @@ +/* + * 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 builds the DiffuseProbeGrid visualization acceleration structure + class DiffuseProbeGridVisualizationAccelerationStructurePass final + : public RPI::Pass + , public RHI::ScopeProducer + { + public: + AZ_RPI_PASS(DiffuseProbeGridVisualizationAccelerationStructurePass); + + AZ_RTTI(DiffuseProbeGridVisualizationAccelerationStructurePass, "{103D8917-D4DC-4CA3-BFB4-CD62846D282A}", Pass); + AZ_CLASS_ALLOCATOR(DiffuseProbeGridVisualizationAccelerationStructurePass, SystemAllocator, 0); + + //! Creates a DiffuseProbeGridVisualizationAccelerationStructurePass + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + ~DiffuseProbeGridVisualizationAccelerationStructurePass() = default; + + private: + explicit DiffuseProbeGridVisualizationAccelerationStructurePass(const RPI::PassDescriptor& descriptor); + + bool ShouldUpdate(const AZStd::shared_ptr& diffuseProbeGrid) const; + + // Scope producer functions + void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; + void BuildCommandList(const RHI::FrameGraphExecuteContext& context) override; + + // Pass overrides + bool IsEnabled() const override; + void BuildInternal() override; + void FrameBeginInternal(FramePrepareParams params) override; + void FrameEndInternal() override; + + bool m_visualizationBlasBuilt = false; + }; + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.cpp new file mode 100644 index 0000000000..722b42daf7 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + RPI::Ptr DiffuseProbeGridVisualizationCompositePass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew DiffuseProbeGridVisualizationCompositePass(descriptor); + return AZStd::move(pass); + } + + DiffuseProbeGridVisualizationCompositePass::DiffuseProbeGridVisualizationCompositePass(const RPI::PassDescriptor& descriptor) + : RPI::FullscreenTrianglePass(descriptor) + { + if (!AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED) + { + SetEnabled(false); + } + } + + bool DiffuseProbeGridVisualizationCompositePass::IsEnabled() const + { + if (!FullscreenTrianglePass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (diffuseProbeGridFeatureProcessor) + { + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (diffuseProbeGrid->GetVisualizationEnabled()) + { + return true; + } + } + } + + return false; + } + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h new file mode 100644 index 0000000000..af0109039b --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h @@ -0,0 +1,39 @@ +/* + * 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 + +namespace AZ +{ + namespace Render + { + //! This pass composites the DiffuseProbeGrid visualization image onto the main scene + class DiffuseProbeGridVisualizationCompositePass + : public RPI::FullscreenTrianglePass + { + public: + AZ_RPI_PASS(DiffuseProbeGridVisualizationCompositePass); + + AZ_RTTI(Render::DiffuseProbeGridVisualizationCompositePass, "{64BD5779-AB30-41C1-81B7-B93D864355E5}", RPI::FullscreenTrianglePass); + AZ_CLASS_ALLOCATOR(Render::DiffuseProbeGridVisualizationCompositePass, SystemAllocator, 0); + + //! Creates a new pass without a PassTemplate + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + ~DiffuseProbeGridVisualizationCompositePass() = default; + + private: + explicit DiffuseProbeGridVisualizationCompositePass(const RPI::PassDescriptor& descriptor); + + // Pass behavior overrides... + bool IsEnabled() const override; + }; + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.cpp new file mode 100644 index 0000000000..29d7ff4aaa --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + RPI::Ptr DiffuseProbeGridVisualizationPreparePass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr diffuseProbeGridVisualizationPreparePass = aznew DiffuseProbeGridVisualizationPreparePass(descriptor); + return AZStd::move(diffuseProbeGridVisualizationPreparePass); + } + + DiffuseProbeGridVisualizationPreparePass::DiffuseProbeGridVisualizationPreparePass(const RPI::PassDescriptor& descriptor) + : RenderPass(descriptor) + { + // disable this pass if we're on a platform that doesn't support raytracing + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + if (device->GetFeatures().m_rayTracing == false || !AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED) + { + SetEnabled(false); + } + else + { + LoadShader(); + } + } + + void DiffuseProbeGridVisualizationPreparePass::LoadShader() + { + // load shaders + // Note: the shader may not be available on all platforms + AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPrepare.azshader"; + m_shader = RPI::LoadCriticalShader(shaderFilePath); + if (m_shader == nullptr) + { + return; + } + + RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; + const auto& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); + m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); + AZ_Assert(m_pipelineState, "Failed to acquire pipeline state"); + + m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + AZ_Assert(m_srgLayout.get(), "Failed to find Srg layout"); + + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) + { + AZ_Error("PassSystem", false, "[DiffuseProbeGridVisualizationPreparePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + } + } + + bool DiffuseProbeGridVisualizationPreparePass::ShouldUpdate(const AZStd::shared_ptr& diffuseProbeGrid) const + { + return (diffuseProbeGrid->GetVisualizationEnabled() && diffuseProbeGrid->GetVisualizationTlasUpdateRequired()); + } + + bool DiffuseProbeGridVisualizationPreparePass::IsEnabled() const + { + if (!RenderPass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (diffuseProbeGridFeatureProcessor) + { + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (ShouldUpdate(diffuseProbeGrid)) + { + return true; + } + } + } + + return false; + } + + void DiffuseProbeGridVisualizationPreparePass::FrameBeginInternal(FramePrepareParams params) + { + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + // create the TLAS descriptor by adding an instance entry for each probe in the grid + RHI::RayTracingTlasDescriptor tlasDescriptor; + RHI::RayTracingTlasDescriptor* tlasDescriptorBuild = tlasDescriptor.Build(); + + // initialize the transform for each probe to Identity(), they will be updated by the compute shader + AZ::Transform transform = AZ::Transform::Identity(); + + uint32_t probeCount = diffuseProbeGrid->GetTotalProbeCount(); + for (uint32_t index = 0; index < probeCount; ++index) + { + tlasDescriptorBuild->Instance() + ->InstanceID(index) + ->HitGroupIndex(0) + ->Blas(diffuseProbeGridFeatureProcessor->GetVisualizationBlas()) + ->Transform(transform) + ; + } + + // create the TLAS buffers from on the descriptor + RHI::Ptr& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas(); + visualizationTlas->CreateBuffers(*device, &tlasDescriptor, diffuseProbeGridFeatureProcessor->GetVisualizationBufferPools()); + } + + RenderPass::FrameBeginInternal(params); + } + + void DiffuseProbeGridVisualizationPreparePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) + { + RenderPass::SetupFrameGraphDependencies(frameGraph); + + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + // import and attach the visualization TLAS and probe data + RHI::Ptr& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas(); + const RHI::Ptr& tlasBuffer = visualizationTlas->GetTlasBuffer(); + const RHI::Ptr& tlasInstancesBuffer = visualizationTlas->GetTlasInstancesBuffer(); + if (tlasBuffer && tlasInstancesBuffer) + { + // TLAS buffer + { + AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId(); + if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasBuffer); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS buffer with error %d", result); + } + + uint32_t byteCount = aznumeric_cast(tlasBuffer->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(byteCount); + + RHI::BufferScopeAttachmentDescriptor desc; + desc.m_attachmentId = attachmentId; + desc.m_bufferViewDescriptor = bufferViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Write); + } + + // TLAS Instances buffer + { + AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeVisualizationTlasInstancesAttachmentId(); + if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(attachmentId, tlasInstancesBuffer); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid visualization TLAS Instances buffer with error %d", result); + } + + uint32_t byteCount = aznumeric_cast(tlasInstancesBuffer->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, byteCount / RayTracingTlasInstanceElementSize, RayTracingTlasInstanceElementSize); + + RHI::BufferScopeAttachmentDescriptor desc; + desc.m_attachmentId = attachmentId; + desc.m_bufferViewDescriptor = bufferViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::DontCare; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Write); + } + + // probe data + { + AZ::RHI::AttachmentId attachmentId = diffuseProbeGrid->GetProbeDataImageAttachmentId(); + if (frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentId) == false) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(attachmentId, diffuseProbeGrid->GetProbeDataImage()); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import DiffuseProbeGrid probe data buffer with error %d", result); + } + + RHI::ImageScopeAttachmentDescriptor desc; + desc.m_attachmentId = attachmentId; + desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDataImageViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read); + } + } + } + } + + void DiffuseProbeGridVisualizationPreparePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context) + { + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + // the DiffuseProbeGrid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs + // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) + diffuseProbeGrid->UpdateVisualizationPrepareSrg(m_shader, m_srgLayout); + diffuseProbeGrid->GetVisualizationPrepareSrg()->Compile(); + } + } + + void DiffuseProbeGridVisualizationPreparePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) + { + RHI::CommandList* commandList = context.GetCommandList(); + + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!ShouldUpdate(diffuseProbeGrid)) + { + continue; + } + + const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetVisualizationPrepareSrg()->GetRHIShaderResourceGroup(); + commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); + + RHI::DispatchItem dispatchItem; + dispatchItem.m_arguments = m_dispatchArgs; + dispatchItem.m_pipelineState = m_pipelineState; + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = diffuseProbeGrid->GetTotalProbeCount(); + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1; + dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; + + commandList->Submit(dispatchItem); + } + } + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h new file mode 100644 index 0000000000..5e86a606aa --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h @@ -0,0 +1,52 @@ +/* + * 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 + +namespace AZ +{ + namespace Render + { + //! This pass updates the DiffuseProbeGrid visualization TLAS instances buffer + class DiffuseProbeGridVisualizationPreparePass final + : public RPI::RenderPass + { + public: + AZ_RPI_PASS(DiffuseProbeGridVisualizationPreparePass); + + AZ_RTTI(DiffuseProbeGridVisualizationPreparePass, "{33BD769D-378B-4142-8C11-6A2ADA2BB095}", Pass); + AZ_CLASS_ALLOCATOR(DiffuseProbeGridVisualizationPreparePass, SystemAllocator, 0); + + //! Creates a DiffuseProbeGridVisualizationPreparePass + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + ~DiffuseProbeGridVisualizationPreparePass() = default; + + private: + explicit DiffuseProbeGridVisualizationPreparePass(const RPI::PassDescriptor& descriptor); + + void LoadShader(); + bool ShouldUpdate(const AZStd::shared_ptr& diffuseProbeGrid) const; + + // Pass overrides + bool IsEnabled() const override; + void FrameBeginInternal(FramePrepareParams params) override; + void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; + void CompileResources(const RHI::FrameGraphCompileContext& context) override; + void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; + + // shader + Data::Instance m_shader; + const RHI::PipelineState* m_pipelineState = nullptr; + RHI::Ptr m_srgLayout; + RHI::DispatchDirect m_dispatchArgs; + }; + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.cpp new file mode 100644 index 0000000000..69c033f76c --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + RPI::Ptr DiffuseProbeGridVisualizationRayTracingPass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew DiffuseProbeGridVisualizationRayTracingPass(descriptor); + return AZStd::move(pass); + } + + DiffuseProbeGridVisualizationRayTracingPass::DiffuseProbeGridVisualizationRayTracingPass(const RPI::PassDescriptor& descriptor) + : RPI::RenderPass(descriptor) + { + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + if (device->GetFeatures().m_rayTracing == false || !AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED) + { + // raytracing or GI is not supported on this platform + SetEnabled(false); + } + } + + void DiffuseProbeGridVisualizationRayTracingPass::CreateRayTracingPipelineState() + { + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + + // load the ray tracing shader + // Note: the shader may not be available on all platforms + AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracing.azshader"; + m_rayTracingShader = RPI::LoadCriticalShader(shaderFilePath); + if (m_rayTracingShader == nullptr) + { + return; + } + + auto shaderVariant = m_rayTracingShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + RHI::PipelineStateDescriptorForRayTracing rayGenerationShaderDescriptor; + shaderVariant.ConfigurePipelineState(rayGenerationShaderDescriptor); + + // closest hit shader + AZStd::string closestHitShaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingClosestHit.azshader"; + m_closestHitShader = RPI::LoadCriticalShader(closestHitShaderFilePath); + + auto closestHitShaderVariant = m_closestHitShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + RHI::PipelineStateDescriptorForRayTracing closestHitShaderDescriptor; + closestHitShaderVariant.ConfigurePipelineState(closestHitShaderDescriptor); + + // miss shader + AZStd::string missShaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingMiss.azshader"; + m_missShader = RPI::LoadCriticalShader(missShaderFilePath); + + auto missShaderVariant = m_missShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + RHI::PipelineStateDescriptorForRayTracing missShaderDescriptor; + missShaderVariant.ConfigurePipelineState(missShaderDescriptor); + + // global pipeline state and Srg + m_globalPipelineState = m_rayTracingShader->AcquirePipelineState(rayGenerationShaderDescriptor); + AZ_Assert(m_globalPipelineState, "Failed to acquire ray tracing global pipeline state"); + + m_globalSrgLayout = m_rayTracingShader->FindShaderResourceGroupLayout(Name{ "RayTracingGlobalSrg" }); + AZ_Assert(m_globalSrgLayout != nullptr, "Failed to find RayTracingGlobalSrg layout for shader [%s]", shaderFilePath.c_str()); + + // build the ray tracing pipeline state descriptor + RHI::RayTracingPipelineStateDescriptor descriptor; + descriptor.Build() + ->PipelineState(m_globalPipelineState.get()) + ->MaxPayloadSize(64) + ->MaxAttributeSize(32) + ->MaxRecursionDepth(2) + ->ShaderLibrary(rayGenerationShaderDescriptor) + ->RayGenerationShaderName(AZ::Name("RayGen")) + ->ShaderLibrary(missShaderDescriptor) + ->MissShaderName(AZ::Name("Miss")) + ->ShaderLibrary(closestHitShaderDescriptor) + ->ClosestHitShaderName(AZ::Name("ClosestHit")) + ->HitGroup(AZ::Name("HitGroup")) + ->ClosestHitShaderName(AZ::Name("ClosestHit")); + + // create the ray tracing pipeline state object + m_rayTracingPipelineState = RHI::Factory::Get().CreateRayTracingPipelineState(); + m_rayTracingPipelineState->Init(*device.get(), &descriptor); + } + + bool DiffuseProbeGridVisualizationRayTracingPass::IsEnabled() const + { + if (!RenderPass::IsEnabled()) + { + return false; + } + + RPI::Scene* scene = m_pipeline->GetScene(); + if (!scene) + { + return false; + } + + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + if (diffuseProbeGridFeatureProcessor) + { + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (diffuseProbeGrid->GetVisualizationEnabled()) + { + return true; + } + } + } + + return false; + } + + void DiffuseProbeGridVisualizationRayTracingPass::FrameBeginInternal(FramePrepareParams params) + { + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + if (!m_initialized) + { + CreateRayTracingPipelineState(); + m_initialized = true; + } + + if (!m_rayTracingShaderTable) + { + RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); + RHI::RayTracingBufferPools& rayTracingBufferPools = diffuseProbeGridFeatureProcessor->GetVisualizationBufferPools(); + + m_rayTracingShaderTable = RHI::Factory::Get().CreateRayTracingShaderTable(); + m_rayTracingShaderTable->Init(*device.get(), rayTracingBufferPools); + + AZStd::shared_ptr descriptor = AZStd::make_shared(); + + // build the ray tracing shader table descriptor + descriptor->Build(AZ::Name("RayTracingShaderTable"), m_rayTracingPipelineState) + ->RayGenerationRecord(AZ::Name("RayGen")) + ->MissRecord(AZ::Name("Miss")) + ->HitGroupRecord(AZ::Name("HitGroup")) + ; + + m_rayTracingShaderTable->Build(descriptor); + } + + RenderPass::FrameBeginInternal(params); + } + + void DiffuseProbeGridVisualizationRayTracingPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) + { + RenderPass::SetupFrameGraphDependencies(frameGraph); + + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!diffuseProbeGrid->GetVisualizationEnabled()) + { + continue; + } + + // TLAS + { + AZ::RHI::AttachmentId tlasAttachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId(); + const RHI::Ptr& visualizationTlasBuffer = diffuseProbeGrid->GetVisualizationTlas()->GetTlasBuffer(); + if (visualizationTlasBuffer) + { + if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(tlasAttachmentId)) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(tlasAttachmentId, visualizationTlasBuffer); + AZ_Assert(result == RHI::ResultCode::Success, "Failed to import ray tracing TLAS buffer with error %d", result); + } + + uint32_t tlasBufferByteCount = aznumeric_cast(visualizationTlasBuffer->GetDescriptor().m_byteCount); + RHI::BufferViewDescriptor tlasBufferViewDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, tlasBufferByteCount); + + RHI::BufferScopeAttachmentDescriptor desc; + desc.m_attachmentId = tlasAttachmentId; + desc.m_bufferViewDescriptor = tlasBufferViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite); + } + } + + // probe irradiance + { + RHI::ImageScopeAttachmentDescriptor desc; + desc.m_attachmentId = diffuseProbeGrid->GetIrradianceImageAttachmentId(); + desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeIrradianceImageViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read); + } + + // probe distance + { + RHI::ImageScopeAttachmentDescriptor desc; + desc.m_attachmentId = diffuseProbeGrid->GetDistanceImageAttachmentId(); + desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDistanceImageViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read); + } + + // probe data + { + RHI::ImageScopeAttachmentDescriptor desc; + desc.m_attachmentId = diffuseProbeGrid->GetProbeDataImageAttachmentId(); + desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDataImageViewDescriptor; + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::Read); + } + } + + // retrieve the visualization image size, this will determine the number of rays to cast + RPI::Ptr visualizationImageAttachment = m_ownedAttachments[0]; + AZ_Assert(visualizationImageAttachment.get(), "Invalid DiffuseProbeGrid Visualization image"); + + m_outputAttachmentSize = visualizationImageAttachment->GetTransientImageDescriptor().m_imageDescriptor.m_size; + } + + void DiffuseProbeGridVisualizationRayTracingPass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context) + { + const RHI::ImageView* outputImageView = context.GetImageView(GetOutputBinding(0).m_attachment->GetAttachmentId()); + AZ_Assert(outputImageView, "Failed to retrieve output ImageView"); + + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!diffuseProbeGrid->GetVisualizationEnabled()) + { + continue; + } + + // the DiffuseProbeGridVisualization Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader + // inputs (see line ValidateSetImageView() in ShaderResourceGroupData.cpp) + diffuseProbeGrid->UpdateVisualizationRayTraceSrg(m_rayTracingShader, m_globalSrgLayout, outputImageView); + diffuseProbeGrid->GetVisualizationRayTraceSrg()->Compile(); + } + } + + void DiffuseProbeGridVisualizationRayTracingPass::BuildCommandListInternal([[maybe_unused]] const RHI::FrameGraphExecuteContext& context) + { + RPI::Scene* scene = m_pipeline->GetScene(); + DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); + + const AZStd::vector& views = m_pipeline->GetViews(RPI::PipelineViewTag{ "MainCamera" }); + if (views.empty()) + { + return; + } + + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) + { + if (!diffuseProbeGrid->GetVisualizationEnabled()) + { + continue; + } + + const RHI::ShaderResourceGroup* shaderResourceGroups[] = { + diffuseProbeGrid->GetVisualizationRayTraceSrg()->GetRHIShaderResourceGroup(), + views[0]->GetRHIShaderResourceGroup() + }; + + RHI::DispatchRaysItem dispatchRaysItem; + dispatchRaysItem.m_width = m_outputAttachmentSize.m_width; + dispatchRaysItem.m_height = m_outputAttachmentSize.m_height; + dispatchRaysItem.m_depth = 1; + dispatchRaysItem.m_rayTracingPipelineState = m_rayTracingPipelineState.get(); + dispatchRaysItem.m_rayTracingShaderTable = m_rayTracingShaderTable.get(); + dispatchRaysItem.m_shaderResourceGroupCount = RHI::ArraySize(shaderResourceGroups); + dispatchRaysItem.m_shaderResourceGroups = shaderResourceGroups; + dispatchRaysItem.m_globalPipelineState = m_globalPipelineState.get(); + + // submit the DispatchRays item + context.GetCommandList()->Submit(dispatchRaysItem); + } + } + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h new file mode 100644 index 0000000000..c2e5ecf3de --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h @@ -0,0 +1,67 @@ +/* + * 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 + { + //! Ray tracing shader that generates the probe visualization image for a DiffuseProbeGrid + class DiffuseProbeGridVisualizationRayTracingPass final + : public RPI::RenderPass + { + public: + AZ_RPI_PASS(DiffuseProbeGridVisualizationRayTracingPass); + + AZ_RTTI(DiffuseProbeGridVisualizationRayTracingPass, "{CDFB5C03-08D1-4FCA-8B63-2F8326E0DF1D}", RPI::RenderPass); + AZ_CLASS_ALLOCATOR(DiffuseProbeGridVisualizationRayTracingPass, SystemAllocator, 0); + + //! Creates a DiffuseProbeGridVisualizationRayTracingPass + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + ~DiffuseProbeGridVisualizationRayTracingPass() = default; + + private: + explicit DiffuseProbeGridVisualizationRayTracingPass(const RPI::PassDescriptor& descriptor); + + void CreateRayTracingPipelineState(); + + // Scope producer functions + void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; + void CompileResources(const RHI::FrameGraphCompileContext& context) override; + void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; + + // Pass overrides + bool IsEnabled() const override; + void FrameBeginInternal(FramePrepareParams params) override; + + // ray tracing shader and pipeline state + Data::Instance m_rayTracingShader; + Data::Instance m_missShader; + Data::Instance m_closestHitShader; + RHI::Ptr m_rayTracingPipelineState; + + // ray tracing shader table + RHI::Ptr m_rayTracingShaderTable; + + // current size of output attachment, updated every frame + RHI::Size m_outputAttachmentSize; + + // ray tracing global shader resource group layout and pipeline state + RHI::Ptr m_globalSrgLayout; + RHI::ConstPtr m_globalPipelineState; + + bool m_initialized = false; + }; + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h index d098fca35a..dce340807d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h @@ -24,6 +24,8 @@ namespace AZ static const uint32_t RayTracingSceneSrgBindingSlot = 1; static const uint32_t RayTracingMaterialSrgBindingSlot = 2; + static const uint32_t RayTracingTlasInstanceElementSize = 64; + enum class RayTracingSubMeshBufferFlags : uint32_t { None = 0, 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 1ec6402b3e..6ba0ed1165 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -140,6 +140,14 @@ set(FILES Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.cpp Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp Source/DisplayMapper/AcesOutputTransformPass.cpp diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingAccelerationStructure.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingAccelerationStructure.h index cd58ee359f..ce12d12162 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingAccelerationStructure.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingAccelerationStructure.h @@ -182,6 +182,7 @@ namespace AZ //! Returns the TLAS RHI buffer virtual const RHI::Ptr GetTlasBuffer() const = 0; + virtual const RHI::Ptr GetTlasInstancesBuffer() const = 0; private: // Platform API diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingBufferPools.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingBufferPools.h index 288a83b4da..6b3e2a4abd 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingBufferPools.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RayTracingBufferPools.h @@ -46,7 +46,7 @@ namespace AZ virtual RHI::BufferBindFlags GetShaderTableBufferBindFlags() const { return RHI::BufferBindFlags::ShaderRead | RHI::BufferBindFlags::CopyRead | RHI::BufferBindFlags::RayTracingShaderTable; } virtual RHI::BufferBindFlags GetScratchBufferBindFlags() const { return RHI::BufferBindFlags::ShaderReadWrite | RHI::BufferBindFlags::RayTracingScratchBuffer; } virtual RHI::BufferBindFlags GetBlasBufferBindFlags() const { return RHI::BufferBindFlags::ShaderReadWrite | RHI::BufferBindFlags::RayTracingAccelerationStructure; } - virtual RHI::BufferBindFlags GetTlasInstancesBufferBindFlags() const { return RHI::BufferBindFlags::ShaderRead; } + virtual RHI::BufferBindFlags GetTlasInstancesBufferBindFlags() const { return RHI::BufferBindFlags::ShaderReadWrite; } virtual RHI::BufferBindFlags GetTlasBufferBindFlags() const { return RHI::BufferBindFlags::RayTracingAccelerationStructure; } private: diff --git a/Gems/Atom/RHI/Code/Source/RHI/RayTracingBufferPools.cpp b/Gems/Atom/RHI/Code/Source/RHI/RayTracingBufferPools.cpp index 3ef2ba05ac..7899d9b5d0 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RayTracingBufferPools.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RayTracingBufferPools.cpp @@ -97,7 +97,7 @@ namespace AZ // create TLAS Instances buffer pool { RHI::BufferPoolDescriptor bufferPoolDesc; - bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Host; + bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device; bufferPoolDesc.m_bindFlags = GetTlasInstancesBufferBindFlags(); m_tlasInstancesBufferPool = RHI::Factory::Get().CreateBufferPool(); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.cpp index c28c5e4db5..a91f995671 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.cpp @@ -54,7 +54,7 @@ namespace AZ // create instances buffer buffers.m_tlasInstancesBuffer = RHI::Factory::Get().CreateBuffer(); AZ::RHI::BufferDescriptor tlasInstancesBufferDescriptor; - tlasInstancesBufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderRead; + tlasInstancesBufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderReadWrite; tlasInstancesBufferDescriptor.m_byteCount = instanceDescsSizeInBytes; tlasInstancesBufferDescriptor.m_alignment = D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.h index accc43ec92..41aad8cf87 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/RayTracingTlas.h @@ -40,7 +40,8 @@ namespace AZ const TlasBuffers& GetBuffers() const { return m_buffers[m_currentBufferIndex]; } // RHI::RayTracingTlas overrides... - virtual const RHI::Ptr GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; } + const RHI::Ptr GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; } + const RHI::Ptr GetTlasInstancesBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasInstancesBuffer; } private: RayTracingTlas() = default; diff --git a/Gems/Atom/RHI/Null/Code/Source/RHI/RayTracingTlas.h b/Gems/Atom/RHI/Null/Code/Source/RHI/RayTracingTlas.h index 7bb0316230..a3e5d8c558 100644 --- a/Gems/Atom/RHI/Null/Code/Source/RHI/RayTracingTlas.h +++ b/Gems/Atom/RHI/Null/Code/Source/RHI/RayTracingTlas.h @@ -26,7 +26,8 @@ namespace AZ static RHI::Ptr Create(); // RHI::RayTracingTlas overrides... - virtual const RHI::Ptr GetTlasBuffer() const override { return nullptr; } + const RHI::Ptr GetTlasBuffer() const override { return nullptr; } + const RHI::Ptr GetTlasInstancesBuffer() const override { return nullptr; } private: RayTracingTlas() = default; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp index c1d87b0211..6211adf35c 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp @@ -970,6 +970,26 @@ namespace AZ const VkAccelerationStructureBuildRangeInfoKHR& offsetInfo = tlasBuffers.m_offsetInfo; const VkAccelerationStructureBuildRangeInfoKHR* pOffsetInfo = &offsetInfo; vkCmdBuildAccelerationStructuresKHR(GetNativeCommandBuffer(), 1, &tlasBuffers.m_buildInfo, &pOffsetInfo); + + // we need a pipeline barrier on VK_ACCESS_ACCELERATION_STRUCTURE (both read and write) in case we are building + // multiple TLAS objects in a command list + VkMemoryBarrier memoryBarrier = {}; + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memoryBarrier.pNext = nullptr; + memoryBarrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; + memoryBarrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; + + vkCmdPipelineBarrier( + GetNativeCommandBuffer(), + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + 0, + 1, + &memoryBarrier, + 0, + nullptr, + 0, + nullptr); } void CommandList::ClearImage(const ResourceClearRequest& request) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBufferPools.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBufferPools.h index a7547c7106..0ae3b37c50 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBufferPools.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBufferPools.h @@ -24,8 +24,8 @@ namespace AZ static RHI::Ptr Create() { return aznew RayTracingBufferPools; } protected: - virtual RHI::BufferBindFlags GetShaderTableBufferBindFlags() const override { return RHI::BufferBindFlags::CopyRead | RHI::BufferBindFlags::RayTracingShaderTable; } - virtual RHI::BufferBindFlags GetTlasInstancesBufferBindFlags() const override { return RHI::BufferBindFlags::ShaderRead | RHI::BufferBindFlags::RayTracingAccelerationStructure; } + RHI::BufferBindFlags GetShaderTableBufferBindFlags() const override { return RHI::BufferBindFlags::CopyRead | RHI::BufferBindFlags::RayTracingShaderTable; } + RHI::BufferBindFlags GetTlasInstancesBufferBindFlags() const override { return RHI::BufferBindFlags::ShaderReadWrite | RHI::BufferBindFlags::RayTracingAccelerationStructure; } private: RayTracingBufferPools() = default; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp index 08b933c96b..b081e3f82d 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp @@ -60,7 +60,7 @@ namespace AZ // create instances buffer buffers.m_tlasInstancesBuffer = RHI::Factory::Get().CreateBuffer(); AZ::RHI::BufferDescriptor tlasInstancesBufferDescriptor; - tlasInstancesBufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderRead | RHI::BufferBindFlags::RayTracingAccelerationStructure; + tlasInstancesBufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderReadWrite | RHI::BufferBindFlags::RayTracingAccelerationStructure; tlasInstancesBufferDescriptor.m_byteCount = instanceDescsSizeInBytes; AZ::RHI::BufferInitRequest tlasInstancesBufferRequest; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.h index 96d5f8f5f6..55fcf481af 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.h @@ -43,7 +43,8 @@ namespace AZ const TlasBuffers& GetBuffers() const { return m_buffers[m_currentBufferIndex]; } // RHI::RayTracingTlas overrides... - virtual const RHI::Ptr GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; } + const RHI::Ptr GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; } + const RHI::Ptr GetTlasInstancesBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasInstancesBuffer; } private: RayTracingTlas() = default; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h index 91c4e2bcf4..32d77c1c3a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h @@ -20,5 +20,6 @@ namespace AZ static constexpr float DefaultDiffuseProbeGridViewBias = 0.2f; static constexpr float DefaultDiffuseProbeGridNormalBias = 0.1f; static constexpr DiffuseProbeGridNumRaysPerProbe DefaultDiffuseProbeGridNumRaysPerProbe = DiffuseProbeGridNumRaysPerProbe::NumRaysPerProbe_288; + static constexpr float DefaultVisualizationSphereRadius = 0.5f; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp index 8c8b29a053..9aa58c1082 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp @@ -34,7 +34,7 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(2) // Added NumRaysPerProbe setting + ->Version(3) // Added probe visualization ->Field("ProbeSpacing", &DiffuseProbeGridComponentConfig::m_probeSpacing) ->Field("Extents", &DiffuseProbeGridComponentConfig::m_extents) ->Field("AmbientMultiplier", &DiffuseProbeGridComponentConfig::m_ambientMultiplier) @@ -49,6 +49,9 @@ namespace AZ ->Field("BakedIrradianceTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedIrradianceTextureAsset) ->Field("BakedDistanceTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedDistanceTextureAsset) ->Field("BakedProbeDataTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedProbeDataTextureAsset) + ->Field("VisualizationEnabled", &DiffuseProbeGridComponentConfig::m_visualizationEnabled) + ->Field("VisualizationShowInactiveProbes", &DiffuseProbeGridComponentConfig::m_visualizationShowInactiveProbes) + ->Field("VisualizationSphereRadius", &DiffuseProbeGridComponentConfig::m_visualizationSphereRadius) ; } } @@ -140,6 +143,9 @@ namespace AZ m_featureProcessor->SetViewBias(m_handle, m_configuration.m_viewBias); m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias); m_featureProcessor->SetNumRaysPerProbe(m_handle, m_configuration.m_numRaysPerProbe); + m_featureProcessor->SetVisualizationEnabled(m_handle, m_configuration.m_visualizationEnabled); + m_featureProcessor->SetVisualizationShowInactiveProbes(m_handle, m_configuration.m_visualizationShowInactiveProbes); + m_featureProcessor->SetVisualizationSphereRadius(m_handle, m_configuration.m_visualizationSphereRadius); // load the baked texture assets, but only if they are all valid if (m_configuration.m_bakedIrradianceTextureAsset.GetId().IsValid() && @@ -356,6 +362,39 @@ namespace AZ m_configuration.m_runtimeMode = runtimeMode; } + void DiffuseProbeGridComponentController::SetVisualizationEnabled(bool visualizationEnabled) + { + if (!m_featureProcessor) + { + return; + } + + m_configuration.m_visualizationEnabled = visualizationEnabled; + m_featureProcessor->SetVisualizationEnabled(m_handle, m_configuration.m_visualizationEnabled); + } + + void DiffuseProbeGridComponentController::SetVisualizationShowInactiveProbes(bool visualizationShowInactiveProbes) + { + if (!m_featureProcessor) + { + return; + } + + m_configuration.m_visualizationShowInactiveProbes = visualizationShowInactiveProbes; + m_featureProcessor->SetVisualizationShowInactiveProbes(m_handle, m_configuration.m_visualizationShowInactiveProbes); + } + + void DiffuseProbeGridComponentController::SetVisualizationSphereRadius(float visualizationSphereRadius) + { + if (!m_featureProcessor) + { + return; + } + + m_configuration.m_visualizationSphereRadius = visualizationSphereRadius; + m_featureProcessor->SetVisualizationSphereRadius(m_handle, m_configuration.m_visualizationSphereRadius); + } + void DiffuseProbeGridComponentController::BakeTextures(DiffuseProbeGridBakeTexturesCallback callback) { if (!m_featureProcessor) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h index 8f84954b2c..44cab5fc32 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h @@ -48,6 +48,10 @@ namespace AZ Data::Asset m_bakedDistanceTextureAsset; Data::Asset m_bakedProbeDataTextureAsset; + bool m_visualizationEnabled = false; + bool m_visualizationShowInactiveProbes = false; + float m_visualizationSphereRadius = DefaultVisualizationSphereRadius; + AZ::u64 m_entityId{ EntityId::InvalidEntityId }; }; @@ -102,6 +106,9 @@ namespace AZ void SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe); void SetEditorMode(DiffuseProbeGridMode editorMode); void SetRuntimeMode(DiffuseProbeGridMode runtimeMode); + void SetVisualizationEnabled(bool visualizationEnabled); + void SetVisualizationShowInactiveProbes(bool visualizationShowInactiveProbes); + void SetVisualizationSphereRadius(float visualizationSphereRadius); // Bake the diffuse probe grid textures to assets void BakeTextures(DiffuseProbeGridBakeTexturesCallback callback); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 6588b18636..dd4ffd25e6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -43,6 +43,9 @@ namespace AZ ->Field("numRaysPerProbe", &EditorDiffuseProbeGridComponent::m_numRaysPerProbe) ->Field("editorMode", &EditorDiffuseProbeGridComponent::m_editorMode) ->Field("runtimeMode", &EditorDiffuseProbeGridComponent::m_runtimeMode) + ->Field("showVisualization", &EditorDiffuseProbeGridComponent::m_showVisualization) + ->Field("showInactiveProbes", &EditorDiffuseProbeGridComponent::m_showInactiveProbes) + ->Field("visualizationSphereRadius", &EditorDiffuseProbeGridComponent::m_visualizationSphereRadius) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -94,10 +97,22 @@ namespace AZ ->Attribute(Edit::Attributes::Step, 0.1f) ->Attribute(Edit::Attributes::Min, 0.0f) ->Attribute(Edit::Attributes::Max, 1.0f) - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_numRaysPerProbe, "Number of Rays Per Probe", "Number of rays cast by each probe to detect lighting in its surroundings") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_numRaysPerProbe, "Number of Rays Per Probe", "Number of rays cast by each probe to detect lighting in its surroundings") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnNumRaysPerProbeChanged) ->Attribute(AZ::Edit::Attributes::EnumValues, &EditorDiffuseProbeGridComponent::GetNumRaysPerProbeEnumList) - ->ClassElement(AZ::Edit::ClassElements::EditorData, "Grid mode") + ->ClassElement(AZ::Edit::ClassElements::Group, "Visualization") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &EditorDiffuseProbeGridComponent::m_showVisualization, "Show Visualization", "Show the probe grid visualization") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnShowVisualizationChanged) + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &EditorDiffuseProbeGridComponent::m_showInactiveProbes, "Show Inactive Probes", "Show inactive probes in the probe grid visualization") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnShowInactiveProbesChanged) + ->DataElement(AZ::Edit::UIHandlers::Slider, &EditorDiffuseProbeGridComponent::m_visualizationSphereRadius, "Visualization Sphere Radius", "Radius of the spheres in the probe grid visualization") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnVisualizationSphereRadiusChanged) + ->Attribute(Edit::Attributes::Decimals, 2) + ->Attribute(Edit::Attributes::Step, 0.25f) + ->Attribute(Edit::Attributes::Min, 0.25f) + ->Attribute(Edit::Attributes::Max, 2.0f) + ->ClassElement(AZ::Edit::ClassElements::Group, "Grid mode") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_editorMode, "Editor Mode", "Controls whether the editor uses RealTime or Baked diffuse GI. RealTime requires a ray-tracing capable GPU. Auto-Select will fallback to Baked if ray-tracing is not available") ->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorDiffuseProbeGridComponent::OnModeChangeValidate) @@ -350,6 +365,24 @@ namespace AZ return AZ::Edit::PropertyRefreshLevels::None; } + AZ::u32 EditorDiffuseProbeGridComponent::OnShowVisualizationChanged() + { + m_controller.SetVisualizationEnabled(m_showVisualization); + return AZ::Edit::PropertyRefreshLevels::None; + } + + AZ::u32 EditorDiffuseProbeGridComponent::OnShowInactiveProbesChanged() + { + m_controller.SetVisualizationShowInactiveProbes(m_showInactiveProbes); + return AZ::Edit::PropertyRefreshLevels::None; + } + + AZ::u32 EditorDiffuseProbeGridComponent::OnVisualizationSphereRadiusChanged() + { + m_controller.SetVisualizationSphereRadius(m_visualizationSphereRadius); + return AZ::Edit::PropertyRefreshLevels::None; + } + AZ::Outcome EditorDiffuseProbeGridComponent::OnModeChangeValidate([[maybe_unused]] void* newValue, [[maybe_unused]] const AZ::Uuid& valueType) { DiffuseProbeGridMode newMode = (*(reinterpret_cast(newValue))); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h index c7832902a8..2b3d4dfe0e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h @@ -69,6 +69,9 @@ namespace AZ AZ::u32 OnNumRaysPerProbeChanged(); AZ::u32 OnEditorModeChanged(); AZ::u32 OnRuntimeModeChanged(); + AZ::u32 OnShowVisualizationChanged(); + AZ::u32 OnShowInactiveProbesChanged(); + AZ::u32 OnVisualizationSphereRadiusChanged(); AZ::Outcome OnModeChangeValidate(void* newValue, const AZ::Uuid& valueType); // Button handler @@ -85,6 +88,9 @@ namespace AZ DiffuseProbeGridNumRaysPerProbe m_numRaysPerProbe = DefaultDiffuseProbeGridNumRaysPerProbe; DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime; DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime; + bool m_showVisualization = false; + bool m_showInactiveProbes = false; + float m_visualizationSphereRadius = DefaultVisualizationSphereRadius; // flags bool m_editorModeSet = false;