Added occlusion culling plane visualization

This commit is contained in:
Doug McDiarmid
2021-05-31 01:38:13 -07:00
parent ddbed2f222
commit 59ab6edaef
14 changed files with 321 additions and 37 deletions
@@ -428,20 +428,52 @@ namespace AZ
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();
if (visibleEntry->m_boundingVolume.Contains(m_jobData->m_view->GetCameraTransform().GetTranslation()))
{
// camera is inside bounding volume
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
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();
const Vector3& minBound = visibleEntry->m_boundingVolume.GetMin();
const Vector3& maxBound = visibleEntry->m_boundingVolume.GetMax();
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()));
// compute bounding volume corners
Vector4 corners[8];
corners[0] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f);
corners[1] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f);
corners[2] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f);
corners[3] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f);
corners[4] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f);
corners[5] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f);
corners[6] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f);
corners[7] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f);
// find min clip-space depth and NDC min/max
float ndcMinX = FLT_MAX;
float ndcMinY = FLT_MAX;
float ndcMaxX = -FLT_MAX;
float ndcMaxY = -FLT_MAX;
float minDepth = FLT_MAX;
for (uint32_t index = 0; index < 8; ++index)
{
minDepth = AZStd::min(minDepth, corners[index].GetW());
// convert to NDC
corners[index] /= corners[index].GetW();
ndcMinX = AZStd::min(ndcMinX, corners[index].GetX());
ndcMinY = AZStd::min(ndcMinY, corners[index].GetY());
ndcMaxX = AZStd::max(ndcMaxX, corners[index].GetX());
ndcMaxY = AZStd::max(ndcMaxY, corners[index].GetY());
}
if (minDepth < 0.00000001f)
{
return MaskedOcclusionCulling::VISIBLE;
}
// 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);
return m_jobData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth);
}
};
@@ -480,15 +512,22 @@ namespace AZ
MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
if (maskedOcclusionCulling)
{
// frustum cull and sort the occlusion planes by view space distance, front-to-back
// frustum cull occlusion planes
using OccluderEntry = AZStd::pair<AZ::Transform, float>;
AZStd::vector<OccluderEntry> visibleOccluders;
for (const AZ::Transform& transform : m_occlusionCullingPlanes)
{
Aabb occluderAabb = Aabb::CreateCenterHalfExtents(transform.GetTranslation(), AZ::Vector3(AZ::Vector2(transform.GetUniformScale() / 2.0f)));
occluderAabb.SetMin(transform.TransformPoint(occluderAabb.GetMin()));
occluderAabb.SetMax(transform.TransformPoint(occluderAabb.GetMax()));
if (ShapeIntersection::Contains(frustum, occluderAabb))
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))
{
// occluder is visible, compute view space distance and add to list
float depth = (view.GetWorldToViewMatrix() * occluderAabb.GetMin()).GetZ();
@@ -498,9 +537,10 @@ namespace AZ
}
}
// sort the occlusion planes by view space distance, front-to-back
AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const OccluderEntry& LHS, const OccluderEntry& RHS)
{
return LHS.second < RHS.second;
return LHS.second > RHS.second;
});
for (const OccluderEntry& occluder : visibleOccluders)