fe8dac7989
* ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface Introduced new PassSystemInterface::ForEachPass() funtion to replace PassSystemInterface::FindPasses(), PassSystemInterface::GetPassesByTemplateName and ParentPass::FindPassByNameRecursive() functions. Update all the places which were using those three functions. The new pass finding filter support any combination of pass name, pass template name, pass class type, pass hirechary, owner scene, owner render pipeline. Update unit tests. Signed-off-by: Qing Tao <qingtao@amazon.com>
646 lines
28 KiB
C++
646 lines
28 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <Atom/RPI.Public/RPIUtils.h>
|
|
#include <Atom/RPI.Public/Scene.h>
|
|
#include <Atom/RPI.Public/Shader/Shader.h>
|
|
#include <Atom/RPI.Public/View.h>
|
|
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
|
#include <DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h>
|
|
#include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
|
|
#include <Atom/RHI/Factory.h>
|
|
#include <Atom/RHI/RHISystemInterface.h>
|
|
#include <Atom/RHI/PipelineState.h>
|
|
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
|
|
|
|
// This component invokes shaders based on Nvidia's RTX-GI SDK.
|
|
// Please refer to "Shaders/DiffuseGlobalIllumination/Nvidia RTX-GI License.txt" for license information.
|
|
|
|
namespace AZ
|
|
{
|
|
namespace Render
|
|
{
|
|
void DiffuseProbeGridFeatureProcessor::Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
|
|
{
|
|
serializeContext
|
|
->Class<DiffuseProbeGridFeatureProcessor, FeatureProcessor>()
|
|
->Version(0);
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::Activate()
|
|
{
|
|
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
|
|
|
|
m_diffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
|
|
m_realTimeDiffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
|
|
|
|
RHI::BufferPoolDescriptor desc;
|
|
desc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
|
|
desc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
|
|
|
|
m_bufferPool = RHI::Factory::Get().CreateBufferPool();
|
|
m_bufferPool->SetName(Name("DiffuseProbeGridBoxBufferPool"));
|
|
[[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(*rhiSystem->GetDevice(), desc);
|
|
AZ_Error("DiffuseProbeGridFeatureProcessor", resultCode == RHI::ResultCode::Success, "Failed to initialize buffer pool");
|
|
|
|
// create box mesh vertices and indices
|
|
CreateBoxMesh();
|
|
|
|
// image pool
|
|
{
|
|
RHI::ImagePoolDescriptor imagePoolDesc;
|
|
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);
|
|
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize output image pool");
|
|
}
|
|
|
|
// create image view descriptors
|
|
m_probeGridRenderData.m_probeRayTraceImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::RayTraceImageFormat, 0, 0);
|
|
m_probeGridRenderData.m_probeIrradianceImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::IrradianceImageFormat, 0, 0);
|
|
m_probeGridRenderData.m_probeDistanceImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::DistanceImageFormat, 0, 0);
|
|
m_probeGridRenderData.m_probeRelocationImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::RelocationImageFormat, 0, 0);
|
|
m_probeGridRenderData.m_probeClassificationImageViewDescriptor = RHI::ImageViewDescriptor::Create(DiffuseProbeGridRenderData::ClassificationImageFormat, 0, 0);
|
|
|
|
// load shader
|
|
// Note: the shader may not be available on all platforms
|
|
Data::Instance<RPI::Shader> shader = RPI::LoadCriticalShader("Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRender.azshader");
|
|
if (shader)
|
|
{
|
|
m_probeGridRenderData.m_drawListTag = shader->GetDrawListTag();
|
|
|
|
m_probeGridRenderData.m_pipelineState = aznew RPI::PipelineStateForDraw;
|
|
m_probeGridRenderData.m_pipelineState->Init(shader); // uses default shader variant
|
|
m_probeGridRenderData.m_pipelineState->SetInputStreamLayout(m_boxStreamLayout);
|
|
m_probeGridRenderData.m_pipelineState->SetOutputFromScene(GetParentScene());
|
|
m_probeGridRenderData.m_pipelineState->Finalize();
|
|
|
|
// load object shader resource group
|
|
m_probeGridRenderData.m_shader = shader;
|
|
m_probeGridRenderData.m_srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Object);
|
|
AZ_Error("DiffuseProbeGridFeatureProcessor", m_probeGridRenderData.m_srgLayout != nullptr, "Failed to find ObjectSrg layout");
|
|
}
|
|
|
|
EnableSceneNotification();
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::Deactivate()
|
|
{
|
|
AZ_Warning("DiffuseProbeGridFeatureProcessor", m_diffuseProbeGrids.size() == 0,
|
|
"Deactivating the DiffuseProbeGridFeatureProcessor, but there are still outstanding probe grids probes. Components\n"
|
|
"using DiffuseProbeGridHandles should free them before the DiffuseProbeGridFeatureProcessor is deactivated.\n"
|
|
);
|
|
|
|
DisableSceneNotification();
|
|
|
|
if (m_bufferPool)
|
|
{
|
|
m_bufferPool.reset();
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
|
|
{
|
|
AZ_PROFILE_SCOPE(AzRender, "DiffuseProbeGridFeatureProcessor: Simulate");
|
|
|
|
// update pipeline states
|
|
if (m_needUpdatePipelineStates)
|
|
{
|
|
UpdatePipelineStates();
|
|
m_needUpdatePipelineStates = false;
|
|
}
|
|
|
|
// check pending textures and connect bus for notifications
|
|
for (auto& notificationEntry : m_notifyTextureAssets)
|
|
{
|
|
if (notificationEntry.m_assetId.IsValid())
|
|
{
|
|
// asset already has an assetId
|
|
continue;
|
|
}
|
|
|
|
// query for the assetId
|
|
AZ::Data::AssetId assetId;
|
|
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
|
assetId,
|
|
&AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
|
|
notificationEntry.m_relativePath.c_str(),
|
|
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
|
|
false);
|
|
|
|
if (assetId.IsValid())
|
|
{
|
|
notificationEntry.m_assetId = assetId;
|
|
notificationEntry.m_asset.Create(assetId, true);
|
|
Data::AssetBus::MultiHandler::BusConnect(assetId);
|
|
}
|
|
}
|
|
|
|
// if the volumes changed we need to re-sort the probe list
|
|
if (m_probeGridSortRequired)
|
|
{
|
|
AZ_PROFILE_SCOPE(AzRender, "Sort diffuse probe grids");
|
|
|
|
// sort the probes by descending inner volume size, so the smallest volumes are rendered last
|
|
auto sortFn = [](AZStd::shared_ptr<DiffuseProbeGrid> const& probe1, AZStd::shared_ptr<DiffuseProbeGrid> const& probe2) -> bool
|
|
{
|
|
const Obb& obb1 = probe1->GetObbWs();
|
|
const Obb& obb2 = probe2->GetObbWs();
|
|
float size1 = obb1.GetHalfLengthX() * obb1.GetHalfLengthZ() * obb1.GetHalfLengthY();
|
|
float size2 = obb2.GetHalfLengthX() * obb2.GetHalfLengthZ() * obb2.GetHalfLengthY();
|
|
|
|
return (size1 > size2);
|
|
};
|
|
|
|
AZStd::sort(m_diffuseProbeGrids.begin(), m_diffuseProbeGrids.end(), sortFn);
|
|
AZStd::sort(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), sortFn);
|
|
m_probeGridSortRequired = false;
|
|
}
|
|
|
|
// call Simulate on all diffuse probe grids
|
|
for (uint32_t probeGridIndex = 0; probeGridIndex < m_diffuseProbeGrids.size(); ++probeGridIndex)
|
|
{
|
|
AZStd::shared_ptr<DiffuseProbeGrid>& diffuseProbeGrid = m_diffuseProbeGrids[probeGridIndex];
|
|
AZ_Assert(diffuseProbeGrid.use_count() > 1, "DiffuseProbeGrid found with no corresponding owner, ensure that RemoveProbe() is called before releasing probe handles");
|
|
|
|
diffuseProbeGrid->Simulate(probeGridIndex);
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::OnBeginPrepareRender()
|
|
{
|
|
for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids)
|
|
{
|
|
diffuseProbeGrid->ResetCullingVisibility();
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::OnEndPrepareRender()
|
|
{
|
|
// re-build the list of visible real-time diffuse probe grids
|
|
m_visibleRealTimeDiffuseProbeGrids.clear();
|
|
for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids)
|
|
{
|
|
if (diffuseProbeGrid->GetIsVisible())
|
|
{
|
|
m_visibleRealTimeDiffuseProbeGrids.push_back(diffuseProbeGrid);
|
|
}
|
|
}
|
|
}
|
|
|
|
DiffuseProbeGridHandle DiffuseProbeGridFeatureProcessor::AddProbeGrid(const AZ::Transform& transform, const AZ::Vector3& extents, const AZ::Vector3& probeSpacing)
|
|
{
|
|
AZStd::shared_ptr<DiffuseProbeGrid> diffuseProbeGrid = AZStd::make_shared<DiffuseProbeGrid>();
|
|
diffuseProbeGrid->Init(GetParentScene(), &m_probeGridRenderData);
|
|
diffuseProbeGrid->SetTransform(transform);
|
|
diffuseProbeGrid->SetExtents(extents);
|
|
diffuseProbeGrid->SetProbeSpacing(probeSpacing);
|
|
m_diffuseProbeGrids.push_back(diffuseProbeGrid);
|
|
|
|
UpdateRealTimeList(diffuseProbeGrid);
|
|
|
|
m_probeGridSortRequired = true;
|
|
|
|
return diffuseProbeGrid;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::RemoveProbeGrid(DiffuseProbeGridHandle& probeGrid)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "RemoveProbeGrid called with an invalid handle");
|
|
|
|
// remove from main list
|
|
auto itEntry = AZStd::find_if(m_diffuseProbeGrids.begin(), m_diffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
|
|
{
|
|
return (entry == probeGrid);
|
|
});
|
|
|
|
AZ_Assert(itEntry != m_diffuseProbeGrids.end(), "RemoveProbeGrid called with a probe grid that is not in the probe list");
|
|
m_diffuseProbeGrids.erase(itEntry);
|
|
|
|
// remove from side list of real-time grids
|
|
itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
|
|
{
|
|
return (entry == probeGrid);
|
|
});
|
|
|
|
if (itEntry != m_realTimeDiffuseProbeGrids.end())
|
|
{
|
|
m_realTimeDiffuseProbeGrids.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)
|
|
{
|
|
return (entry == probeGrid);
|
|
});
|
|
|
|
if (itEntry != m_visibleRealTimeDiffuseProbeGrids.end())
|
|
{
|
|
m_visibleRealTimeDiffuseProbeGrids.erase(itEntry);
|
|
}
|
|
|
|
probeGrid = nullptr;
|
|
}
|
|
|
|
bool DiffuseProbeGridFeatureProcessor::ValidateExtents(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& newExtents)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetTransform called with an invalid handle");
|
|
return probeGrid->ValidateExtents(newExtents);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetExtents(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& extents)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetExtents called with an invalid handle");
|
|
probeGrid->SetExtents(extents);
|
|
m_probeGridSortRequired = true;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetTransform(const DiffuseProbeGridHandle& probeGrid, const AZ::Transform& transform)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetTransform called with an invalid handle");
|
|
probeGrid->SetTransform(transform);
|
|
m_probeGridSortRequired = true;
|
|
}
|
|
|
|
bool DiffuseProbeGridFeatureProcessor::ValidateProbeSpacing(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& newSpacing)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetTransform called with an invalid handle");
|
|
return probeGrid->ValidateProbeSpacing(newSpacing);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetProbeSpacing(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& probeSpacing)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetProbeSpacing called with an invalid handle");
|
|
probeGrid->SetProbeSpacing(probeSpacing);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetViewBias(const DiffuseProbeGridHandle& probeGrid, float viewBias)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetViewBias called with an invalid handle");
|
|
probeGrid->SetViewBias(viewBias);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetNormalBias(const DiffuseProbeGridHandle& probeGrid, float normalBias)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetNormalBias called with an invalid handle");
|
|
probeGrid->SetNormalBias(normalBias);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetAmbientMultiplier(const DiffuseProbeGridHandle& probeGrid, float ambientMultiplier)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetAmbientMultiplier called with an invalid handle");
|
|
probeGrid->SetAmbientMultiplier(ambientMultiplier);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::Enable(const DiffuseProbeGridHandle& probeGrid, bool enable)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "Enable called with an invalid handle");
|
|
probeGrid->Enable(enable);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetGIShadows(const DiffuseProbeGridHandle& probeGrid, bool giShadows)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetGIShadows called with an invalid handle");
|
|
probeGrid->SetGIShadows(giShadows);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetUseDiffuseIbl called with an invalid handle");
|
|
probeGrid->SetUseDiffuseIbl(useDiffuseIbl);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::BakeTextures(
|
|
const DiffuseProbeGridHandle& probeGrid,
|
|
DiffuseProbeGridBakeTexturesCallback callback,
|
|
const AZStd::string& irradianceTextureRelativePath,
|
|
const AZStd::string& distanceTextureRelativePath,
|
|
const AZStd::string& relocationTextureRelativePath,
|
|
const AZStd::string& classificationTextureRelativePath)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "BakeTextures called with an invalid handle");
|
|
|
|
AddNotificationEntry(irradianceTextureRelativePath);
|
|
AddNotificationEntry(distanceTextureRelativePath);
|
|
AddNotificationEntry(relocationTextureRelativePath);
|
|
AddNotificationEntry(classificationTextureRelativePath);
|
|
|
|
probeGrid->GetTextureReadback().BeginTextureReadback(callback);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::UpdateRealTimeList(const DiffuseProbeGridHandle& diffuseProbeGrid)
|
|
{
|
|
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::RealTime)
|
|
{
|
|
// add to side list of real-time grids
|
|
auto itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
|
|
{
|
|
return (entry == diffuseProbeGrid);
|
|
});
|
|
|
|
if (itEntry == m_realTimeDiffuseProbeGrids.end())
|
|
{
|
|
m_realTimeDiffuseProbeGrids.push_back(diffuseProbeGrid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// remove from side list of real-time grids
|
|
auto itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
|
|
{
|
|
return (entry == diffuseProbeGrid);
|
|
});
|
|
|
|
if (itEntry != m_realTimeDiffuseProbeGrids.end())
|
|
{
|
|
m_realTimeDiffuseProbeGrids.erase(itEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::AddNotificationEntry(const AZStd::string& relativePath)
|
|
{
|
|
AZStd::string assetPath = relativePath + ".streamingimage";
|
|
|
|
// check to see if this is an existing asset
|
|
AZ::Data::AssetId assetId;
|
|
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
|
assetId,
|
|
&AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
|
|
assetPath.c_str(),
|
|
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
|
|
false);
|
|
|
|
// We only track notifications for new texture assets, meaning assets that are created the first time a DiffuseProbeGrid is baked.
|
|
// On subsequent bakes the existing assets are automatically reloaded by the RPI since they are already known by the asset system.
|
|
if (!assetId.IsValid())
|
|
{
|
|
m_notifyTextureAssets.push_back({ assetPath, assetId });
|
|
}
|
|
}
|
|
|
|
bool DiffuseProbeGridFeatureProcessor::CheckTextureAssetNotification(
|
|
const AZStd::string& relativePath,
|
|
Data::Asset<RPI::StreamingImageAsset>& outTextureAsset,
|
|
DiffuseProbeGridTextureNotificationType& outNotificationType)
|
|
{
|
|
for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
|
|
{
|
|
if (itNotification->m_relativePath == relativePath)
|
|
{
|
|
outNotificationType = itNotification->m_notificationType;
|
|
if (outNotificationType != DiffuseProbeGridTextureNotificationType::None)
|
|
{
|
|
outTextureAsset = itNotification->m_asset;
|
|
m_notifyTextureAssets.erase(itNotification);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool DiffuseProbeGridFeatureProcessor::AreBakedTexturesReferenced(
|
|
const AZStd::string& irradianceTextureRelativePath,
|
|
const AZStd::string& distanceTextureRelativePath,
|
|
const AZStd::string& relocationTextureRelativePath,
|
|
const AZStd::string& classificationTextureRelativePath)
|
|
{
|
|
for (auto& diffuseProbeGrid : m_diffuseProbeGrids)
|
|
{
|
|
if ((diffuseProbeGrid->GetBakedIrradianceRelativePath() == irradianceTextureRelativePath) ||
|
|
(diffuseProbeGrid->GetBakedDistanceRelativePath() == distanceTextureRelativePath) ||
|
|
(diffuseProbeGrid->GetBakedRelocationRelativePath() == relocationTextureRelativePath) ||
|
|
(diffuseProbeGrid->GetBakedClassificationRelativePath() == classificationTextureRelativePath))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetMode called with an invalid handle");
|
|
probeGrid->SetMode(mode);
|
|
|
|
UpdateRealTimeList(probeGrid);
|
|
|
|
m_probeGridSortRequired = true;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures)
|
|
{
|
|
AZ_Assert(probeGrid.get(), "SetBakedTextures called with an invalid handle");
|
|
probeGrid->SetBakedTextures(bakedTextures);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::CreateBoxMesh()
|
|
{
|
|
// vertex positions
|
|
static const Position positions[] =
|
|
{
|
|
// front
|
|
{ -0.5f, -0.5f, 0.5f },
|
|
{ 0.5f, -0.5f, 0.5f },
|
|
{ 0.5f, 0.5f, 0.5f },
|
|
{ -0.5f, 0.5f, 0.5f },
|
|
|
|
// back
|
|
{ -0.5f, -0.5f, -0.5f },
|
|
{ 0.5f, -0.5f, -0.5f },
|
|
{ 0.5f, 0.5f, -0.5f },
|
|
{ -0.5f, 0.5f, -0.5f },
|
|
|
|
// left
|
|
{ -0.5f, -0.5f, 0.5f },
|
|
{ -0.5f, 0.5f, 0.5f },
|
|
{ -0.5f, 0.5f, -0.5f },
|
|
{ -0.5f, -0.5f, -0.5f },
|
|
|
|
// right
|
|
{ 0.5f, -0.5f, 0.5f },
|
|
{ 0.5f, 0.5f, 0.5f },
|
|
{ 0.5f, 0.5f, -0.5f },
|
|
{ 0.5f, -0.5f, -0.5f },
|
|
|
|
// bottom
|
|
{ -0.5f, -0.5f, 0.5f },
|
|
{ 0.5f, -0.5f, 0.5f },
|
|
{ 0.5f, -0.5f, -0.5f },
|
|
{ -0.5f, -0.5f, -0.5f },
|
|
|
|
// top
|
|
{ -0.5f, 0.5f, 0.5f },
|
|
{ 0.5f, 0.5f, 0.5f },
|
|
{ 0.5f, 0.5f, -0.5f },
|
|
{ -0.5f, 0.5f, -0.5f },
|
|
};
|
|
static const u32 numPositions = sizeof(positions) / sizeof(positions[0]);
|
|
|
|
for (u32 i = 0; i < numPositions; ++i)
|
|
{
|
|
m_boxPositions.push_back(positions[i]);
|
|
}
|
|
|
|
// indices
|
|
static const uint16_t indices[] =
|
|
{
|
|
// front
|
|
0, 1, 2, 2, 3, 0,
|
|
|
|
// back
|
|
5, 4, 7, 7, 6, 5,
|
|
|
|
// left
|
|
8, 9, 10, 10, 11, 8,
|
|
|
|
// right
|
|
14, 13, 12, 12, 15, 14,
|
|
|
|
// bottom
|
|
18, 17, 16, 16, 19, 18,
|
|
|
|
// top
|
|
23, 20, 21, 21, 22, 23
|
|
};
|
|
static const u32 numIndices = sizeof(indices) / sizeof(indices[0]);
|
|
|
|
for (u32 i = 0; i < numIndices; ++i)
|
|
{
|
|
m_boxIndices.push_back(indices[i]);
|
|
}
|
|
|
|
// create stream layout
|
|
RHI::InputStreamLayoutBuilder layoutBuilder;
|
|
layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
|
|
layoutBuilder.SetTopology(RHI::PrimitiveTopology::TriangleList);
|
|
m_boxStreamLayout = layoutBuilder.End();
|
|
|
|
// create index buffer
|
|
AZ::RHI::BufferInitRequest request;
|
|
m_boxIndexBuffer = AZ::RHI::Factory::Get().CreateBuffer();
|
|
request.m_buffer = m_boxIndexBuffer.get();
|
|
request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) };
|
|
request.m_initialData = m_boxIndices.data();
|
|
AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request);
|
|
AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result);
|
|
|
|
// create index buffer view
|
|
AZ::RHI::IndexBufferView indexBufferView =
|
|
{
|
|
*m_boxIndexBuffer,
|
|
0,
|
|
sizeof(indices),
|
|
AZ::RHI::IndexFormat::Uint16,
|
|
};
|
|
m_probeGridRenderData.m_boxIndexBufferView = indexBufferView;
|
|
m_probeGridRenderData.m_boxIndexCount = numIndices;
|
|
|
|
// create position buffer
|
|
m_boxPositionBuffer = AZ::RHI::Factory::Get().CreateBuffer();
|
|
request.m_buffer = m_boxPositionBuffer.get();
|
|
request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxPositions.size() * sizeof(Position) };
|
|
request.m_initialData = m_boxPositions.data();
|
|
result = m_bufferPool->InitBuffer(request);
|
|
AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result);
|
|
|
|
// create position buffer view
|
|
RHI::StreamBufferView positionBufferView =
|
|
{
|
|
*m_boxPositionBuffer,
|
|
0,
|
|
(uint32_t)(m_boxPositions.size() * sizeof(Position)),
|
|
sizeof(Position),
|
|
};
|
|
m_probeGridRenderData.m_boxPositionBufferView = { { positionBufferView } };
|
|
|
|
AZ::RHI::ValidateStreamBufferViews(m_boxStreamLayout, m_probeGridRenderData.m_boxPositionBufferView);
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::OnRenderPipelinePassesChanged([[maybe_unused]] RPI::RenderPipeline* renderPipeline)
|
|
{
|
|
UpdatePasses();
|
|
m_needUpdatePipelineStates = true;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::OnRenderPipelineAdded([[maybe_unused]] RPI::RenderPipelinePtr pipeline)
|
|
{
|
|
UpdatePasses();
|
|
m_needUpdatePipelineStates = true;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* pipeline)
|
|
{
|
|
m_needUpdatePipelineStates = true;
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::UpdatePipelineStates()
|
|
{
|
|
if(m_probeGridRenderData.m_pipelineState)
|
|
{
|
|
m_probeGridRenderData.m_pipelineState->SetOutputFromScene(GetParentScene());
|
|
m_probeGridRenderData.m_pipelineState->Finalize();
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::UpdatePasses()
|
|
{
|
|
// disable the DiffuseProbeGridUpdatePass if the platform does not support raytracing
|
|
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
|
|
if (device->GetFeatures().m_rayTracing == false)
|
|
{
|
|
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene());
|
|
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
|
{
|
|
pass->SetEnabled(false);
|
|
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
|
});
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::HandleAssetNotification(Data::Asset<Data::AssetData> asset, DiffuseProbeGridTextureNotificationType notificationType)
|
|
{
|
|
for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
|
|
{
|
|
if (itNotification->m_assetId == asset.GetId())
|
|
{
|
|
// store the texture asset
|
|
itNotification->m_asset = Data::static_pointer_cast<RPI::StreamingImageAsset>(asset);
|
|
itNotification->m_notificationType = notificationType;
|
|
|
|
// stop notifications on this asset
|
|
Data::AssetBus::MultiHandler::BusDisconnect(itNotification->m_assetId);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DiffuseProbeGridFeatureProcessor::OnAssetReady(Data::Asset<Data::AssetData> asset)
|
|
{
|
|
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());
|
|
|
|
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Error);
|
|
}
|
|
} // namespace Render
|
|
} // namespace AZ
|