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>
monroegm-disable-blank-issue-2
dmcdiarmid-ly 4 years ago
parent 117cb11505
commit 5f7a30f8da

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18a2bfdeeabfbbf6397daab7c89f9f7321e4863b54a4669fa87e457cb113322c
size 78256

@ -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"
}
]
}

@ -0,0 +1,13 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData":
{
"PassTemplate":
{
"Name": "DiffuseProbeGridVisualizationAccelerationStructurePassTemplate",
"PassClass": "DiffuseProbeGridVisualizationAccelerationStructurePass"
}
}
}

@ -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"
}
}
}
}

@ -0,0 +1,13 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData":
{
"PassTemplate":
{
"Name": "DiffuseProbeGridVisualizationPreparePassTemplate",
"PassClass": "DiffuseProbeGridVisualizationPreparePass"
}
}
}

@ -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"
}
}
]
}
}
}

@ -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"
}
},
{

@ -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": [

@ -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"

@ -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 <scenesrg.srgi>
#include <viewsrg.srgi>
#include <Atom/Features/PostProcessing/FullscreenVertexUtil.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertexInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
#include <Atom/RPI/Math.azsli>
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<float4> m_visualization;
Texture2D<float> m_depth;
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
}
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
// 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;
}

@ -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": ""
}
]
}

@ -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"
}
]
}
]
}
}

@ -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"
}
]
}
]
}
}

@ -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"
}
]
}
]
}
}

@ -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"
}
]
}
]
}
}

@ -125,6 +125,9 @@ namespace AZ
virtual void SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl) = 0;
virtual void SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode) = 0;
virtual void SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures) = 0;
virtual void SetVisualizationEnabled(const DiffuseProbeGridHandle& probeGrid, bool visualizationEnabled) = 0;
virtual void SetVisualizationShowInactiveProbes(const DiffuseProbeGridHandle& probeGrid, bool visualizationShowInactiveProbes) = 0;
virtual void SetVisualizationSphereRadius(const DiffuseProbeGridHandle& probeGrid, float visualizationSphereRadius) = 0;
virtual void BakeTextures(
const DiffuseProbeGridHandle& probeGrid,

@ -94,6 +94,10 @@
#include <DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridDownsamplePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceTracePass.h>
@ -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);

@ -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<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& 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<uint32_t>(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<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& 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<uint32_t>(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)

@ -8,6 +8,7 @@
#pragma once
#include <Atom/RHI/DrawPacketBuilder.h>
#include <Atom/RHI/RayTracingAccelerationStructure.h>
#include <Atom/RPI.Public/Culling.h>
#include <Atom/RPI.Public/PipelineState.h>
#include <Atom/RPI.Public/Scene.h>
@ -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<uint32_t>(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<RPI::ShaderResourceGroup>& GetRelocationSrg() const { return m_relocationSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetClassificationSrg() const { return m_classificationSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetRenderObjectSrg() const { return m_renderObjectSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetVisualizationPrepareSrg() const { return m_visualizationPrepareSrg; }
const Data::Instance<RPI::ShaderResourceGroup>& GetVisualizationRayTraceSrg() const { return m_visualizationRayTraceSrg; }
// Srg updates
void UpdateRayTraceSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
@ -135,6 +147,8 @@ namespace AZ
void UpdateRelocationSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
void UpdateClassificationSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
void UpdateRenderObjectSrg();
void UpdateVisualizationPrepareSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout);
void UpdateVisualizationRayTraceSrg(const Data::Instance<RPI::Shader>& shader, const RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout, const RHI::ImageView* outputImageView);
// textures
const RHI::Ptr<RHI::Image> 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<RHI::RayTracingTlas>& GetVisualizationTlas() const { return m_visualizationTlas; }
RHI::Ptr<RHI::RayTracingTlas>& 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<RHI::Image> m_probeDataImage[ImageFrameCount];
uint32_t m_currentImageIndex = 0;
bool m_updateTextures = false;
bool m_irradianceClearRequired = true;
bool m_textureClearRequired = true;
// baked textures
Data::Instance<RPI::Image> 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<RHI::RayTracingTlas> m_visualizationTlas;
bool m_visualizationTlasUpdateRequired = false;
RHI::AttachmentId m_visualizationTlasAttachmentId;
RHI::AttachmentId m_visualizationTlasInstancesAttachmentId;
Data::Instance<RPI::ShaderResourceGroup> m_visualizationPrepareSrg;
Data::Instance<RPI::ShaderResourceGroup> m_visualizationRayTraceSrg;
};
} // namespace Render
} // namespace AZ

@ -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<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBlendDistancePass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridBlendDistancePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)

