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
parent
fdf67b8217
commit
282a793a13
|
@ -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.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;
|
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.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)
|
if (p3.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||||
|
@ -856,7 +856,7 @@ void CEngine::DebugObject(int objRank)
|
||||||
vecStr = p1.bboxMax.ToString();
|
vecStr = p1.bboxMax.ToString();
|
||||||
l->Debug(" bboxMax: %s\n", vecStr.c_str());
|
l->Debug(" bboxMax: %s\n", vecStr.c_str());
|
||||||
l->Debug(" totalTriangles: %d\n", p1.totalTriangles);
|
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++)
|
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
|
||||||
{
|
{
|
||||||
|
@ -1659,7 +1659,6 @@ void CEngine::UpdateGeometry()
|
||||||
|
|
||||||
p1.bboxMin.LoadZero();
|
p1.bboxMin.LoadZero();
|
||||||
p1.bboxMax.LoadZero();
|
p1.bboxMax.LoadZero();
|
||||||
p1.radius = 0;
|
|
||||||
|
|
||||||
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
|
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.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.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;
|
m_updateGeometry = false;
|
||||||
|
@ -1925,9 +1924,8 @@ bool CEngine::IsVisible(int objRank)
|
||||||
|
|
||||||
assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size()));
|
assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size()));
|
||||||
|
|
||||||
float radius = m_baseObjects[baseObjRank].radius;
|
const auto& sphere = m_baseObjects[baseObjRank].boundingSphere;
|
||||||
Math::Vector center(0.0f, 0.0f, 0.0f);
|
if (m_device->ComputeSphereVisibility(sphere.pos, sphere.radius) == Gfx::FRUSTUM_PLANE_ALL)
|
||||||
if (m_device->ComputeSphereVisibility(center, radius) == Gfx::FRUSTUM_PLANE_ALL)
|
|
||||||
{
|
{
|
||||||
m_objects[objRank].visible = true;
|
m_objects[objRank].visible = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -246,8 +246,8 @@ struct EngineBaseObject
|
||||||
Math::Vector bboxMin;
|
Math::Vector bboxMin;
|
||||||
//! bounding box max (origin 0,0,0 always included)
|
//! bounding box max (origin 0,0,0 always included)
|
||||||
Math::Vector bboxMax;
|
Math::Vector bboxMax;
|
||||||
//! Radius of the sphere at the origin
|
//! A bounding sphere that contains all the vertices in this EngineBaseObject
|
||||||
float radius = 0.0f;
|
Math::Sphere boundingSphere;
|
||||||
//! Next tier (Tex)
|
//! Next tier (Tex)
|
||||||
std::vector<EngineBaseObjTexTier> next;
|
std::vector<EngineBaseObjTexTier> next;
|
||||||
|
|
||||||
|
|
|
@ -44,4 +44,11 @@ inline float DistanceBetweenSpheres(const Sphere& sphere1, const Sphere& sphere2
|
||||||
return Math::Distance(sphere1.pos, sphere2.pos) - sphere1.radius - sphere2.radius;
|
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
|
} // namespace Math
|
||||||
|
|
Loading…
Reference in New Issue