1
0
forked from 0ad/0ad

#More accurate bounds calculations to improve shadow resolution

and a fix for the auto-build: #define enums from EXT_framebuffer_object

* clip shadow bounds to frustum
* add CBrush, a class representing a convex object

This was SVN commit r3695.
This commit is contained in:
prefect 2006-03-26 21:58:48 +00:00
parent 73506eb076
commit 0d648b2df8
9 changed files with 535 additions and 13 deletions

View File

@ -30,16 +30,21 @@ public:
~CFrustum ();
//Set the number of planes to use for
//calculations. This is clipped to
//calculations. This is clipped to
//[0,MAX_NUM_FRUSTUM_PLANES]
void SetNumPlanes (int num);
uint GetNumPlanes() const { return m_NumPlanes; }
//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 IsSphereVisible (const CVector3D &center, float radius) const;
bool IsBoxVisible (const CVector3D &position,const CBound &bounds) const;
CPlane& operator[](uint idx) { return m_aPlanes[idx]; }
const CPlane& operator[](uint idx) const { return m_aPlanes[idx]; }
public:
//make the planes public for ease of use
CPlane m_aPlanes[MAX_NUM_FRUSTUM_PLANES];
@ -47,5 +52,5 @@ public:
private:
int m_NumPlanes;
};
#endif

View File

@ -46,6 +46,61 @@ extern "C" {
#endif
// Enums from EXT_framebuffer_object
#ifndef GL_FRAMEBUFFER_EXT
#define GL_FRAMEBUFFER_EXT 0x8D40
#define GL_RENDERBUFFER_EXT 0x8D41
#define GL_STENCIL_INDEX1_EXT 0x8D46
#define GL_STENCIL_INDEX4_EXT 0x8D47
#define GL_STENCIL_INDEX8_EXT 0x8D48
#define GL_STENCIL_INDEX16_EXT 0x8D49
#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
#endif
//
// extensions
//
@ -99,7 +154,7 @@ extern int ogl_max_tex_units; // limit on GL_TEXTUREn
// set detect.cpp gfx_card[] and gfx_drv_ver[].
// (called by detect.cpp get_gfx_info()).
//
//
// fails if OpenGL not ready for use.
// gfx_card and gfx_drv_ver are unchanged on failure.
extern LibError ogl_get_gfx_info(void);

View File

@ -14,6 +14,9 @@
#include <float.h>
#include "Bound.h"
#include "Frustum.h"
#include "Brush.h"
///////////////////////////////////////////////////////////////////////////////
// operator+=: extend this bound to include given bound
@ -173,6 +176,19 @@ void CBound::Transform(const CMatrix3D& m,CBound& result) const
}
///////////////////////////////////////////////////////////////////////////////
// Intersect with the given frustum in a conservative manner
void CBound::IntersectFrustumConservative(const CFrustum& frustum)
{
CBrush brush(*this);
CBrush buf;
brush.Intersect(frustum, buf);
buf.Bounds(*this);
}
///////////////////////////////////////////////////////////////////////////////
// Render the bounding box
void CBound::Render()

View File

@ -13,6 +13,8 @@
#include "Vector3D.h"
#include "Matrix3D.h"
class CFrustum;
///////////////////////////////////////////////////////////////////////////////
// CBound: basic axis aligned bounding box class
class CBound
@ -47,6 +49,21 @@ public:
centre=(m_Data[0]+m_Data[1])*0.5f;
}
/**
* IntersectFrustumConservative: Approximate the intersection of this bounds object
* with the given frustum. The bounds object is overwritten with the results.
*
* The approximation is conservative in the sense that the result will always contain
* the actual intersection, but it may be larger than the intersection itself.
* The result will always be fully contained within the original bounds.
*
* @note While not in the spirit of this function's purpose, a no-op would be a correct
* implementation of this function.
*
* @param frustum the frustum to intersect with
*/
void IntersectFrustumConservative(const CFrustum& frustum);
/**
* Render: Render the surfaces of the bound object as polygons.
*/

324
source/maths/Brush.cpp Normal file
View File