@ -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;

@ -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<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBlendIrradiancePass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridBlendIrradiancePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)

@ -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;

@ -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<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridBorderUpdatePass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return false;
}
RenderPass::FrameBeginInternal(params);
return true;
}
void DiffuseProbeGridBorderUpdatePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)

@ -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;

@ -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<DiffuseProbeGridFeatureProcessor>();
if (!RenderPass::IsEnabled())
{
return false;
}
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
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<DiffuseProbeGridFeatureProcessor>();
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);

@ -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;

@ -7,6 +7,7 @@
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@ -39,6 +40,7 @@ namespace AZ
void DiffuseProbeGridFeatureProcessor::Activate()
{
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
RHI::Ptr<RHI::Device> 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<AZ::RPI::ModelAsset>(
"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<DiffuseProbeGrid> 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<DiffuseProbeGrid> 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<Data::AssetData> asset)
{
Data::Asset<RPI::ModelAsset> modelAsset = asset;
m_visualizationModel = RPI::Model::FindOrCreate(modelAsset);
AZ_Assert(m_visualizationModel.get(), "Failed to load DiffuseProbeGrid visualization model");
const AZStd::span<const Data::Instance<RPI::ModelLod>>& modelLods = m_visualizationModel->GetLods();
AZ_Assert(!modelLods.empty(), "Invalid DiffuseProbeGrid visualization model");
if (modelLods.empty())
{
return;
}
const Data::Instance<RPI::ModelLod>& 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<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
m_visualizationBlas = AZ::RHI::RayTracingBlas::CreateRHIRayTracingBlas();
m_visualizationBlas->CreateBuffers(*device, &blasDescriptor, *m_visualizationBufferPools);
}
void DiffuseProbeGridFeatureProcessor::HandleAssetNotification(Data::Asset<Data::AssetData> 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<Data::AssetData> asset)
{
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready);
if (asset.GetId() == m_visualizationModelAsset.GetId())
{
OnVisualizationModelAssetReady(asset);
}
else
{
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready);
}
}
void DiffuseProbeGridFeatureProcessor::OnAssetError(Data::Asset<Data::AssetData> 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

@ -9,6 +9,9 @@
#pragma once
#include <Atom/Feature/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessorInterface.h>
#include <Atom/RHI/RayTracingBufferPools.h>
#include <Atom/RHI/RayTracingAccelerationStructure.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGrid.h>
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<RHI::RayTracingBlas>& GetVisualizationBlas() const { return m_visualizationBlas; }
RHI::Ptr<RHI::RayTracingBlas>& 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<Data::AssetData> 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<NotifyTextureAssetEntry> NotifyTextureAssetVector;
NotifyTextureAssetVector m_notifyTextureAssets;
// visualization
RHI::Ptr<RHI::RayTracingBufferPools> m_visualizationBufferPools;
Data::Asset<RPI::ModelAsset> m_visualizationModelAsset;
RHI::Ptr<RHI::RayTracingBlas> m_visualizationBlas;
Data::Instance<RPI::Model> m_visualizationModel;
RHI::StreamBufferView m_visualizationVB;
RHI::IndexBufferView m_visualizationIB;
};
} // namespace Render
} // namespace AZ

