Cached occlusion plane corner points and AABB in the feature processor

This commit is contained in:
Doug McDiarmid
2021-06-03 16:02:16 -07:00
parent c63d83859d
commit 792176d764
4 changed files with 76 additions and 44 deletions
@@ -33,6 +33,7 @@ namespace AZ
void OcclusionCullingPlaneFeatureProcessor::Activate()
{
m_occlusionCullingPlanes.reserve(InitialOcclusionCullingPlanesAllocationSize);
m_rpiOcclusionPlanes.reserve(InitialOcclusionCullingPlanesAllocationSize);
EnableSceneNotification();
}
@@ -48,13 +49,46 @@ namespace AZ
}
void OcclusionCullingPlaneFeatureProcessor::OnBeginPrepareRender()
{
AZStd::vector<AZ::Transform> occlusionCullingPlanes;
for (auto& occlusionCullingPlane : m_occlusionCullingPlanes)
{
if (m_rpiListNeedsUpdate)
{
occlusionCullingPlanes.push_back(occlusionCullingPlane->GetTransform());
// rebuild the RPI occlusion list
m_rpiOcclusionPlanes.clear();
for (auto& occlusionCullingPlane : m_occlusionCullingPlanes)
{
if (!occlusionCullingPlane->GetEnabled())
{
continue;
}
RPI::CullingScene::OcclusionPlane rpiOcclusionPlane;
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);
const AZ::Transform& transform = occlusionCullingPlane->GetTransform();
// convert corners to world space
rpiOcclusionPlane.m_cornerBL = transform.TransformPoint(BL);
rpiOcclusionPlane.m_cornerBR = transform.TransformPoint(BR);
rpiOcclusionPlane.m_cornerTL = transform.TransformPoint(TL);
rpiOcclusionPlane.m_cornerTR = transform.TransformPoint(TR);
// build world space AABB
AZ::Vector3 aabbMin = rpiOcclusionPlane.m_cornerBL.GetMin(rpiOcclusionPlane.m_cornerTR);
AZ::Vector3 aabbMax = rpiOcclusionPlane.m_cornerBL.GetMax(rpiOcclusionPlane.m_cornerTR);
rpiOcclusionPlane.m_aabb = Aabb::CreateFromMinMax(aabbMin, aabbMax);
m_rpiOcclusionPlanes.push_back(rpiOcclusionPlane);
}
GetParentScene()->GetCullingScene()->SetOcclusionPlanes(m_rpiOcclusionPlanes);
m_rpiListNeedsUpdate = false;
}
GetParentScene()->GetCullingScene()->SetOcclusionCullingPlanes(occlusionCullingPlanes);
}
OcclusionCullingPlaneHandle OcclusionCullingPlaneFeatureProcessor::AddOcclusionCullingPlane(const AZ::Transform& transform)
@@ -63,6 +97,8 @@ namespace AZ
occlusionCullingPlane->Init(GetParentScene());
occlusionCullingPlane->SetTransform(transform);
m_occlusionCullingPlanes.push_back(occlusionCullingPlane);
m_rpiListNeedsUpdate = true;
return occlusionCullingPlane;
}
@@ -78,18 +114,21 @@ namespace AZ
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;
m_rpiListNeedsUpdate = true;
}
void OcclusionCullingPlaneFeatureProcessor::SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform)
{
AZ_Assert(occlusionCullingPlane.get(), "SetTransform called with an invalid handle");
occlusionCullingPlane->SetTransform(transform);
m_rpiListNeedsUpdate = true;
}
void OcclusionCullingPlaneFeatureProcessor::SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled)
{
AZ_Assert(occlusionCullingPlane.get(), "Enable called with an invalid handle");
occlusionCullingPlane->SetEnabled(enabled);
m_rpiListNeedsUpdate = true;
}
void OcclusionCullingPlaneFeatureProcessor::ShowVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool showVisualization)
@@ -57,6 +57,10 @@ namespace AZ
// list of occlusion planes
const size_t InitialOcclusionCullingPlanesAllocationSize = 64;
OcclusionCullingPlaneVector m_occlusionCullingPlanes;
// prebuilt list of RPI scene occlusion planes
RPI::CullingScene::OcclusionPlaneVector m_rpiOcclusionPlanes;
bool m_rpiListNeedsUpdate = false;
};
} // namespace Render
} // namespace AZ
@@ -215,8 +215,20 @@ namespace AZ
void Activate(const class Scene* parentScene);
void Deactivate();
struct OcclusionPlane
{
// World space corners of the occluson plane
Vector3 m_cornerBL;
Vector3 m_cornerBR;
Vector3 m_cornerTL;
Vector3 m_cornerTR;
Aabb m_aabb;
};
using OcclusionPlaneVector = AZStd::vector<OcclusionPlane>;
//! Sets a list of occlusion planes to be used during the culling process.
void SetOcclusionCullingPlanes(const AZStd::vector<AZ::Transform>& occlusionCullingPlanes) { m_occlusionCullingPlanes = occlusionCullingPlanes; }
void SetOcclusionPlanes(const OcclusionPlaneVector& occlusionPlanes) { m_occlusionPlanes = occlusionPlanes; }
//! Notifies the CullingScene that culling will begin for this frame.
void BeginCulling(const AZStd::vector<ViewPtr>& views);
@@ -258,7 +270,7 @@ namespace AZ
AzFramework::IVisibilityScene* m_visScene = nullptr;
CullingDebugContext m_debugCtx;
AZStd::concurrency_checker m_cullDataConcurrencyCheck;
AZStd::vector<AZ::Transform> m_occlusionCullingPlanes;
OcclusionPlaneVector m_occlusionPlanes;
};
@@ -546,60 +546,37 @@ namespace AZ
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
// setup occlusion culling, if necessary
MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
if (maskedOcclusionCulling)
{
// frustum cull occlusion planes
using OccluderEntry = AZStd::pair<AZ::Transform, float>;
AZStd::vector<OccluderEntry> visibleOccluders;
for (const AZ::Transform& transform : m_occlusionCullingPlanes)
using VisibleOcclusionPlane = AZStd::pair<OcclusionPlane, float>;
AZStd::vector<VisibleOcclusionPlane> visibleOccluders;
for (const auto& occlusionPlane : m_occlusionPlanes)
{
static const AZ::Vector3 BL(-0.5f, -0.5f, 0.0f);
static const AZ::Vector3 TR(0.5f, 0.5f, 0.0f);
AZ::Vector3 P1 = transform.TransformPoint(BL);
AZ::Vector3 P2 = transform.TransformPoint(TR);
AZ::Vector3 aabbMin = P1.GetMin(P2);
AZ::Vector3 aabbMax = P1.GetMax(P2);
AZ::Aabb occluderAabb = Aabb::CreateFromMinMax(aabbMin, aabbMax);
if (ShapeIntersection::Overlaps(frustum, occluderAabb))
if (ShapeIntersection::Overlaps(frustum, occlusionPlane.m_aabb))
{
// occluder is visible, compute view space distance and add to list
float depth = (view.GetWorldToViewMatrix() * occluderAabb.GetMin()).GetZ();
depth = AZStd::min(depth, (view.GetWorldToViewMatrix() * occluderAabb.GetMax()).GetZ());
float depth = (view.GetWorldToViewMatrix() * occlusionPlane.m_aabb.GetMin()).GetZ();
depth = AZStd::min(depth, (view.GetWorldToViewMatrix() * occlusionPlane.m_aabb.GetMax()).GetZ());
visibleOccluders.push_back(AZStd::make_pair(transform, depth));
visibleOccluders.push_back(AZStd::make_pair(occlusionPlane, depth));
}
}
// sort the occlusion planes by view space distance, front-to-back
AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const OccluderEntry& LHS, const OccluderEntry& RHS)
AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const VisibleOcclusionPlane& LHS, const VisibleOcclusionPlane& RHS)
{
return LHS.second > RHS.second;
});
for (const OccluderEntry& occluder : visibleOccluders)
for (const VisibleOcclusionPlane& occlusionPlane: visibleOccluders)
{
const AZ::Transform& transform = occluder.first;
// 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);
Vector4 projectedBL = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBL);
Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBR);
Vector4 projectedTL = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerTL);
Vector4 projectedTR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerTR);
// store to float array
float verts[16];