@ -0,0 +1,324 @@
/**
* =========================================================================
* File : Brush.h
* Project : Pyrogenesis
* Description : Implementation of CBrush, a class representing a convex object
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
* =========================================================================
*/
#include "precompiled.h"
#include "ogl.h"
#include <float.h>
#include "Brush.h"
#include "Bound.h"
#include "Frustum.h"
///////////////////////////////////////////////////////////////////////////////
// Convert the given bounds into a brush
CBrush::CBrush(const CBound& bounds)
{
m_Vertices.resize(8);
for(uint i = 0; i < 8; ++i)
{
m_Vertices[i][0] = bounds[(i & 1) ? 1 : 0][0];
m_Vertices[i][1] = bounds[(i & 2) ? 1 : 0][1];
m_Vertices[i][2] = bounds[(i & 4) ? 1 : 0][2];
}
m_Faces.resize(30);
m_Faces[0] = 0; m_Faces[1] = 1; m_Faces[2] = 3; m_Faces[3] = 2; m_Faces[4] = 0; // Z = min
m_Faces[5] = 4; m_Faces[6] = 5; m_Faces[7] = 7; m_Faces[8] = 6; m_Faces[9] = 4; // Z = max
m_Faces[10] = 0; m_Faces[11] = 2; m_Faces[12] = 6; m_Faces[13] = 4; m_Faces[14] = 0; // X = min
m_Faces[15] = 1; m_Faces[16] = 3; m_Faces[17] = 7; m_Faces[18] = 5; m_Faces[19] = 1; // X = max
m_Faces[20] = 0; m_Faces[21] = 1; m_Faces[22] = 5; m_Faces[23] = 4; m_Faces[24] = 0; // Y = min
m_Faces[25] = 2; m_Faces[26] = 3; m_Faces[27] = 7; m_Faces[28] = 6; m_Faces[29] = 2; // Y = max
}
///////////////////////////////////////////////////////////////////////////////
// Calculate bounds of this brush
void CBrush::Bounds(CBound& result) const
{
result.SetEmpty();
for(uint i = 0; i < m_Vertices.size(); ++i)
result += m_Vertices[i];
}
///////////////////////////////////////////////////////////////////////////////
// Cut the brush according to a given plane
struct SliceVertexInfo {
float d; // distance
uint res; // index in result brush (or no_vertex if cut away)
};
struct NewVertexInfo {
uint v1, v2; // adjacent vertices in original brush
uint res; // index in result brush
uint neighb1, neighb2; // index into newv
};
struct SliceInfo {
std::vector<SliceVertexInfo> v;
std::vector<NewVertexInfo> newv;
uint thisFaceNewVertex; // index into newv
const CBrush* original;
CBrush* result;
};
struct CBrush::Helper
{
static uint SliceNewVertex(SliceInfo& si, uint v1, uint v2);
};
// create a new vertex between the given two vertices (index into original brush)
// returns the index of the new vertex in the resulting brush
uint CBrush::Helper::SliceNewVertex(SliceInfo& si, uint v1, uint v2)
{
uint idx;
for(idx = 0; idx < si.newv.size(); ++idx)
{
if ((si.newv[idx].v1 == v1 && si.newv[idx].v2 == v2) ||
(si.newv[idx].v1 == v2 && si.newv[idx].v2 == v1))
break;
}
if (idx >= si.newv.size())
{
NewVertexInfo nvi;
CVector3D newpos;
float inv = 1.0 / (si.v[v1].d - si.v[v2].d);
newpos = si.original->m_Vertices[v2]*(si.v[v1].d*inv) +
si.original->m_Vertices[v1]*(-si.v[v2].d*inv);
nvi.v1 = v1;
nvi.v2 = v2;
nvi.res = si.result->m_Vertices.size();
nvi.neighb1 = no_vertex;
nvi.neighb2 = no_vertex;
si.result->m_Vertices.push_back(newpos);
si.newv.push_back(nvi);
}
if (si.thisFaceNewVertex != no_vertex)
{
if (si.newv[si.thisFaceNewVertex].neighb1 == no_vertex)
si.newv[si.thisFaceNewVertex].neighb1 = idx;
else
si.newv[si.thisFaceNewVertex].neighb2 = idx;
if (si.newv[idx].neighb1 == no_vertex)
si.newv[idx].neighb1 = si.thisFaceNewVertex;
else
si.newv[idx].neighb2 = si.thisFaceNewVertex;
si.thisFaceNewVertex = no_vertex;
}
else
{
si.thisFaceNewVertex = idx;
}
return si.newv[idx].res;
}
void CBrush::Slice(const CPlane& plane, CBrush& result) const
{
debug_assert(&result != this);
SliceInfo si;
si.original = this;
si.result = &result;
si.thisFaceNewVertex = no_vertex;
si.newv.reserve(m_Vertices.size() / 2);
result.m_Vertices.resize(0); // clear any left-overs
result.m_Faces.resize(0);
result.m_Vertices.reserve(m_Vertices.size() + 2);
result.m_Faces.reserve(m_Faces.size() + 5);
// Classify and copy vertices
si.v.resize(m_Vertices.size());
for(uint i = 0; i < m_Vertices.size(); ++i)
{
si.v[i].d = plane.DistanceToPlane(m_Vertices[i]);
if (si.v[i].d >= 0.0)
{
si.v[i].res = result.m_Vertices.size();
result.m_Vertices.push_back(m_Vertices[i]);
}
else
{
si.v[i].res = no_vertex;
}
}
// Transfer faces
uint firstInFace = no_vertex; // in original brush
uint startInResultFaceArray = ~0;
for(uint i = 0; i < m_Faces.size(); ++i)
{
if (firstInFace == no_vertex)
{
debug_assert(si.thisFaceNewVertex == no_vertex);
firstInFace = m_Faces[i];
startInResultFaceArray = result.m_Faces.size();
continue;
}
uint prev = m_Faces[i-1];
uint cur = m_Faces[i];
if (si.v[prev].res == no_vertex)
{
if (si.v[cur].res != no_vertex)
{
// re-entering the front side of the plane
result.m_Faces.push_back(Helper::SliceNewVertex(si, prev, cur));
result.m_Faces.push_back(si.v[cur].res);
}
}
else
{
if (si.v[cur].res != no_vertex)
{
// perfectly normal edge
result.m_Faces.push_back(si.v[cur].res);
}
else
{
// leaving the front side of the plane
result.m_Faces.push_back(Helper::SliceNewVertex(si, prev, cur));
}
}
if (cur == firstInFace)
{
if (result.m_Faces.size() > startInResultFaceArray)
result.m_Faces.push_back(result.m_Faces[startInResultFaceArray]);
firstInFace = no_vertex; // start a new face
}
}
debug_assert(firstInFace == no_vertex);
// Create the face that lies in the slicing plane
if (si.newv.size())
{
uint prev = 0;
uint idx;
result.m_Faces.push_back(si.newv[0].res);
idx = si.newv[0].neighb2;
si.newv[0].neighb2 = no_vertex;
while(idx != 0)
{
debug_assert(idx < si.newv.size());
if (si.newv[idx].neighb1 == prev)
{
si.newv[idx].neighb1 = si.newv[idx].neighb2;
si.newv[idx].neighb2 = no_vertex;
}
else
{
debug_assert(si.newv[idx].neighb2 == prev);
si.newv[idx].neighb2 = no_vertex;
}
result.m_Faces.push_back(si.newv[idx].res);
prev = idx;
idx = si.newv[idx].neighb1;
si.newv[prev].neighb1 = no_vertex;
}
result.m_Faces.push_back(si.newv[0].res);
}
}
///////////////////////////////////////////////////////////////////////////////
// Intersect with frustum by repeated slicing
void CBrush::Intersect(const CFrustum& frustum, CBrush& result) const
{
debug_assert(&result != this);
if (!frustum.GetNumPlanes())
{
result = *this;
return;
}
CBrush buf;
const CBrush* prev = this;
CBrush* next;
if (frustum.GetNumPlanes() & 1)
next = &result;
else
next = &buf;
for(uint i = 0; i < frustum.GetNumPlanes(); ++i)
{
prev->Slice(frustum[i], *next);
prev = next;
if (prev == &buf)
next = &result;
else
next = &buf;
}
debug_assert(prev == &result);
}
///////////////////////////////////////////////////////////////////////////////
// Dump the faces to OpenGL
void CBrush::Render() const
{
uint firstInFace = no_vertex;
for(uint i = 0; i < m_Faces.size(); ++i)
{
if (firstInFace == no_vertex)
{
glBegin(GL_POLYGON);
firstInFace = m_Faces[i];
continue;
}
const CVector3D& vertex = m_Vertices[m_Faces[i]];
glVertex3fv(&vertex.X);
if (firstInFace == m_Faces[i])
{
glEnd();
firstInFace = no_vertex;
}
}
debug_assert(firstInFace == no_vertex);
}