@ -107,15 +107,40 @@ namespace AZ
m_rayTracingPipelineState->Init(*device.get(), &descriptor);
}
void DiffuseProbeGridRayTracingPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridRayTracingPass::IsEnabled() const
{
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
if (!scene)
{
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
if (!rayTracingFeatureProcessor)
{
return;
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
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<RayTracingFeatureProcessor>();
if (!m_initialized)
{
CreateRayTracingPipelineState();
@ -131,13 +156,6 @@ namespace AZ
m_rayTracingShaderTable->Init(*device.get(), rayTracingBufferPools);
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
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<RHI::Buffer>& rayTracingTlasBuffer = rayTracingFeatureProcessor->GetTlas()->GetTlasBuffer();
if (rayTracingTlasBuffer)
{
uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(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<uint32_t>(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();
}
}

@ -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

@ -74,49 +74,71 @@ namespace AZ
}
}
void DiffuseProbeGridRelocationPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridRelocationPass::IsEnabled() const
{
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!scene)
{
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
if (!rayTracingFeatureProcessor || !rayTracingFeatureProcessor->GetSubMeshCount())
{
// empty scene
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
return false;
}
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridRelocationPass requires the RayTracingFeatureProcessor");
if (!rayTracingFeatureProcessor->GetSubMeshCount())
// check TLAS version
uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision();
if (rayTracingDataRevision != m_rayTracingDataRevision)
{
// empty scene
return;
return true;
}
// create the Relocation Srgs for each DiffuseProbeGrid, and check to see if any grids need relocation
bool needRelocation = false;
// check to see if any grids need relocation
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids())
{
uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision();
if (rayTracingDataRevision != m_rayTracingDataRevision)
if (diffuseProbeGrid->GetRemainingRelocationIterations() > 0)
{
// the TLAS changed, relocate probes
m_rayTracingDataRevision = rayTracingDataRevision;
diffuseProbeGrid->ResetRemainingRelocationIterations();
return true;
}
}
return false;
}
if (diffuseProbeGrid->GetRemainingRelocationIterations() > 0)
void DiffuseProbeGridRelocationPass::FrameBeginInternal(FramePrepareParams params)
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
AZ_Assert(rayTracingFeatureProcessor, "DiffuseProbeGridRelocationPass requires the RayTracingFeatureProcessor");
// reset the relocation iterations on the grids if the TLAS was updated
uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids())
{
if (rayTracingDataRevision != m_rayTracingDataRevision)
{
needRelocation = true;
// the TLAS changed, relocate probes
diffuseProbeGrid->ResetRemainingRelocationIterations();
}
}
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<DiffuseProbeGridFeatureProcessor>();
// 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

@ -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<RPI::Shader> m_shader;

@ -51,18 +51,35 @@ namespace AZ
AZ_Assert(m_shaderResourceGroup, "[DiffuseProbeGridRenderPass '%s']: Failed to create SRG", GetPathName().GetCStr());
}
void DiffuseProbeGridRenderPass::FrameBeginInternal(FramePrepareParams params)
bool DiffuseProbeGridRenderPass::IsEnabled() const
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
if (!RenderPass::IsEnabled())
{
return false;
}
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!scene)
{
return false;
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
{
// no diffuse probe grids
return;
return false;
}
return true;
}
void DiffuseProbeGridRenderPass::FrameBeginInternal(FramePrepareParams params)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// get output attachment size
AZ_Assert(GetInputOutputCount() > 0, "DiffuseProbeGridRenderPass: Could not find output bindings");
RPI::PassAttachment* m_outputAttachment = GetInputOutputBinding(0).m_attachment.get();

@ -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;

@ -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 <Atom/RHI/FrameScheduler.h>
#include <Atom/RHI/CommandList.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.h>
#include <RayTracing/RayTracingFeatureProcessor.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationAccelerationStructurePass> DiffuseProbeGridVisualizationAccelerationStructurePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationAccelerationStructurePass> 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<RHI::Device> 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>& 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<DiffuseProbeGridFeatureProcessor>();
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<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// import and attach the visualization TLAS buffers
RHI::Ptr<RHI::RayTracingTlas>& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas();
const RHI::Ptr<RHI::Buffer>& tlasBuffer = visualizationTlas->GetTlasBuffer();
const RHI::Ptr<RHI::Buffer>& 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<uint32_t>(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<uint32_t>(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<DiffuseProbeGridFeatureProcessor>();
// 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<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// TLAS is now updated
diffuseProbeGrid->ResetVisualizationTlasUpdateRequired();
}
}
} // namespace RPI
} // namespace AZ

