From 282a793a130c9073de7f5234b8cbc8f4ce29a020 Mon Sep 17 00:00:00 2001 From: AbigailBuccaneer Date: Sun, 29 Apr 2018 18:05:19 +0100 Subject: [PATCH] Improve object vis with tighter bounding spheres This commit improves rendering performance by doing a better job of checking whether an object is visible via its bounding sphere or not. The engine maintains a bounding box for each EngineBaseObject that's exactly large enough to fit every vertex. From this, it computes a bounding sphere, and only draws objects if the sphere is within the view frustum. Previously, the bounding sphere was always centered on the EngineBaseObject's origin, even for models where the bounding box center is significantly offset from the origin. Now, the bounding sphere is always the tightest sphere which fits the bounding box. --- src/graphics/engine/engine.cpp | 16 +++++++--------- src/graphics/engine/engine.h | 4 ++-- src/math/sphere.h | 7 +++++++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 23ed2108..304dabc6 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -765,7 +765,7 @@ void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector p1.bboxMax.z = Math::Max(vertices[i].coord.z, p1.bboxMax.z); } - p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length()); + p1.boundingSphere = Math::BoundingSphereForBox(p1.bboxMin, p1.bboxMax); p1.totalTriangles += vertices.size() / 3; } @@ -801,7 +801,7 @@ void CEngine::AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buff p1.bboxMax.z = Math::Max(p3.vertices[i].coord.z, p1.bboxMax.z); } - p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length()); + p1.boundingSphere = Math::BoundingSphereForBox(p1.bboxMin, p1.bboxMax); } if (p3.type == ENG_TRIANGLE_TYPE_TRIANGLES) @@ -856,7 +856,7 @@ void CEngine::DebugObject(int objRank) vecStr = p1.bboxMax.ToString(); l->Debug(" bboxMax: %s\n", vecStr.c_str()); l->Debug(" totalTriangles: %d\n", p1.totalTriangles); - l->Debug(" radius: %f\n", p1.radius); + l->Debug(" radius: %f\n", p1.boundingSphere.radius); for (int l2 = 0; l2 < static_cast( p1.next.size() ); l2++) { @@ -1659,7 +1659,6 @@ void CEngine::UpdateGeometry() p1.bboxMin.LoadZero(); p1.bboxMax.LoadZero(); - p1.radius = 0; for (int l2 = 0; l2 < static_cast( p1.next.size() ); l2++) { @@ -1678,10 +1677,10 @@ void CEngine::UpdateGeometry() p1.bboxMax.y = Math::Max(p3.vertices[i].coord.y, p1.bboxMax.y); p1.bboxMax.z = Math::Max(p3.vertices[i].coord.z, p1.bboxMax.z); } - - p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length()); } } + + p1.boundingSphere = Math::BoundingSphereForBox(p1.bboxMin, p1.bboxMax); } m_updateGeometry = false; @@ -1925,9 +1924,8 @@ bool CEngine::IsVisible(int objRank) assert(baseObjRank >= 0 && baseObjRank < static_cast(m_baseObjects.size())); - float radius = m_baseObjects[baseObjRank].radius; - Math::Vector center(0.0f, 0.0f, 0.0f); - if (m_device->ComputeSphereVisibility(center, radius) == Gfx::FRUSTUM_PLANE_ALL) + const auto& sphere = m_baseObjects[baseObjRank].boundingSphere; + if (m_device->ComputeSphereVisibility(sphere.pos, sphere.radius) == Gfx::FRUSTUM_PLANE_ALL) { m_objects[objRank].visible = true; return true; diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 27f01585..6adc9323 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -246,8 +246,8 @@ struct EngineBaseObject Math::Vector bboxMin; //! bounding box max (origin 0,0,0 always included) Math::Vector bboxMax; - //! Radius of the sphere at the origin - float radius = 0.0f; + //! A bounding sphere that contains all the vertices in this EngineBaseObject + Math::Sphere boundingSphere; //! Next tier (Tex) std::vector next; diff --git a/src/math/sphere.h b/src/math/sphere.h index a5121d0c..ea009332 100644 --- a/src/math/sphere.h +++ b/src/math/sphere.h @@ -44,4 +44,11 @@ inline float DistanceBetweenSpheres(const Sphere& sphere1, const Sphere& sphere2 return Math::Distance(sphere1.pos, sphere2.pos) - sphere1.radius - sphere2.radius; } +inline Sphere BoundingSphereForBox(Vector mins, Vector maxs) +{ + auto centroid = (maxs + mins) / 2.0f; + auto halfExtent = (maxs - centroid); + return Sphere{centroid, halfExtent.Length()}; +} + } // namespace Math