87
source/maths/Brush.h Normal file
View File

@ -0,0 +1,87 @@
/**
* =========================================================================
* File : Brush.h
* Project : Pyrogenesis
* Description : CBrush, a class representing a convex object
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
* =========================================================================
*/
#ifndef maths_brush_h
#define maths_brush_h
#include "Vector3D.h"
class CBound;
class CFrustum;
class CPlane;
/**
* Class CBrush: Represents a convex object, supports some CSG operations.
*/
class CBrush
{
public:
CBrush() { }
/**
* CBrush: Construct a brush from a bounds object.
*
* @param bounds the CBound object to construct the brush from.
*/
CBrush(const CBound& bounds);
/**
* IsEmpty: Returns whether the brush is empty.
*
* @return @c true if the brush is empty, @c false otherwise
*/
bool IsEmpty() const { return m_Vertices.size() == 0; }
/**
* Bounds: Calculate the axis-aligned bounding box for this brush.
*
* @param result the resulting bounding box is stored here
*/
void Bounds(CBound& result) const;
/**
* Slice: Cut the object along the given plane, resulting in a smaller (or even empty)
* brush representing the part of the object that lies in front of the plane.
*
* @param plane the slicing plane
* @param result the resulting brush is stored here
*/
void Slice(const CPlane& plane, CBrush& result) const;
/**
* Intersect: Intersect the brush with the given frustum.
*
* @param frustum the frustum to intersect with
* @param result the resulting brush is stored here
*/
void Intersect(const CFrustum& frustum, CBrush& result) const;
/**
* Render: Renders the brush as OpenGL polygons.
*
* @note the winding of the brush faces is undefined (i.e. it is undefined which
* sides of the faces are the front faces)
*/
void Render() const;
private:
static const uint no_vertex = ~0;
typedef std::vector<CVector3D> Vertices;
typedef std::vector<uint> FaceIndices;
Vertices m_Vertices;
FaceIndices m_Faces;
struct Helper;
};
#endif // maths_brush_h

