Optimization of isBoxVisible + cleanup, fixes #3712

This was SVN commit r17561.
This commit is contained in:
mimo 2015-12-28 16:27:31 +00:00
parent 82c215de49
commit 543472b77b
8 changed files with 92 additions and 137 deletions

View File

@ -53,7 +53,7 @@ void CFrustum::SetNumPlanes (size_t num)
}
}
void CFrustum::AddPlane (const CPlane& plane)
void CFrustum::AddPlane(const CPlane& plane)
{
if (m_NumPlanes >= MAX_NUM_FRUSTUM_PLANES)
{
@ -66,7 +66,7 @@ void CFrustum::AddPlane (const CPlane& plane)
void CFrustum::Transform(CMatrix3D& m)
{
for (size_t i = 0; i < m_NumPlanes; i++)
for (size_t i = 0; i < m_NumPlanes; ++i)
{
CVector3D n = m.Rotate(m_aPlanes[i].m_Norm);
CVector3D p = m.Transform(m_aPlanes[i].m_Norm * -m_aPlanes[i].m_Dist);
@ -75,22 +75,18 @@ void CFrustum::Transform(CMatrix3D& m)
}
}
bool CFrustum::IsPointVisible (const CVector3D &point) const
bool CFrustum::IsPointVisible(const CVector3D& point) const
{
PLANESIDE Side;
for (size_t i=0; i<m_NumPlanes; i++)
for (size_t i=0; i<m_NumPlanes; ++i)
{
Side = m_aPlanes[i].ClassifyPoint (point);
if (Side == PS_BACK)
if (m_aPlanes[i].IsPointOnBackSide(point))
return false;
}
return true;
}
bool CFrustum::DoesSegmentIntersect(const CVector3D& startRef, const CVector3D &endRef)
bool CFrustum::DoesSegmentIntersect(const CVector3D& startRef, const CVector3D& endRef) const
{
CVector3D start = startRef;
CVector3D end = endRef;
@ -99,97 +95,64 @@ bool CFrustum::DoesSegmentIntersect(const CVector3D& startRef, const CVector3D &
return true;
CVector3D intersect;
for ( size_t i = 0; i<m_NumPlanes; ++i )
for (size_t i = 0; i<m_NumPlanes; ++i)
{
if ( m_aPlanes[i].FindLineSegIntersection(start, end, &intersect) )
if (m_aPlanes[i].FindLineSegIntersection(start, end, &intersect))
{
if ( IsPointVisible( intersect ) )
if (IsPointVisible(intersect))
return true;
}
}
return false;
}
bool CFrustum::IsSphereVisible (const CVector3D &center, float radius) const
bool CFrustum::IsSphereVisible(const CVector3D& center, float radius) const
{
for (size_t i = 0; i < m_NumPlanes; i++)
for (size_t i = 0; i < m_NumPlanes; ++i)
{
float Dist = m_aPlanes[i].DistanceToPlane(center);
// If none of the sphere is in front of the plane, then
// it is outside the frustum
if (-Dist > radius)
if (-m_aPlanes[i].DistanceToPlane(center) > radius)
return false;
}
return true;
}
bool CFrustum::IsBoxVisible (const CVector3D &position,const CBoundingBoxAligned &bounds) const
bool CFrustum::IsBoxVisible(const CVector3D& position, const CBoundingBoxAligned& bounds) const
{
//basically for every plane we calculate the furthest point
//in the box to that plane. If that point is beyond the plane
//then the box is not visible
CVector3D FarPoint;
PLANESIDE Side;
CVector3D Min = position+bounds[0];
CVector3D Max = position+bounds[1];
for (size_t i=0; i<m_NumPlanes; i++)
for (size_t i=0; i<m_NumPlanes; ++i)
{
if (m_aPlanes[i].m_Norm.X > 0.0f)
{
if (m_aPlanes[i].m_Norm.Y > 0.0f)
{
if (m_aPlanes[i].m_Norm.Z > 0.0f)
{
FarPoint.X = Max.X; FarPoint.Y = Max.Y; FarPoint.Z = Max.Z;
}
else
{
FarPoint.X = Max.X; FarPoint.Y = Max.Y; FarPoint.Z = Min.Z;
}
}
else
{
if (m_aPlanes[i].m_Norm.Z > 0.0f)
{
FarPoint.X = Max.X; FarPoint.Y = Min.Y; FarPoint.Z = Max.Z;
}
else
{
FarPoint.X = Max.X; FarPoint.Y = Min.Y; FarPoint.Z = Min.Z;
}
}
}
else
{
if (m_aPlanes[i].m_Norm.Y > 0.0f)
{
if (m_aPlanes[i].m_Norm.Z > 0.0f)
{
FarPoint.X = Min.X; FarPoint.Y = Max.Y; FarPoint.Z = Max.Z;
}
else
{
FarPoint.X = Min.X; FarPoint.Y = Max.Y; FarPoint.Z = Min.Z;
}
}
else
{
if (m_aPlanes[i].m_Norm.Z > 0.0f)
{
FarPoint.X = Min.X; FarPoint.Y = Min.Y; FarPoint.Z = Max.Z;
}
else
{
FarPoint.X = Min.X; FarPoint.Y = Min.Y; FarPoint.Z = Min.Z;
}
}
}
FarPoint.X = m_aPlanes[i].m_Norm.X > 0.0f ? Max.X : Min.X;
FarPoint.Y = m_aPlanes[i].m_Norm.Y > 0.0f ? Max.Y : Min.Y;
FarPoint.Z = m_aPlanes[i].m_Norm.Z > 0.0f ? Max.Z : Min.Z;
Side = m_aPlanes[i].ClassifyPoint (FarPoint);
if (Side == PS_BACK)
if (m_aPlanes[i].IsPointOnBackSide(FarPoint))
return false;
}
return true;
}
bool CFrustum::IsBoxVisible(const CBoundingBoxAligned& bounds) const
{
//Same as the previous one, but with the position = (0, 0, 0)
CVector3D FarPoint;
for (size_t i=0; i<m_NumPlanes; ++i)
{
FarPoint.X = m_aPlanes[i].m_Norm.X > 0.0f ? bounds[1].X : bounds[0].X;
FarPoint.Y = m_aPlanes[i].m_Norm.Y > 0.0f ? bounds[1].Y : bounds[0].Y;
FarPoint.Z = m_aPlanes[i].m_Norm.Z > 0.0f ? bounds[1].Z : bounds[0].Z;
if (m_aPlanes[i].IsPointOnBackSide(FarPoint))
return false;
}

View File

@ -55,10 +55,11 @@ public:
//The following methods return true if the shape is
//partially or completely in front of the frustum planes
bool IsPointVisible (const CVector3D &point) const;
bool DoesSegmentIntersect(const CVector3D& start, const CVector3D &end);
bool IsSphereVisible (const CVector3D &center, float radius) const;
bool IsBoxVisible (const CVector3D &position,const CBoundingBoxAligned &bounds) const;
bool IsPointVisible(const CVector3D& point) const;
bool DoesSegmentIntersect(const CVector3D& start, const CVector3D& end) const;
bool IsSphereVisible(const CVector3D& center, float radius) const;
bool IsBoxVisible(const CVector3D& position, const CBoundingBoxAligned& bounds) const;
bool IsBoxVisible(const CBoundingBoxAligned& bounds) const;
CPlane& operator[](size_t idx) { return m_aPlanes[idx]; }
const CPlane& operator[](size_t idx) const { return m_aPlanes[idx]; }

View File

@ -498,23 +498,23 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
PROFILE3("submit terrain");
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f;
const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide();
// find out which patches will be drawn
for (ssize_t j=0; j<patchesPerSide; j++) {
for (ssize_t i=0; i<patchesPerSide; i++) {
for (ssize_t j=0; j<patchesPerSide; ++j)
{
for (ssize_t i=0; i<patchesPerSide; ++i)
{
CPatch* patch=pTerrain->GetPatch(i,j); // can't fail
// If the patch is underwater, calculate a bounding box that also contains the water plane
CBoundingBoxAligned bounds = patch->GetWorldBounds();
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f;
if(bounds[1].Y < waterHeight) {
if(bounds[1].Y < waterHeight)
bounds[1].Y = waterHeight;
}
if (!m->Culling || frustum.IsBoxVisible (CVector3D(0,0,0), bounds)) {
if (!m->Culling || frustum.IsBoxVisible(bounds))
c->Submit(patch);
}
}
}
}

View File

@ -27,13 +27,15 @@
#include "Plane.h"
#include "MathUtil.h"
CPlane::CPlane ()
const float CPlane::m_EPS = 0.001f;
CPlane::CPlane()
{
m_Dist = 0.0f;
}
//sets the plane equation from 3 points on that plane
void CPlane::Set (const CVector3D &p1, const CVector3D &p2, const CVector3D &p3)
void CPlane::Set(const CVector3D& p1, const CVector3D& p2, const CVector3D& p3)
{
CVector3D D1, D2;
CVector3D Norm;
@ -45,28 +47,24 @@ void CPlane::Set (const CVector3D &p1, const CVector3D &p2, const CVector3D &p3)
//cross multiply gives normal
Norm = D2.Cross(D1);
Set (Norm, p1);
Set(Norm, p1);
}
//sets the plane equation from a normal and a point on
//that plane
void CPlane::Set (const CVector3D &norm, const CVector3D &point)
void CPlane::Set(const CVector3D& norm, const CVector3D& point)
{
m_Norm = norm;
m_Dist = - (norm.X * point.X +
norm.Y * point.Y +
norm.Z * point.Z);
m_Dist = - (norm.X * point.X + norm.Y * point.Y + norm.Z * point.Z);
// Normalize ();
}
//normalizes the plane equation
void CPlane::Normalize ()
void CPlane::Normalize()
{
float Scale;
Scale = 1.0f/m_Norm.Length ();
float Scale = 1.0f/m_Norm.Length();
m_Norm.X *= Scale;
m_Norm.Y *= Scale;
@ -76,20 +74,13 @@ void CPlane::Normalize ()
//returns the side of the plane on which this point
//lies.
PLANESIDE CPlane::ClassifyPoint (const CVector3D &point) const
PLANESIDE CPlane::ClassifyPoint(const CVector3D& point) const
{
float Dist;
float Dist = DistanceToPlane(point);
Dist = m_Norm.X * point.X +
m_Norm.Y * point.Y +
m_Norm.Z * point.Z +
m_Dist;
const float EPS = 0.001f;
if (Dist > EPS)
if (Dist > m_EPS)
return PS_FRONT;
else if (Dist < -EPS)
else if (Dist < -m_EPS)
return PS_BACK;
return PS_ON;
@ -97,26 +88,26 @@ PLANESIDE CPlane::ClassifyPoint (const CVector3D &point) const
//calculates the intersection point of a line with this
//plane. Returns false if there is no intersection
bool CPlane::FindLineSegIntersection (const CVector3D &start, const CVector3D &end, CVector3D *intsect)
bool CPlane::FindLineSegIntersection(const CVector3D& start, const CVector3D& end, CVector3D* intsect) const
{
float dist1 = DistanceToPlane( start );
float dist2 = DistanceToPlane( end );
float dist1 = DistanceToPlane(start);
float dist2 = DistanceToPlane(end);
if( (dist1 < 0 && dist2 < 0) || (dist1 >= 0 && dist2 >= 0) )
return false;
float t = (-dist1) / (dist2-dist1);
*intsect = Interpolate( start, end, t );
*intsect = Interpolate(start, end, t);
return true;
}
bool CPlane::FindRayIntersection (const CVector3D &start, const CVector3D &direction, CVector3D *intsect)
bool CPlane::FindRayIntersection(const CVector3D& start, const CVector3D& direction, CVector3D* intsect) const
{
float dot = m_Norm.Dot (direction);
float dot = m_Norm.Dot(direction);
if (dot == 0.0f)
return false;
*intsect = start - (direction * (DistanceToPlane (start)/dot));
*intsect = start - (direction * (DistanceToPlane(start)/dot));
return true;
}

View File

@ -38,46 +38,46 @@ enum PLANESIDE
class CPlane
{
public:
CPlane ();
CPlane (const CVector4D& coeffs) : m_Norm(coeffs.X, coeffs.Y, coeffs.Z), m_Dist(coeffs.W) { }
CPlane();
CPlane(const CVector4D& coeffs) : m_Norm(coeffs.X, coeffs.Y, coeffs.Z), m_Dist(coeffs.W) { }
//sets the plane equation from 3 points on that plane
void Set (const CVector3D &p1, const CVector3D &p2, const CVector3D &p3);
void Set(const CVector3D& p1, const CVector3D& p2, const CVector3D& p3);
//sets the plane equation from a normal and a point on
//that plane
void Set (const CVector3D &norm, const CVector3D &point);
void Set(const CVector3D& norm, const CVector3D& point);
//normalizes the plane equation
void Normalize ();
void Normalize();
//returns the side of the plane on which this point
//lies.
PLANESIDE ClassifyPoint (const CVector3D &point) const;
//returns the side of the plane on which this point lies
PLANESIDE ClassifyPoint(const CVector3D& point) const;
//returns true if this point is on the back side
inline bool IsPointOnBackSide(const CVector3D& point) const;
//solves the plane equation for a particular point
inline float DistanceToPlane (const CVector3D &point) const;
inline float DistanceToPlane(const CVector3D& point) const;
//calculates the intersection point of a line with this
//plane. Returns false if there is no intersection
bool FindLineSegIntersection (const CVector3D &start, const CVector3D &end, CVector3D *intsect);
bool FindRayIntersection (const CVector3D &start, const CVector3D &direction, CVector3D *intsect);
bool FindLineSegIntersection(const CVector3D& start, const CVector3D& end, CVector3D* intsect) const;
bool FindRayIntersection(const CVector3D& start, const CVector3D& direction, CVector3D* intsect) const;
public:
CVector3D m_Norm; //normal vector of the plane
float m_Dist; //Plane distance (ie D in the plane eq.)
static const float m_EPS;
};
float CPlane::DistanceToPlane (const CVector3D &point) const
float CPlane::DistanceToPlane(const CVector3D& point) const
{
float Dist;
return m_Norm.X * point.X + m_Norm.Y * point.Y + m_Norm.Z * point.Z + m_Dist;
}
Dist = m_Norm.X * point.X +
m_Norm.Y * point.Y +
m_Norm.Z * point.Z +
m_Dist;
return Dist;
bool CPlane::IsPointOnBackSide(const CVector3D& point) const
{
return DistanceToPlane(point) < -m_EPS;
}
#endif

View File

@ -908,11 +908,11 @@ void WaterManager::RenderWaves(const CFrustum& frustrum)
for (size_t a = 0; a < m_ShoreWaves.size(); ++a)
{
if (!frustrum.IsBoxVisible(CVector3D(0,0,0), m_ShoreWaves[a]->m_AABB))
if (!frustrum.IsBoxVisible(m_ShoreWaves[a]->m_AABB))
continue;
CVertexBuffer::VBChunk* VBchunk = m_ShoreWaves[a]->m_VBvertices;
SWavesVertex *base=(SWavesVertex *)VBchunk->m_Owner->Bind();
SWavesVertex* base = (SWavesVertex*)VBchunk->m_Owner->Bind();
// setup data pointers
GLsizei stride = sizeof(SWavesVertex);

View File

@ -320,7 +320,7 @@ void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrust
{
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
int player = GetSimContext().GetCurrentDisplayedPlayer();
ICmpRangeManager::CLosQuerier los (cmpRangeManager->GetLosQuerier(player));
ICmpRangeManager::CLosQuerier los(cmpRangeManager->GetLosQuerier(player));
bool losRevealAll = cmpRangeManager->GetLosRevealAll(player);
for (size_t i = 0; i < m_Projectiles.size(); ++i)
@ -335,7 +335,7 @@ void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrust
model.ValidatePosition();
if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetWorldBoundsRec()))
if (culling && !frustum.IsBoxVisible(model.GetWorldBoundsRec()))
continue;
// TODO: do something about LOS (copy from CCmpVisualActor)

View File

@ -430,7 +430,7 @@ void CCmpUnitRenderer::RenderSubmit(SceneCollector& collector, const CFrustum& f
unit.lastTransformFrame = m_FrameNumber;
}
if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), unitModel.GetWorldBoundsRec()))
if (culling && !frustum.IsBoxVisible(unitModel.GetWorldBoundsRec()))
continue;
collector.SubmitRecursive(&unitModel);