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.
1008-fix
AbigailBuccaneer 2018-04-29 18:05:19 +01:00
parent fdf67b8217
commit 282a793a13
3 changed files with 16 additions and 11 deletions

View File

@ -765,7 +765,7 @@ void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector<VertexTex2>
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<int>( 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<int>( 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<int>(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;

View File

@ -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<EngineBaseObjTexTier> next;

View File

@ -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