@ -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 <Atom/RHI/ScopeProducer.h>
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Buffer/Buffer.h>
#include <Atom/RHI/RayTracingBufferPools.h>
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<DiffuseProbeGridVisualizationAccelerationStructurePass> Create(const RPI::PassDescriptor& descriptor);
~DiffuseProbeGridVisualizationAccelerationStructurePass() = default;
private:
explicit DiffuseProbeGridVisualizationAccelerationStructurePass(const RPI::PassDescriptor& descriptor);
bool ShouldUpdate(const AZStd::shared_ptr<DiffuseProbeGrid>& 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

@ -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 <Atom/RPI.Public/RenderPipeline.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationCompositePass.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationCompositePass> DiffuseProbeGridVisualizationCompositePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationCompositePass> 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<DiffuseProbeGridFeatureProcessor>();
if (diffuseProbeGridFeatureProcessor)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (diffuseProbeGrid->GetVisualizationEnabled())
{
return true;
}
}
}
return false;
}
} // namespace RPI
} // namespace AZ

@ -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 <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
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<DiffuseProbeGridVisualizationCompositePass> 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

@ -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 <Atom/RHI/CommandList.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationPreparePass.h>
#include <RayTracing/RayTracingFeatureProcessor.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationPreparePass> DiffuseProbeGridVisualizationPreparePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationPreparePass> 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<RHI::Device> 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>& 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<DiffuseProbeGridFeatureProcessor>();
if (diffuseProbeGridFeatureProcessor)
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (ShouldUpdate(diffuseProbeGrid))
{
return true;
}
}
}
return false;
}
void DiffuseProbeGridVisualizationPreparePass::FrameBeginInternal(FramePrepareParams params)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
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<RHI::RayTracingTlas>& 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<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!ShouldUpdate(diffuseProbeGrid))
{
continue;
}
// import and attach the visualization TLAS and probe data
RHI::Ptr<RHI::RayTracingTlas>& visualizationTlas = diffuseProbeGrid->GetVisualizationTlas();
const RHI::Ptr<RHI::Buffer>& tlasBuffer = visualizationTlas->GetTlasBuffer();
const RHI::Ptr<RHI::Buffer>& 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<uint32_t>(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<uint32_t>(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<DiffuseProbeGridFeatureProcessor>();
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<DiffuseProbeGridFeatureProcessor>();
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

@ -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 <Atom/RPI.Public/Pass/RenderPass.h>
#include <Atom/RPI.Public/Shader/Shader.h>
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<DiffuseProbeGridVisualizationPreparePass> Create(const RPI::PassDescriptor& descriptor);
~DiffuseProbeGridVisualizationPreparePass() = default;
private:
explicit DiffuseProbeGridVisualizationPreparePass(const RPI::PassDescriptor& descriptor);
void LoadShader();
bool ShouldUpdate(const AZStd::shared_ptr<DiffuseProbeGrid>& 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<RPI::Shader> m_shader;
const RHI::PipelineState* m_pipelineState = nullptr;
RHI::Ptr<RHI::ShaderResourceGroupLayout> m_srgLayout;
RHI::DispatchDirect m_dispatchArgs;
};
} // namespace RPI
} // namespace AZ

