forked from 0ad/0ad
Optimization of isBoxVisible + cleanup, fixes #3712
This was SVN commit r17561.
This commit is contained in:
parent
82c215de49
commit
543472b77b
@ -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 ¢er, 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;
|
||||
}
|
||||
|
||||
|
@ -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 ¢er, 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]; }
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user