You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
530 lines
22 KiB
C++
530 lines
22 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/View.h>
|
|
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
|
#include <Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h>
|
|
#include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
|
|
#include <Atom/RHI/Factory.h>
|
|
#include <Atom/RHI/RHISystemInterface.h>
|
|
#include <Atom/RHI/PipelineState.h>
|
|
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
|
|
#include <AzCore/Debug/EventTrace.h>
|
|
|
|
namespace AZ
|
|
{
|
|
namespace Render
|
|
{
|
|
void ReflectionProbeFeatureProcessor::Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
|
|
{
|
|
serializeContext
|
|
->Class<ReflectionProbeFeatureProcessor, FeatureProcessor>()
|
|
->Version(0);
|
|
}
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::Activate()
|
|
{
|
|
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
|
|
|
|
m_reflectionProbes.reserve(InitialProbeAllocationSize);
|
|
|
|
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("ReflectionProbeBoxBufferPool"));
|
|
[[maybe_unused]] RHI::ResultCode resultCode = m_bufferPool->Init(*rhiSystem->GetDevice(), desc);
|
|
AZ_Error("ReflectionProbeFeatureProcessor", resultCode == RHI::ResultCode::Success, "Failed to initialize buffer pool");
|
|
|
|
// create box mesh vertices and indices
|
|
CreateBoxMesh();
|
|
|
|
// load shaders for stencil, blend weight, and render passes
|
|
LoadShader("shaders/reflections/reflectionprobestencil.azshader",
|
|
m_reflectionRenderData.m_stencilPipelineState,
|
|
m_reflectionRenderData.m_stencilShader,
|
|
m_reflectionRenderData.m_stencilSrgLayout,
|
|
m_reflectionRenderData.m_stencilDrawListTag);
|
|
|
|
LoadShader("shaders/reflections/reflectionprobeblendweight.azshader",
|
|
m_reflectionRenderData.m_blendWeightPipelineState,
|
|
m_reflectionRenderData.m_blendWeightShader,
|
|
m_reflectionRenderData.m_blendWeightSrgLayout,
|
|
m_reflectionRenderData.m_blendWeightDrawListTag);
|
|
|
|
LoadShader("shaders/reflections/reflectionproberenderouter.azshader",
|
|
m_reflectionRenderData.m_renderOuterPipelineState,
|
|
m_reflectionRenderData.m_renderOuterShader,
|
|
m_reflectionRenderData.m_renderOuterSrgLayout,
|
|
m_reflectionRenderData.m_renderOuterDrawListTag);
|
|
|
|
LoadShader("shaders/reflections/reflectionproberenderinner.azshader",
|
|
m_reflectionRenderData.m_renderInnerPipelineState,
|
|
m_reflectionRenderData.m_renderInnerShader,
|
|
m_reflectionRenderData.m_renderInnerSrgLayout,
|
|
m_reflectionRenderData.m_renderInnerDrawListTag);
|
|
|
|
EnableSceneNotification();
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::Deactivate()
|
|
{
|
|
AZ_Warning("ReflectionProbeFeatureProcessor", m_reflectionProbes.size() == 0,
|
|
"Deactivating the ReflectionProbeFeatureProcessor, but there are still outstanding reflection probes. Components\n"
|
|
"using ReflectionProbeHandles should free them before the ReflectionProbeFeatureProcessor is deactivated.\n"
|
|
);
|
|
|
|
DisableSceneNotification();
|
|
|
|
if (m_bufferPool)
|
|
{
|
|
m_bufferPool.reset();
|
|
}
|
|
|
|
Data::AssetBus::MultiHandler::BusDisconnect();
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
|
|
{
|
|
AZ_PROFILE_SCOPE(AzRender, "ReflectionProbeFeatureProcessor: Simulate");
|
|
|
|
// update pipeline states
|
|
if (m_needUpdatePipelineStates)
|
|
{
|
|
UpdatePipelineStates();
|
|
m_needUpdatePipelineStates = false;
|
|
}
|
|
|
|
// check pending cubemaps and notify that the asset is ready
|
|
for (auto& notificationEntry : m_notifyCubeMapAssets)
|
|
{
|
|
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_probeSortRequired)
|
|
{
|
|
AZ_PROFILE_SCOPE(AzRender, "Sort reflection probes");
|
|
|
|
// sort the probes by descending inner volume size, so the smallest volumes are rendered last
|
|
auto sortFn = [](AZStd::shared_ptr<ReflectionProbe> const& probe1, AZStd::shared_ptr<ReflectionProbe> const& probe2) -> bool
|
|
{
|
|
const Obb& obb1 = probe1->GetInnerObbWs();
|
|
const Obb& obb2 = probe2->GetInnerObbWs();
|
|
float size1 = obb1.GetHalfLengthX() * obb1.GetHalfLengthZ() * obb1.GetHalfLengthY();
|
|
float size2 = obb2.GetHalfLengthX() * obb2.GetHalfLengthZ() * obb2.GetHalfLengthY();
|
|
|
|
return (size1 > size2);
|
|
};
|
|
|
|
AZStd::sort(m_reflectionProbes.begin(), m_reflectionProbes.end(), sortFn);
|
|
m_probeSortRequired = false;
|
|
|
|
// notify the MeshFeatureProcessor that the reflection probes changed
|
|
MeshFeatureProcessor* meshFeatureProcessor = GetParentScene()->GetFeatureProcessor<MeshFeatureProcessor>();
|
|
meshFeatureProcessor->UpdateMeshReflectionProbes();
|
|
}
|
|
|
|
// call Simulate on all reflection probes
|
|
for (uint32_t probeIndex = 0; probeIndex < m_reflectionProbes.size(); ++probeIndex)
|
|
{
|
|
AZStd::shared_ptr<ReflectionProbe>& reflectionProbe = m_reflectionProbes[probeIndex];
|
|
AZ_Assert(reflectionProbe.use_count() > 1, "ReflectionProbe found with no corresponding owner, ensure that RemoveProbe() is called before releasing probe handles");
|
|
|
|
reflectionProbe->Simulate(probeIndex);
|
|
}
|
|
}
|
|
|
|
ReflectionProbeHandle ReflectionProbeFeatureProcessor::AddProbe(const AZ::Transform& transform, bool useParallaxCorrection)
|
|
{
|
|
AZStd::shared_ptr<ReflectionProbe> reflectionProbe = AZStd::make_shared<ReflectionProbe>();
|
|
reflectionProbe->Init(GetParentScene(), &m_reflectionRenderData);
|
|
reflectionProbe->SetTransform(transform);
|
|
reflectionProbe->SetUseParallaxCorrection(useParallaxCorrection);
|
|
m_reflectionProbes.push_back(reflectionProbe);
|
|
m_probeSortRequired = true;
|
|
|
|
return reflectionProbe;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::RemoveProbe(ReflectionProbeHandle& probe)
|
|
{
|
|
AZ_Assert(probe.get(), "RemoveProbe called with an invalid handle");
|
|
|
|
auto itEntry = AZStd::find_if(m_reflectionProbes.begin(), m_reflectionProbes.end(), [&](AZStd::shared_ptr<ReflectionProbe> const& entry)
|
|
{
|
|
return (entry == probe);
|
|
});
|
|
|
|
AZ_Assert(itEntry != m_reflectionProbes.end(), "RemoveProbe called with a probe that is not in the probe list");
|
|
m_reflectionProbes.erase(itEntry);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::SetProbeOuterExtents(const ReflectionProbeHandle& probe, const Vector3& outerExtents)
|
|
{
|
|
AZ_Assert(probe.get(), "SetProbeOuterExtents called with an invalid handle");
|
|
probe->SetOuterExtents(outerExtents);
|
|
m_probeSortRequired = true;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::SetProbeInnerExtents(const ReflectionProbeHandle& probe, const Vector3& innerExtents)
|
|
{
|
|
AZ_Assert(probe.get(), "SetProbeInnerExtents called with an invalid handle");
|
|
probe->SetInnerExtents(innerExtents);
|
|
m_probeSortRequired = true;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::SetProbeCubeMap(const ReflectionProbeHandle& probe, Data::Instance<RPI::Image>& cubeMapImage, const AZStd::string& relativePath)
|
|
{
|
|
AZ_Assert(probe.get(), "SetProbeCubeMap called with an invalid handle");
|
|
probe->SetCubeMapImage(cubeMapImage, relativePath);
|
|
|
|
// notify the MeshFeatureProcessor that the reflection probe changed
|
|
MeshFeatureProcessor* meshFeatureProcessor = GetParentScene()->GetFeatureProcessor<MeshFeatureProcessor>();
|
|
meshFeatureProcessor->UpdateMeshReflectionProbes();
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::SetProbeTransform(const ReflectionProbeHandle& probe, const AZ::Transform& transform)
|
|
{
|
|
AZ_Assert(probe.get(), "SetProbeTransform called with an invalid handle");
|
|
probe->SetTransform(transform);
|
|
m_probeSortRequired = true;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::BakeProbe(const ReflectionProbeHandle& probe, BuildCubeMapCallback callback, const AZStd::string& relativePath)
|
|
{
|
|
AZ_Assert(probe.get(), "BakeProbe called with an invalid handle");
|
|
probe->BuildCubeMap(callback);
|
|
|
|
// check to see if this is an existing asset
|
|
AZ::Data::AssetId assetId;
|
|
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
|
assetId,
|
|
&AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
|
|
relativePath.c_str(),
|
|
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
|
|
false);
|
|
|
|
// we only track notifications for new cubemap assets, existing assets are automatically reloaded by the RPI
|
|
if (!assetId.IsValid())
|
|
{
|
|
m_notifyCubeMapAssets.push_back({ relativePath, assetId });
|
|
}
|
|
}
|
|
|
|
bool ReflectionProbeFeatureProcessor::CheckCubeMapAssetNotification(const AZStd::string& relativePath, Data::Asset<RPI::StreamingImageAsset>& outCubeMapAsset, CubeMapAssetNotificationType& outNotificationType)
|
|
{
|
|
for (NotifyCubeMapAssetVector::iterator itNotification = m_notifyCubeMapAssets.begin(); itNotification != m_notifyCubeMapAssets.end(); ++itNotification)
|
|
{
|
|
if (itNotification->m_relativePath == relativePath)
|
|
{
|
|
outNotificationType = itNotification->m_notificationType;
|
|
if (outNotificationType != CubeMapAssetNotificationType::None)
|
|
{
|
|
outCubeMapAsset = itNotification->m_asset;
|
|
m_notifyCubeMapAssets.erase(itNotification);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ReflectionProbeFeatureProcessor::IsCubeMapReferenced(const AZStd::string& relativePath)
|
|
{
|
|
for (auto& reflectionProbe : m_reflectionProbes)
|
|
{
|
|
if (reflectionProbe->GetCubeMapRelativePath() == relativePath)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization)
|
|
{
|
|
AZ_Assert(probe.get(), "ShowProbeVisualization called with an invalid handle");
|
|
probe->ShowVisualization(showVisualization);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure)
|
|
{
|
|
AZ_Assert(probe.get(), "SetRenderExposure called with an invalid handle");
|
|
probe->SetRenderExposure(renderExposure);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure)
|
|
{
|
|
AZ_Assert(probe.get(), "SetBakeExposure called with an invalid handle");
|
|
probe->SetBakeExposure(bakeExposure);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::FindReflectionProbes(const Vector3& position, ReflectionProbeVector& reflectionProbes)
|
|
{
|
|
reflectionProbes.clear();
|
|
|
|
// simple AABB check to find the reflection probes that contain the position
|
|
for (auto& reflectionProbe : m_reflectionProbes)
|
|
{
|
|
if (reflectionProbe->GetOuterObbWs().Contains(position)
|
|
&& reflectionProbe->GetCubeMapImage()
|
|
&& reflectionProbe->GetCubeMapImage()->IsInitialized())
|
|
{
|
|
reflectionProbes.push_back(reflectionProbe);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::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("ReflectionProbeFeatureProcessor", 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_reflectionRenderData.m_boxIndexBufferView = indexBufferView;
|
|
m_reflectionRenderData.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("ReflectionProbeFeatureProcessor", 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_reflectionRenderData.m_boxPositionBufferView = { { positionBufferView } };
|
|
|
|
AZ::RHI::ValidateStreamBufferViews(m_boxStreamLayout, m_reflectionRenderData.m_boxPositionBufferView);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::LoadShader(
|
|
const char* filePath,
|
|
RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
|
|
Data::Instance<RPI::Shader>& shader,
|
|
RHI::Ptr<RHI::ShaderResourceGroupLayout>& srgLayout,
|
|
RHI::DrawListTag& drawListTag)
|
|
{
|
|
// load shader
|
|
shader = RPI::LoadCriticalShader(filePath);
|
|
AZ_Error("ReflectionProbeFeatureProcessor", shader, "Failed to find asset for shader [%s]", filePath);
|
|
|
|
// store drawlist tag
|
|
drawListTag = shader->GetDrawListTag();
|
|
|
|
// create pipeline state
|
|
pipelineState = aznew RPI::PipelineStateForDraw;
|
|
pipelineState->Init(shader); // uses default shader variant
|
|
pipelineState->SetInputStreamLayout(m_boxStreamLayout);
|
|
pipelineState->SetOutputFromScene(GetParentScene());
|
|
pipelineState->Finalize();
|
|
|
|
// load object shader resource group
|
|
srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Object);
|
|
AZ_Error("ReflectionProbeFeatureProcessor", srgLayout != nullptr, "Failed to find ObjectSrg layout from shader [%s]", filePath);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
|
|
{
|
|
for (auto& reflectionProbe : m_reflectionProbes)
|
|
{
|
|
reflectionProbe->OnRenderPipelinePassesChanged(renderPipeline);
|
|
}
|
|
m_needUpdatePipelineStates = true;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
|
|
{
|
|
m_needUpdatePipelineStates = true;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* pipeline)
|
|
{
|
|
m_needUpdatePipelineStates = true;
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::UpdatePipelineStates()
|
|
{
|
|
auto scene = GetParentScene();
|
|
|
|
m_reflectionRenderData.m_stencilPipelineState->SetOutputFromScene(scene);
|
|
m_reflectionRenderData.m_stencilPipelineState->Finalize();
|
|
|
|
m_reflectionRenderData.m_blendWeightPipelineState->SetOutputFromScene(scene);
|
|
m_reflectionRenderData.m_blendWeightPipelineState->Finalize();
|
|
|
|
m_reflectionRenderData.m_renderOuterPipelineState->SetOutputFromScene(scene);
|
|
m_reflectionRenderData.m_renderOuterPipelineState->Finalize();
|
|
|
|
m_reflectionRenderData.m_renderInnerPipelineState->SetOutputFromScene(scene);
|
|
m_reflectionRenderData.m_renderInnerPipelineState->Finalize();
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::HandleAssetNotification(Data::Asset<Data::AssetData> asset, CubeMapAssetNotificationType notificationType)
|
|
{
|
|
for (NotifyCubeMapAssetVector::iterator itNotification = m_notifyCubeMapAssets.begin(); itNotification != m_notifyCubeMapAssets.end(); ++itNotification)
|
|
{
|
|
if (itNotification->m_assetId == asset.GetId())
|
|
{
|
|
// store the cubemap 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 ReflectionProbeFeatureProcessor::OnAssetReady(Data::Asset<Data::AssetData> asset)
|
|
{
|
|
HandleAssetNotification(asset, CubeMapAssetNotificationType::Ready);
|
|
}
|
|
|
|
void ReflectionProbeFeatureProcessor::OnAssetError(Data::Asset<Data::AssetData> asset)
|
|
{
|
|
AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str());
|
|
|
|
HandleAssetNotification(asset, CubeMapAssetNotificationType::Error);
|
|
}
|
|
} // namespace Render
|
|
} // namespace AZ
|