@ -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 <Atom/RHI/CommandList.h>
#include <Atom/RHI/DispatchRaysItem.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/View.h>
#include <Atom_Feature_Traits_Platform.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
#include <DiffuseGlobalIllumination/DiffuseProbeGridVisualizationRayTracingPass.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<DiffuseProbeGridVisualizationRayTracingPass> DiffuseProbeGridVisualizationRayTracingPass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<DiffuseProbeGridVisualizationRayTracingPass> pass = aznew DiffuseProbeGridVisualizationRayTracingPass(descriptor);
return AZStd::move(pass);
}
DiffuseProbeGridVisualizationRayTracingPass::DiffuseProbeGridVisualizationRayTracingPass(const RPI::PassDescriptor& descriptor)
: RPI::RenderPass(descriptor)
{
RHI::Ptr<RHI::Device> 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<RHI::Device> 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<DiffuseProbeGridFeatureProcessor>();
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<DiffuseProbeGridFeatureProcessor>();
if (!m_initialized)
{
CreateRayTracingPipelineState();
m_initialized = true;
}
if (!m_rayTracingShaderTable)
{
RHI::Ptr<RHI::Device> 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<RHI::RayTracingShaderTableDescriptor> descriptor = AZStd::make_shared<RHI::RayTracingShaderTableDescriptor>();
// 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<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids())
{
if (!diffuseProbeGrid->GetVisualizationEnabled())
{
continue;
}
// TLAS
{
AZ::RHI::AttachmentId tlasAttachmentId = diffuseProbeGrid->GetProbeVisualizationTlasAttachmentId();
const RHI::Ptr<RHI::Buffer>& 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<uint32_t>(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<RPI::PassAttachment> 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<DiffuseProbeGridFeatureProcessor>();
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<DiffuseProbeGridFeatureProcessor>();
const AZStd::vector<RPI::ViewPtr>& 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

@ -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 <Atom/RPI.Public/Pass/RenderPass.h>
#include <Atom/RHI/RayTracingPipelineState.h>
#include <Atom/RHI/RayTracingShaderTable.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
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<DiffuseProbeGridVisualizationRayTracingPass> 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<RPI::Shader> m_rayTracingShader;
Data::Instance<RPI::Shader> m_missShader;
Data::Instance<RPI::Shader> m_closestHitShader;
RHI::Ptr<RHI::RayTracingPipelineState> m_rayTracingPipelineState;
// ray tracing shader table
RHI::Ptr<RHI::RayTracingShaderTable> 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<RHI::ShaderResourceGroupLayout> m_globalSrgLayout;
RHI::ConstPtr<RHI::PipelineState> m_globalPipelineState;
bool m_initialized = false;
};
} // namespace RPI
} // namespace AZ

@ -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,

@ -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

@ -182,6 +182,7 @@ namespace AZ
//! Returns the TLAS RHI buffer
virtual const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const = 0;
virtual const RHI::Ptr<RHI::Buffer> GetTlasInstancesBuffer() const = 0;
private:
// Platform API

@ -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:

@ -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();

@ -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;

@ -40,7 +40,8 @@ namespace AZ
const TlasBuffers& GetBuffers() const { return m_buffers[m_currentBufferIndex]; }
// RHI::RayTracingTlas overrides...
virtual const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; }
const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; }
const RHI::Ptr<RHI::Buffer> GetTlasInstancesBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasInstancesBuffer; }
private:
RayTracingTlas() = default;

@ -26,7 +26,8 @@ namespace AZ
static RHI::Ptr<RayTracingTlas> Create();
// RHI::RayTracingTlas overrides...
virtual const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const override { return nullptr; }
const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const override { return nullptr; }
const RHI::Ptr<RHI::Buffer> GetTlasInstancesBuffer() const override { return nullptr; }
private:
RayTracingTlas() = default;

@ -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)

@ -24,8 +24,8 @@ namespace AZ
static RHI::Ptr<RayTracingBufferPools> 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;

@ -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;

@ -43,7 +43,8 @@ namespace AZ
const TlasBuffers& GetBuffers() const { return m_buffers[m_currentBufferIndex]; }
// RHI::RayTracingTlas overrides...
virtual const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; }
const RHI::Ptr<RHI::Buffer> GetTlasBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasBuffer; }
const RHI::Ptr<RHI::Buffer> GetTlasInstancesBuffer() const override { return m_buffers[m_currentBufferIndex].m_tlasInstancesBuffer; }
private:
RayTracingTlas() = default;

@ -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

@ -34,7 +34,7 @@ namespace AZ
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<DiffuseProbeGridComponentConfig>()
->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)

@ -48,6 +48,10 @@ namespace AZ
Data::Asset<RPI::StreamingImageAsset> m_bakedDistanceTextureAsset;
Data::Asset<RPI::StreamingImageAsset> 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);

@ -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<void, AZStd::string> EditorDiffuseProbeGridComponent::OnModeChangeValidate([[maybe_unused]] void* newValue, [[maybe_unused]] const AZ::Uuid& valueType)
{
DiffuseProbeGridMode newMode = (*(reinterpret_cast<DiffuseProbeGridMode*>(newValue)));

@ -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<void, AZStd::string> 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;

Loading…
Cancel
Save