Added Occlusion Culling Planes and RPI Culling support for Masked Occlusion Culling

This commit is contained in:
Doug McDiarmid
2021-05-26 19:18:18 -07:00
parent 29163fba1a
commit 17e9c17f31
23 changed files with 913 additions and 50 deletions
@@ -0,0 +1,41 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/Math/Transform.h>
#include <Atom/RPI.Public/FeatureProcessor.h>
namespace AZ
{
namespace Render
{
class OcclusionCullingPlane;
using OcclusionCullingPlaneHandle = AZStd::shared_ptr<OcclusionCullingPlane>;
// OcclusionCullingPlaneFeatureProcessorInterface provides an interface to the feature processor for code outside of Atom
class OcclusionCullingPlaneFeatureProcessorInterface
: public RPI::FeatureProcessor
{
public:
AZ_RTTI(AZ::Render::OcclusionCullingPlaneFeatureProcessorInterface, "{50F6B45E-A622-44EC-B962-DE25FBD44095}");
virtual OcclusionCullingPlaneHandle AddOcclusionCullingPlane(const AZ::Transform& transform) = 0;
virtual void RemoveOcclusionCullingPlane(OcclusionCullingPlaneHandle& handle) = 0;
virtual bool IsValidOcclusionCullingPlaneHandle(const OcclusionCullingPlaneHandle& occlusionCullingPlane) const = 0;
virtual void SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) = 0;
virtual void SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled) = 0;
};
} // namespace Render
} // namespace AZ
@@ -102,6 +102,7 @@
#include <ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.h>
#include <ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h>
namespace AZ
{
@@ -137,6 +138,7 @@ namespace AZ
ModelPreset::Reflect(context);
DiffuseProbeGridFeatureProcessor::Reflect(context);
RayTracingFeatureProcessor::Reflect(context);
OcclusionCullingPlaneFeatureProcessor::Reflect(context);
if (SerializeContext* serialize = azrtti_cast<SerializeContext*>(context))
{
@@ -193,6 +195,7 @@ namespace AZ
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<SMAAFeatureProcessor>();
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<RayTracingFeatureProcessor>();
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<OcclusionCullingPlaneFeatureProcessor>();
// Add SkyBox pass
auto* passSystem = RPI::PassSystemInterface::Get();
@@ -295,6 +298,7 @@ namespace AZ
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<SkyBoxFeatureProcessor>();
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<TransformServiceFeatureProcessor>();
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<AuxGeomFeatureProcessor>();
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<OcclusionCullingPlaneFeatureProcessor>();
}
void CommonSystemComponent::LoadPassTemplateMappings()
@@ -0,0 +1,96 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Culling.h>
namespace AZ
{
namespace Render
{
void OcclusionCullingPlaneFeatureProcessor::Reflect(ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext
->Class<OcclusionCullingPlaneFeatureProcessor, FeatureProcessor>()
->Version(0);
}
}
void OcclusionCullingPlaneFeatureProcessor::Activate()
{
m_occlusionCullingPlanes.reserve(InitialOcclusionCullingPlanesAllocationSize);
EnableSceneNotification();
}
void OcclusionCullingPlaneFeatureProcessor::Deactivate()
{
AZ_Warning("OcclusionCullingPlaneFeatureProcessor", m_occlusionCullingPlanes.size() == 0,
"Deactivating the OcclusionCullingPlaneFeatureProcessor, but there are still outstanding occlusion planes. Components\n"
"using OcclusionCullingPlaneHandles should free them before the OcclusionCullingPlaneFeatureProcessor is deactivated.\n"
);
DisableSceneNotification();
}
void OcclusionCullingPlaneFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
AZStd::vector<AZ::Transform> occlusionCullingPlanes;
for (auto& occlusionCullingPlane : m_occlusionCullingPlanes)
{
occlusionCullingPlanes.push_back(occlusionCullingPlane->GetTransform());
}
GetParentScene()->GetCullingScene()->SetOcclusionCullingPlanes(occlusionCullingPlanes);
}
OcclusionCullingPlaneHandle OcclusionCullingPlaneFeatureProcessor::AddOcclusionCullingPlane(const AZ::Transform& transform)
{
AZStd::shared_ptr<OcclusionCullingPlane> occlusionCullingPlane = AZStd::make_shared<OcclusionCullingPlane>();
occlusionCullingPlane->SetTransform(transform);
m_occlusionCullingPlanes.push_back(occlusionCullingPlane);
return occlusionCullingPlane;
}
void OcclusionCullingPlaneFeatureProcessor::RemoveOcclusionCullingPlane(OcclusionCullingPlaneHandle& occlusionCullingPlane)
{
AZ_Assert(occlusionCullingPlane.get(), "RemoveOcclusionCullingPlane called with an invalid handle");
auto itEntry = AZStd::find_if(m_occlusionCullingPlanes.begin(), m_occlusionCullingPlanes.end(), [&](AZStd::shared_ptr<OcclusionCullingPlane> const& entry)
{
return (entry == occlusionCullingPlane);
});
AZ_Assert(itEntry != m_occlusionCullingPlanes.end(), "RemoveOcclusionCullingPlane called with an occlusion plane that is not in the occlusion plane list");
m_occlusionCullingPlanes.erase(itEntry);
occlusionCullingPlane = nullptr;
}
void OcclusionCullingPlaneFeatureProcessor::SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform)
{
AZ_Assert(occlusionCullingPlane.get(), "SetTransform called with an invalid handle");
occlusionCullingPlane->SetTransform(transform);
}
void OcclusionCullingPlaneFeatureProcessor::SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled)
{
AZ_Assert(occlusionCullingPlane.get(), "Enable called with an invalid handle");
occlusionCullingPlane->SetEnabled(enabled);
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,75 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h>
namespace AZ
{
namespace Render
{
//! This class represents an OcclusionCullingPlane which is used to cull meshes that are inside the view frustum
class OcclusionCullingPlane final
{
public:
OcclusionCullingPlane() = default;
~OcclusionCullingPlane() = default;
void SetTransform(const AZ::Transform& transform) { m_transform = transform; }
const AZ::Transform& GetTransform() const { return m_transform; }
void SetEnabled(bool enabled) { m_enabled = enabled; }
bool GetEnabled() const { return m_enabled; }
private:
AZ::Transform m_transform;
bool m_enabled = true;
};
//! This class manages OcclusionCullingPlanes which are used to cull meshes that are inside the view frustum
class OcclusionCullingPlaneFeatureProcessor final
: public OcclusionCullingPlaneFeatureProcessorInterface
{
public:
AZ_RTTI(AZ::Render::OcclusionCullingPlaneFeatureProcessor, "{C3DE91D7-EF7A-4A82-A55F-E22BC52074EA}", OcclusionCullingPlaneFeatureProcessorInterface);
static void Reflect(AZ::ReflectContext* context);
OcclusionCullingPlaneFeatureProcessor() = default;
virtual ~OcclusionCullingPlaneFeatureProcessor() = default;
// OcclusionCullingPlaneFeatureProcessorInterface overrides
OcclusionCullingPlaneHandle AddOcclusionCullingPlane(const AZ::Transform& transform) override;
void RemoveOcclusionCullingPlane(OcclusionCullingPlaneHandle& handle) override;
bool IsValidOcclusionCullingPlaneHandle(const OcclusionCullingPlaneHandle& occlusionCullingPlane) const override { return (occlusionCullingPlane.get() != nullptr); }
void SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) override;
void SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enable) override;
// FeatureProcessor overrides
void Activate() override;
void Deactivate() override;
void Simulate(const FeatureProcessor::SimulatePacket& packet) override;
// retrieve the full list of occlusion planes
using OcclusionCullingPlaneVector = AZStd::vector<AZStd::shared_ptr<OcclusionCullingPlane>>;
OcclusionCullingPlaneVector& GetOcclusionCullingPlanes() { return m_occlusionCullingPlanes; }
private:
AZ_DISABLE_COPY_MOVE(OcclusionCullingPlaneFeatureProcessor);
// list of occlusion planes
const size_t InitialOcclusionCullingPlanesAllocationSize = 64;
OcclusionCullingPlaneVector m_occlusionCullingPlanes;
};
} // namespace Render
} // namespace AZ
@@ -175,6 +175,8 @@ set(FILES
Source/MorphTargets/MorphTargetComputePass.h
Source/MorphTargets/MorphTargetDispatchItem.cpp
Source/MorphTargets/MorphTargetDispatchItem.h
Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h
Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp
Source/PostProcess/PostProcessBase.cpp
Source/PostProcess/PostProcessBase.h
Source/PostProcess/PostProcessFeatureProcessor.cpp
@@ -44,6 +44,7 @@ set(FILES
Include/Atom/Feature/ParamMacros/StartParamFunctionsVirtual.inl
Include/Atom/Feature/ParamMacros/StartParamMembers.inl
Include/Atom/Feature/ParamMacros/StartParamSerializeContext.inl
Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h
Include/Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h
Include/Atom/Feature/PostProcess/PostProcessParams.inl
Include/Atom/Feature/PostProcess/PostProcessSettings.inl
@@ -31,7 +31,7 @@
#include <AzFramework/Visibility/IVisibilitySystem.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h>
#include <Atom/RHI/DrawList.h>
#include <AtomCore/std/parallel/concurrency_checker.h>
@@ -213,8 +213,11 @@ namespace AZ
void Activate(const class Scene* parentScene);
void Deactivate();
//! Sets a list of occlusion planes to be used during the culling process.
void SetOcclusionCullingPlanes(const AZStd::vector<AZ::Transform>& occlusionCullingPlanes) { m_occlusionCullingPlanes = occlusionCullingPlanes; }
//! Notifies the CullingScene that culling will begin for this frame.
void BeginCulling(const AZStd::vector<ViewPtr>& views);
void BeginCulling(const AZStd::vector<ViewPtr>& views, const AZStd::vector<RenderPipelinePtr>& activePipelines);
//! Notifies the CullingScene that the culling is done for this frame.
void EndCulling();
@@ -251,12 +254,9 @@ namespace AZ
const Scene* m_parentScene = nullptr;
AzFramework::IVisibilityScene* m_visScene = nullptr;
CullingDebugContext m_debugCtx;
AZStd::concurrency_checker m_cullDataConcurrencyCheck;
AZStd::mutex m_mutex;
AZStd::vector<AZ::Transform> m_occlusionCullingPlanes;
};
@@ -18,6 +18,7 @@
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h>
#include <AzCore/Math/Matrix4x4.h>
#include <AzCore/Memory/SystemAllocator.h>
@@ -57,7 +58,7 @@ namespace AZ
//! Only use this function to create a new view object. And force using smart pointer to manage view's life time
static ViewPtr CreateView(const AZ::Name& name, UsageFlags usage);
~View() = default;
~View();
void SetDrawListMask(const RHI::DrawListMask& drawListMask);
RHI::DrawListMask GetDrawListMask() const { return m_drawListMask; }
@@ -126,6 +127,12 @@ namespace AZ
//! Notifies consumers when the world to clip matrix has changed.
void ConnectWorldToClipMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
//! Prepare for view culling
void BeginCulling(const AZStd::vector<RenderPipelinePtr>& activePipelines);
//! Returns the masked occlusion culling interface
MaskedOcclusionCulling* GetMaskedOcclusionCulling();
private:
View() = delete;
View(const AZ::Name& name, UsageFlags usage);
@@ -193,6 +200,9 @@ namespace AZ
MatrixChangedEvent m_onWorldToClipMatrixChange;
MatrixChangedEvent m_onWorldToViewMatrixChange;
// Software occlusion culling
MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr;
};
AZ_DEFINE_ENUM_BITWISE_OPERATORS(View::UsageFlags);
@@ -10,3 +10,16 @@
#
set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED TRUE)
ly_add_source_properties(
SOURCES Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp
PROPERTY COMPILE_OPTIONS
VALUES /arch:AVX2 /W3
)
ly_add_source_properties(
SOURCES
Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp
Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp
PROPERTY COMPILE_OPTIONS
VALUES /W3
)
+130 -41
View File
@@ -262,21 +262,24 @@ namespace AZ
public:
AZ_CLASS_ALLOCATOR(AddObjectsToViewJob, ThreadPoolAllocator, 0);
struct JobData
{
CullingDebugContext* m_debugCtx = nullptr;
MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr;
const Scene* m_scene = nullptr;
View* m_view = nullptr;
Frustum m_frustum;
};
private:
CullingDebugContext* m_debugCtx;
const Scene* m_scene;
View* m_view;
Frustum m_frustum;
const AZStd::shared_ptr<JobData> m_jobData;
CullingScene::WorkListType m_worklist;
public:
AddObjectsToViewJob(CullingDebugContext& debugCtx, const Scene& scene, View& view, Frustum& frustum, CullingScene::WorkListType& worklist)
AddObjectsToViewJob(const AZStd::shared_ptr<AddObjectsToViewJob::JobData>& jobData, CullingScene::WorkListType& worklist)
: Job(true, nullptr) //auto-deletes, no JobContext
, m_debugCtx(&debugCtx)
, m_scene(&scene)
, m_view(&view)
, m_frustum(frustum) //capture by value
, m_worklist(AZStd::move(worklist)) //capture by value
, m_jobData(jobData)
, m_worklist(worklist)
{
}
@@ -285,37 +288,40 @@ namespace AZ
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
const View::UsageFlags viewFlags = m_view->GetUsageFlags();
const RHI::DrawListMask drawListMask = m_view->GetDrawListMask();
const View::UsageFlags viewFlags = m_jobData->m_view->GetUsageFlags();
const RHI::DrawListMask drawListMask = m_jobData->m_view->GetDrawListMask();
uint32_t numDrawPackets = 0;
uint32_t numVisibleCullables = 0;
for (const AzFramework::IVisibilityScene::NodeData& nodeData : m_worklist)
{
//If a node is entirely contained within the frustum, then we can skip the fine grained culling.
bool nodeIsContainedInFrustum = ShapeIntersection::Contains(m_frustum, nodeData.m_bounds);
bool nodeIsContainedInFrustum = ShapeIntersection::Contains(m_jobData->m_frustum, nodeData.m_bounds);
#ifdef AZ_CULL_PROFILE_VERBOSE
AZ_PROFILE_SCOPE_DYNAMIC(Debug::ProfileCategory::AzRender, "process node (view: %s, skip fine cull: %d",
m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0);
#endif
if (nodeIsContainedInFrustum || !m_debugCtx->m_enableFrustumCulling)
if (nodeIsContainedInFrustum || !m_jobData->m_debugCtx->m_enableFrustumCulling)
{
//Add all objects within this node to the view, without any extra culling
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE)
{
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if ((c->m_cullData.m_drawListMask & drawListMask).none() ||
c->m_cullData.m_hideFlags & viewFlags ||
c->m_cullData.m_scene != m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
{
continue;
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if ((c->m_cullData.m_drawListMask & drawListMask).none() ||
c->m_cullData.m_hideFlags & viewFlags ||
c->m_cullData.m_scene != m_jobData->m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
{
continue;
}
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view);
++numVisibleCullables;
}
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_view);
++numVisibleCullables;
}
}
}
@@ -329,66 +335,69 @@ namespace AZ
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if ((c->m_cullData.m_drawListMask & drawListMask).none() ||
c->m_cullData.m_hideFlags & viewFlags ||
c->m_cullData.m_scene != m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
c->m_cullData.m_scene != m_jobData->m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
{
continue;
}
IntersectResult res = ShapeIntersection::Classify(m_frustum, c->m_cullData.m_boundingSphere);
IntersectResult res = ShapeIntersection::Classify(m_jobData->m_frustum, c->m_cullData.m_boundingSphere);
if (res == IntersectResult::Exterior)
{
continue;
}
else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_frustum, c->m_cullData.m_boundingObb))
else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_jobData->m_frustum, c->m_cullData.m_boundingObb))
{
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_view);
++numVisibleCullables;
if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE)
{
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view);
++numVisibleCullables;
}
}
}
}
}
if (m_debugCtx->m_debugDraw && (m_view->GetName() == m_debugCtx->m_currentViewSelectionName))
if (m_jobData->m_debugCtx->m_debugDraw && (m_jobData->m_view->GetName() == m_jobData->m_debugCtx->m_currentViewSelectionName))
{
AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "debug draw culling");
AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_scene);
AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_jobData->m_scene);
if (auxGeomPtr)
{
//Draw the node bounds
// "Fully visible" nodes are nodes that are fully inside the frustum. "Partially visible" nodes intersect the edges of the frustum.
// Since the nodes of an octree have lots of overlapping boxes with coplanar edges, it's easier to view these separately, so
// we have a few debug booleans to toggle which ones to draw.
if (nodeIsContainedInFrustum && m_debugCtx->m_drawFullyVisibleNodes)
if (nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawFullyVisibleNodes)
{
auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Lime, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off);
}
else if (!nodeIsContainedInFrustum && m_debugCtx->m_drawPartiallyVisibleNodes)
else if (!nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawPartiallyVisibleNodes)
{
auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Yellow, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off);
}
//Draw bounds on individual objects
if (m_debugCtx->m_drawBoundingBoxes || m_debugCtx->m_drawBoundingSpheres || m_debugCtx->m_drawLodRadii)
if (m_jobData->m_debugCtx->m_drawBoundingBoxes || m_jobData->m_debugCtx->m_drawBoundingSpheres || m_jobData->m_debugCtx->m_drawLodRadii)
{
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
{
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if (m_debugCtx->m_drawBoundingBoxes)
if (m_jobData->m_debugCtx->m_drawBoundingBoxes)
{
auxGeomPtr->DrawObb(c->m_cullData.m_boundingObb, Matrix3x4::Identity(),
nodeIsContainedInFrustum ? Colors::Lime : Colors::Yellow, AuxGeomDraw::DrawStyle::Line);
}
if (m_debugCtx->m_drawBoundingSpheres)
if (m_jobData->m_debugCtx->m_drawBoundingSpheres)
{
auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_cullData.m_boundingSphere.GetRadius(),
Color(0.5f, 0.5f, 0.5f, 0.3f), AuxGeomDraw::DrawStyle::Shaded);
}
if (m_debugCtx->m_drawLodRadii)
if (m_jobData->m_debugCtx->m_drawLodRadii)
{
auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(),
c->m_lodData.m_lodSelectionRadius,
@@ -401,9 +410,9 @@ namespace AZ
}
}
if (m_debugCtx->m_enableStats)
if (m_jobData->m_debugCtx->m_enableStats)
{
CullingDebugContext::CullStats& cullStats = m_debugCtx->GetCullStatsForView(m_view);
CullingDebugContext::CullStats& cullStats = m_jobData->m_debugCtx->GetCullStatsForView(m_jobData->m_view);
//no need for mutex here since these are all atomics
cullStats.m_numVisibleDrawPackets += numDrawPackets;
@@ -411,6 +420,29 @@ namespace AZ
++cullStats.m_numJobs;
}
}
MaskedOcclusionCulling::CullingResult TestOcclusionCulling(AzFramework::VisibilityEntry* visibleEntry)
{
if (!m_jobData->m_maskedOcclusionCulling)
{
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
// convert the bounding box of the visibility entry to NDC
AZ::Vector4 clipSpaceMin = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(visibleEntry->m_boundingVolume.GetMin());
float depth = clipSpaceMin.GetW();
AZ::Vector4 ndcMin = clipSpaceMin / clipSpaceMin.GetW();
AZ::Vector4 clipSpaceMax = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(visibleEntry->m_boundingVolume.GetMax());
depth = AZStd::min(depth, clipSpaceMax.GetW());
AZ::Vector4 ndcMax = clipSpaceMax / clipSpaceMax.GetW();
Vector2 rectMin(AZStd::min(ndcMin.GetX(), ndcMax.GetX()), AZStd::min(ndcMin.GetY(), ndcMax.GetY()));
Vector2 rectMax(AZStd::max(ndcMin.GetX(), ndcMax.GetX()), AZStd::max(ndcMin.GetY(), ndcMax.GetY()));
// test against the occlusion buffer, which contains only the manually placed occlusion planes
return m_jobData->m_maskedOcclusionCulling->TestRect(rectMin.GetX(), rectMin.GetY(), rectMax.GetX(), rectMax.GetY(), depth);
}
};
void CullingScene::ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob)
@@ -444,8 +476,53 @@ namespace AZ
cullStats.m_cameraViewToWorld = view.GetViewToWorldMatrix();
}
// setup occlusion culling, if necessary
MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
if (maskedOcclusionCulling)
{
for (const AZ::Transform& transform : m_occlusionCullingPlanes)
{
// find the corners of the plane
static const Vector3 BL = Vector3(-0.5f, -0.5f, 0.0f);
static const Vector3 BR = Vector3(0.5f, -0.5f, 0.0f);
static const Vector3 TL = Vector3(-0.5f, 0.5f, 0.0f);
static const Vector3 TR = Vector3(0.5f, 0.5f, 0.0f);
Vector3 planeBL = transform.TransformPoint(BL);
Vector3 planeBR = transform.TransformPoint(BR);
Vector3 planeTL = transform.TransformPoint(TL);
Vector3 planeTR = transform.TransformPoint(TR);
// convert to clip-space
Vector4 projectedBL = view.GetWorldToClipMatrix() * Vector4(planeBL);
Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(planeBR);
Vector4 projectedTL = view.GetWorldToClipMatrix() * Vector4(planeTL);
Vector4 projectedTR = view.GetWorldToClipMatrix() * Vector4(planeTR);
// store to float array
float verts[16];
projectedBL.StoreToFloat4(&verts[0]);
projectedBR.StoreToFloat4(&verts[4]);
projectedTL.StoreToFloat4(&verts[8]);
projectedTR.StoreToFloat4(&verts[12]);
static uint32_t indices[6] = { 0, 2, 1, 2, 3, 1 };
// render into the occlusion buffer, specifying BACKFACE_NONE so it functions as a double-sided occluder
maskedOcclusionCulling->RenderTriangles((float*)verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE);
}
}
WorkListType worklist;
auto nodeVisitorLambda = [this, &scene, &view, &parentJob, &frustum, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void
AZStd::shared_ptr<AddObjectsToViewJob::JobData> jobData = AZStd::make_shared<AddObjectsToViewJob::JobData>();
jobData->m_debugCtx = &m_debugCtx;
jobData->m_maskedOcclusionCulling = maskedOcclusionCulling;
jobData->m_scene = &scene;
jobData->m_view = &view;
jobData->m_frustum = frustum;
auto nodeVisitorLambda = [this, jobData, &parentJob, &frustum, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void
{
AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "nodeVisitorLambda()");
AZ_Assert(nodeData.m_entries.size() > 0, "should not get called with 0 entries");
@@ -458,7 +535,7 @@ namespace AZ
if (worklist.size() == worklist.capacity())
{
//Kick off a job to process the (full) worklist
AddObjectsToViewJob* job = aznew AddObjectsToViewJob(m_debugCtx, scene, view, frustum, worklist); //pool allocated (cheap), auto-deletes when job finishes
AddObjectsToViewJob* job = aznew AddObjectsToViewJob(jobData, worklist); //pool allocated (cheap), auto-deletes when job finishes
worklist.clear();
parentJob.SetContinuation(job);
job->Start();
@@ -476,8 +553,15 @@ namespace AZ
if (worklist.size() > 0)
{
AZStd::shared_ptr<AddObjectsToViewJob::JobData> remainingJobData = AZStd::make_shared<AddObjectsToViewJob::JobData>();
remainingJobData->m_debugCtx = &m_debugCtx;
remainingJobData->m_maskedOcclusionCulling = maskedOcclusionCulling;
remainingJobData->m_scene = &scene;
remainingJobData->m_view = &view;
remainingJobData->m_frustum = frustum;
//Kick off a job to process any remaining workitems
AddObjectsToViewJob* job = aznew AddObjectsToViewJob(m_debugCtx, scene, view, frustum, worklist); //pool allocated (cheap), auto-deletes when job finishes
AddObjectsToViewJob* job = aznew AddObjectsToViewJob(remainingJobData, worklist); //pool allocated (cheap), auto-deletes when job finishes
parentJob.SetContinuation(job);
job->Start();
}
@@ -559,13 +643,18 @@ namespace AZ
}
}
void CullingScene::BeginCulling(const AZStd::vector<ViewPtr>& views)
void CullingScene::BeginCulling(const AZStd::vector<ViewPtr>& views, const AZStd::vector<RenderPipelinePtr>& activePipelines)
{
m_cullDataConcurrencyCheck.soft_lock();
m_debugCtx.ResetCullStats();
m_debugCtx.m_numCullablesInScene = GetNumCullables();
for (auto& view : views)
{
view->BeginCulling(activePipelines);
}
AuxGeomDrawPtr auxGeom;
if (m_debugCtx.m_debugDraw)
{
@@ -23,6 +23,7 @@
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Jobs/JobFunction.h>
@@ -499,7 +500,7 @@ namespace AZ
}
// Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs)
m_cullingScene->BeginCulling(m_renderPacket.m_views);
m_cullingScene->BeginCulling(m_renderPacket.m_views, activePipelines);
for (ViewPtr& viewPtr : m_renderPacket.m_views)
{
AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob)
+67 -1
View File
@@ -15,7 +15,8 @@
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Culling.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
#include <Atom/RHI/DrawListTagRegistry.h>
#include <AzCore/Casting/lossy_cast.h>
@@ -51,6 +52,18 @@ namespace AZ
{
m_shaderResourceGroup = ShaderResourceGroup::Create(viewSrgAsset);
}
m_maskedOcclusionCulling = MaskedOcclusionCulling::Create();
m_maskedOcclusionCulling->SetNearClipPlane(0.1f);
}
View::~View()
{
if (m_maskedOcclusionCulling)
{
MaskedOcclusionCulling::Destroy(m_maskedOcclusionCulling);
m_maskedOcclusionCulling = nullptr;
}
}
void View::SetDrawListMask(const RHI::DrawListMask& drawListMask)
@@ -374,5 +387,58 @@ namespace AZ
m_shaderResourceGroup->Compile();
m_needBuildSrg = false;
}
void View::BeginCulling(const AZStd::vector<RenderPipelinePtr>& activePipelines)
{
// retrieve current resolution
Vector2 resolution(0.0f, 0.0f);
for (auto& pipeline : activePipelines)
{
ViewPtr pipelineView = pipeline->GetDefaultView();
if (pipelineView.get() == this)
{
RPI::SwapChainPass* pass = AZ::RPI::PassSystemInterface::Get()->FindSwapChainPass(pipeline->GetWindowHandle());
if (pass)
{
const RHI::Viewport& viewport = pass->GetViewport();
resolution.SetX(viewport.m_maxX);
resolution.SetY(viewport.m_maxY);
}
break;
}
}
// calculate culling resolution based on required tile size for MaskedOcclusionCulling
static const uint32_t MaskedOcclusionCullingSubTileWidth = 8;
static const uint32_t MaskedOcclusionCullingSubTileHeight = 4;
uint32_t cullingWidth = RHI::AlignUp(resolution.GetX(), MaskedOcclusionCullingSubTileWidth);
uint32_t cullingHeight = RHI::AlignUp(resolution.GetY(), MaskedOcclusionCullingSubTileHeight);
m_maskedOcclusionCulling->SetResolution(cullingWidth, cullingHeight);
if (cullingWidth > 0 && cullingHeight > 0)
{
m_maskedOcclusionCulling->ClearBuffer();
}
}
MaskedOcclusionCulling* View::GetMaskedOcclusionCulling()
{
if (m_maskedOcclusionCulling)
{
uint32_t width = 0;
uint32_t height = 0;
m_maskedOcclusionCulling->GetResolution(width, height);
if (width > 0 && height > 0)
{
return m_maskedOcclusionCulling;
}
}
return nullptr;
}
} // namespace RPI
} // namespace AZ
@@ -101,6 +101,7 @@ set(FILES
Include/Atom/RPI.Public/GpuQuery/Query.h
Include/Atom/RPI.Public/GpuQuery/QueryPool.h
Include/Atom/RPI.Public/GpuQuery/TimestampQueryPool.h
Include/Atom/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h
Source/RPI.Public/Culling.cpp
Source/RPI.Public/FeatureProcessor.cpp
Source/RPI.Public/FeatureProcessorFactory.cpp
@@ -178,4 +179,7 @@ set(FILES
Source/RPI.Public/GpuQuery/Query.cpp
Source/RPI.Public/GpuQuery/QueryPool.cpp
Source/RPI.Public/GpuQuery/TimestampQueryPool.cpp
Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp
Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp
Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp
)
@@ -24,6 +24,7 @@
#include <Material/MaterialComponent.h>
#include <Mesh/MeshComponent.h>
#include <ReflectionProbe/ReflectionProbeComponent.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponent.h>
#include <PostProcess/PostFxLayerComponent.h>
#include <PostProcess/Bloom/BloomComponent.h>
#include <PostProcess/DepthOfField/DepthOfFieldComponent.h>
@@ -55,6 +56,7 @@
#include <Mesh/EditorMeshComponent.h>
#include <Mesh/EditorMeshSystemComponent.h>
#include <ReflectionProbe/EditorReflectionProbeComponent.h>
#include <OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h>
#include <PostProcess/EditorPostFxLayerComponent.h>
#include <PostProcess/Bloom/EditorBloomComponent.h>
#include <PostProcess/DepthOfField/EditorDepthOfFieldComponent.h>
@@ -114,6 +116,7 @@ namespace AZ
DeferredFogComponent::CreateDescriptor(),
SurfaceData::SurfaceDataMeshComponent::CreateDescriptor(),
AttachmentComponent::CreateDescriptor(),
OcclusionCullingPlaneComponent::CreateDescriptor(),
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
EditorAreaLightComponent::CreateDescriptor(),
@@ -145,6 +148,7 @@ namespace AZ
EditorDeferredFogComponent::CreateDescriptor(),
SurfaceData::EditorSurfaceDataMeshComponent::CreateDescriptor(),
EditorAttachmentComponent::CreateDescriptor(),
EditorOcclusionCullingPlaneComponent::CreateDescriptor(),
#endif
});
}
@@ -0,0 +1,91 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/Component/Entity.h>
namespace AZ
{
namespace Render
{
void EditorOcclusionCullingPlaneComponent::Reflect(AZ::ReflectContext* context)
{
BaseClass::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorOcclusionCullingPlaneComponent, BaseClass>()
->Version(1, ConvertToEditorRenderComponentAdapter<1>)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorOcclusionCullingPlaneComponent>(
"Occlusion Culling Plane", "The OcclusionCullingPlane component is used to cull meshes that are inside the view frustum and behind the occlusion plane")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Atom")
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
editContext->Class<OcclusionCullingPlaneComponentController>(
"OcclusionCullingPlaneComponentController", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &OcclusionCullingPlaneComponentController::m_configuration, "Configuration", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
editContext->Class<OcclusionCullingPlaneComponentConfig>(
"OcclusionCullingPlaneComponentConfig", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->ConstantProperty("EditorOcclusionCullingPlaneComponentTypeId", BehaviorConstant(Uuid(EditorOcclusionCullingPlaneComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
}
}
EditorOcclusionCullingPlaneComponent::EditorOcclusionCullingPlaneComponent()
{
}
EditorOcclusionCullingPlaneComponent::EditorOcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config)
: BaseClass(config)
{
}
void EditorOcclusionCullingPlaneComponent::Activate()
{
BaseClass::Activate();
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
}
void EditorOcclusionCullingPlaneComponent::Deactivate()
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
BaseClass::Deactivate();
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponent.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h>
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
namespace AZ
{
namespace Render
{
class EditorOcclusionCullingPlaneComponent final
: public EditorRenderComponentAdapter<OcclusionCullingPlaneComponentController, OcclusionCullingPlaneComponent, OcclusionCullingPlaneComponentConfig>
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
using BaseClass = EditorRenderComponentAdapter<OcclusionCullingPlaneComponentController, OcclusionCullingPlaneComponent, OcclusionCullingPlaneComponentConfig>;
AZ_EDITOR_COMPONENT(AZ::Render::EditorOcclusionCullingPlaneComponent, EditorOcclusionCullingPlaneComponentTypeId, BaseClass);
static void Reflect(AZ::ReflectContext* context);
EditorOcclusionCullingPlaneComponent();
EditorOcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config);
// AZ::Component overrides
void Activate() override;
void Deactivate() override;
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponent.h>
namespace AZ
{
namespace Render
{
OcclusionCullingPlaneComponent::OcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config)
: BaseClass(config)
{
}
void OcclusionCullingPlaneComponent::Reflect(AZ::ReflectContext* context)
{
BaseClass::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<OcclusionCullingPlaneComponent, BaseClass>()
->Version(0)
;
}
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->ConstantProperty("OcclusionCullingPlaneComponentTypeId", BehaviorConstant(Uuid(OcclusionCullingPlaneComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common);
}
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h>
#include <AzFramework/Components/ComponentAdapter.h>
namespace AZ
{
namespace Render
{
class OcclusionCullingPlaneComponent final
: public AzFramework::Components::ComponentAdapter<OcclusionCullingPlaneComponentController, OcclusionCullingPlaneComponentConfig>
{
public:
using BaseClass = AzFramework::Components::ComponentAdapter<OcclusionCullingPlaneComponentController, OcclusionCullingPlaneComponentConfig>;
AZ_COMPONENT(AZ::Render::OcclusionCullingPlaneComponent, OcclusionCullingPlaneComponentTypeId, BaseClass);
OcclusionCullingPlaneComponent() = default;
OcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config);
static void Reflect(AZ::ReflectContext* context);
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,22 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
namespace AZ
{
namespace Render
{
static constexpr const char* const OcclusionCullingPlaneComponentTypeId = "{F7537387-15A8-48F0-A1F3-D19C5886B886}";
static constexpr const char* const EditorOcclusionCullingPlaneComponentTypeId = "{BE7CC17B-32EB-49B0-BAD9-D26E3A059012}";
} // namespace Render
} // namespace AZ
@@ -0,0 +1,137 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/RPI.Public/Scene.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzFramework/Entity/EntityContext.h>
#include <AzFramework/Scene/Scene.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
namespace Render
{
void OcclusionCullingPlaneComponentConfig::Reflect(ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<OcclusionCullingPlaneComponentConfig>()
->Version(0)
;
}
}
void OcclusionCullingPlaneComponentController::Reflect(ReflectContext* context)
{
OcclusionCullingPlaneComponentConfig::Reflect(context);
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<OcclusionCullingPlaneComponentController>()
->Version(0)
->Field("Configuration", &OcclusionCullingPlaneComponentController::m_configuration);
}
}
void OcclusionCullingPlaneComponentController::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
void OcclusionCullingPlaneComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x9123f33d));
}
void OcclusionCullingPlaneComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x9123f33d));
}
void OcclusionCullingPlaneComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService"));
}
OcclusionCullingPlaneComponentController::OcclusionCullingPlaneComponentController(const OcclusionCullingPlaneComponentConfig& config)
: m_configuration(config)
{
}
void OcclusionCullingPlaneComponentController::Activate(AZ::EntityId entityId)
{
m_entityId = entityId;
TransformNotificationBus::Handler::BusConnect(m_entityId);
m_featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<OcclusionCullingPlaneFeatureProcessorInterface>(entityId);
AZ_Assert(m_featureProcessor, "OcclusionCullingPlaneComponentController was unable to find a OcclusionCullingPlaneFeatureProcessor on the EntityContext provided.");
m_transformInterface = TransformBus::FindFirstHandler(entityId);
AZ_Assert(m_transformInterface, "Unable to attach to a TransformBus handler");
if (!m_transformInterface)
{
return;
}
// add this occlusion plane to the feature processor
const AZ::Transform& transform = m_transformInterface->GetWorldTM();
m_handle = m_featureProcessor->AddOcclusionCullingPlane(transform);
}
void OcclusionCullingPlaneComponentController::Deactivate()
{
if (m_featureProcessor)
{
m_featureProcessor->RemoveOcclusionCullingPlane(m_handle);
}
Data::AssetBus::MultiHandler::BusDisconnect();
TransformNotificationBus::Handler::BusDisconnect();
m_transformInterface = nullptr;
m_featureProcessor = nullptr;
}
void OcclusionCullingPlaneComponentController::SetConfiguration(const OcclusionCullingPlaneComponentConfig& config)
{
m_configuration = config;
}
const OcclusionCullingPlaneComponentConfig& OcclusionCullingPlaneComponentController::GetConfiguration() const
{
return m_configuration;
}
void OcclusionCullingPlaneComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
{
if (!m_featureProcessor)
{
return;
}
m_featureProcessor->SetTransform(m_handle, world);
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,78 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h>
namespace AZ
{
namespace Render
{
class OcclusionCullingPlaneComponentConfig final
: public AZ::ComponentConfig
{
public:
AZ_RTTI(AZ::Render::OcclusionCullingPlaneComponentConfig, "{D0E107CA-5AFB-4675-BC97-94BCA5F248DB}", ComponentConfig);
AZ_CLASS_ALLOCATOR(OcclusionCullingPlaneComponentConfig, SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
OcclusionCullingPlaneComponentConfig() = default;
};
class OcclusionCullingPlaneComponentController final
: public Data::AssetBus::MultiHandler
, private TransformNotificationBus::Handler
{
public:
friend class EditorOcclusionCullingPlaneComponent;
AZ_CLASS_ALLOCATOR(OcclusionCullingPlaneComponentController, AZ::SystemAllocator, 0);
AZ_RTTI(AZ::Render::OcclusionCullingPlaneComponentController, "{8EDA3C7D-5171-4843-9969-4D84DB13F221}");
static void Reflect(AZ::ReflectContext* context);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
OcclusionCullingPlaneComponentController() = default;
OcclusionCullingPlaneComponentController(const OcclusionCullingPlaneComponentConfig& config);
void Activate(AZ::EntityId entityId);
void Deactivate();
void SetConfiguration(const OcclusionCullingPlaneComponentConfig& config);
const OcclusionCullingPlaneComponentConfig& GetConfiguration() const;
private:
AZ_DISABLE_COPY(OcclusionCullingPlaneComponentController);
// TransformNotificationBus overrides
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
// handle for this occlusion plane in the feature processor
OcclusionCullingPlaneHandle m_handle;
OcclusionCullingPlaneFeatureProcessorInterface* m_featureProcessor = nullptr;
TransformInterface* m_transformInterface = nullptr;
AZ::EntityId m_entityId;
OcclusionCullingPlaneComponentConfig m_configuration;
};
} // namespace Render
} // namespace AZ
@@ -53,6 +53,8 @@ set(FILES
Source/Mesh/EditorMeshSystemComponent.h
Source/Mesh/MeshThumbnail.h
Source/Mesh/MeshThumbnail.cpp
Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h
Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp
Source/PostProcess/EditorPostFxLayerComponent.cpp
Source/PostProcess/EditorPostFxLayerComponent.h
Source/PostProcess/Bloom/EditorBloomComponent.cpp
@@ -66,6 +66,10 @@ set(FILES
Source/Mesh/MeshComponent.cpp
Source/Mesh/MeshComponentController.h
Source/Mesh/MeshComponentController.cpp
Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.h
Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.cpp
Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h
Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp
Source/PostProcess/PostFxLayerComponent.cpp
Source/PostProcess/PostFxLayerComponent.h
Source/PostProcess/PostFxLayerComponentConfig.cpp