View File

@ -547,13 +547,13 @@ bool CRenderer::GetOptionBool(enum Option opt) const
//////////////////////////////////////////////////////////////////////////////////////////
// SetOptionColor: set color renderer option
void CRenderer::SetOptionColor(enum Option opt,const RGBAColor& value)
void CRenderer::SetOptionColor(enum Option opt,const RGBAColor& UNUSED(value))
{
switch (opt) {
default:
// switch (opt) {
// default:
debug_warn("CRenderer::SetOptionColor: unknown option");
break;
}
// break;
// }
}
void CRenderer::SetOptionFloat(enum Option opt, float val)
@ -575,11 +575,11 @@ const RGBAColor& CRenderer::GetOptionColor(enum Option opt) const
{
static const RGBAColor defaultColor(1.0f,1.0f,1.0f,1.0f);
switch (opt) {
default:
// switch (opt) {
// default:
debug_warn("CRenderer::GetOptionColor: unknown option");
break;
}
// break;
// }
return defaultColor;
}

View File

@ -61,6 +61,9 @@ struct ShadowMapInternals
// bounding box of shadowed objects in light space
CBound ShadowBound;
// Camera transformed into light space
CCamera LightspaceCamera;
// Helper functions
void CalcShadowMatrices();
void CreateTexture();
@ -144,6 +147,11 @@ void ShadowMap::SetupFrame(const CCamera& camera, const CVector3D& lightdir)
m->LightTransform.GetInverse(m->InvLightTransform);
m->ShadowBound.SetEmpty();
//
m->LightspaceCamera = camera;
m->LightspaceCamera.m_Orientation = m->LightTransform * camera.m_Orientation;
m->LightspaceCamera.UpdateFrustum();
}
@ -166,6 +174,16 @@ void ShadowMapInternals::CalcShadowMatrices()
{
CRenderer& renderer = g_Renderer;
float minZ = ShadowBound[0].Z;
ShadowBound.IntersectFrustumConservative(LightspaceCamera.GetFrustum());
// minimum Z bound must not be clipped too much, because objects that lie outside
// the shadow bounds cannot cast shadows either
// the 2.0 is rather arbitrary: it should be big enough so that we won't accidently miss
// a shadow generator, and small enough not to affect Z precision
ShadowBound[0].Z = minZ - 2.0;
// Setup orthogonal projection (lightspace -> clip space) for shadowmap rendering
CVector3D scale = ShadowBound[1] - ShadowBound[0];
CVector3D shift = (ShadowBound[1] + ShadowBound[0]) * -0.5;

View File

@ -270,7 +270,7 @@ void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* dat
// Prepare for one rendering pass
void PolygonSortModelRenderer::BeginPass(uint streamflags, const CMatrix3D* UNUSED(texturematrix))
{
debug_assert(streamflags == streamflags & (STREAM_POS|STREAM_COLOR|STREAM_UV0));
debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_COLOR|STREAM_UV0)));
glEnableClientState(GL_VERTEX_ARRAY);