- add CBound::Render()

- fix CBound::Transform() math
- beginnings of new shadow bound calculations

This was SVN commit r3436.
This commit is contained in:
prefect
2006-01-29 17:34:45 +00:00
parent 6699dc11c7
commit 90bf4ae0a7
7 changed files with 248 additions and 52 deletions
+61 -21
View File
@@ -10,6 +10,8 @@
// necessary includes
#include "ogl.h"
#include <float.h>
#include "Bound.h"
@@ -71,51 +73,51 @@ bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir,
tfar = t2;
}
if (tfar<0)
if (tfar<0)
return false;
}
if (dir[1]==0 && (origin[1]<m_Data[0][1] || origin[1]>m_Data[1][1]))
if (dir[1]==0 && (origin[1]<m_Data[0][1] || origin[1]>m_Data[1][1]))
return false;
else {
t1=(m_Data[0][1]-origin[1])/dir[1];
t2=(m_Data[1][1]-origin[1])/dir[1];
if (dir[1]<0) {
if (t2>tnear)
if (dir[1]<0) {
if (t2>tnear)
tnear = t2;
if (t1<tfar)
if (t1<tfar)
tfar = t1;
} else {
if (t1>tnear)
if (t1>tnear)
tnear = t1;
if (t2<tfar)
if (t2<tfar)
tfar = t2;
}
if (tnear>tfar || tfar<0)
if (tnear>tfar || tfar<0)
return false;
}
if (dir[2]==0 && (origin[2]<m_Data[0][2] || origin[2]>m_Data[1][2]))
if (dir[2]==0 && (origin[2]<m_Data[0][2] || origin[2]>m_Data[1][2]))
return false;
else {
t1=(m_Data[0][2]-origin[2])/dir[2];
t2=(m_Data[1][2]-origin[2])/dir[2];
if (dir[2]<0) {
if (t2>tnear)
if (dir[2]<0) {
if (t2>tnear)
tnear = t2;
if (t1<tfar)
if (t1<tfar)
tfar = t1;
} else {
if (t1>tnear)
if (t1>tnear)
tnear = t1;
if (t2<tfar)
if (t2<tfar)
tfar = t2;
}
if (tnear>tfar || tfar<0)
if (tnear>tfar || tfar<0)
return false;
}
@@ -150,14 +152,14 @@ void CBound::Transform(const CMatrix3D& m,CBound& result) const
debug_assert(this!=&result);
for (int i=0;i<3;++i) {
// handle translation
// handle translation
result[0][i]=result[1][i]=m(i,3);
// Now find the extreme points by considering the product of the
// min and max with each component of matrix
// Now find the extreme points by considering the product of the
// min and max with each component of matrix
for(int j=0;j<3;j++) {
float a=m(j,i)*m_Data[0][j];
float b=m(j,i)*m_Data[1][j];
float a=m(i,j)*m_Data[0][j];
float b=m(i,j)*m_Data[1][j];
if (a<b) {
result[0][i]+=a;
@@ -169,3 +171,41 @@ void CBound::Transform(const CMatrix3D& m,CBound& result) const
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Render the bounding box
void CBound::Render()
{
glBegin(GL_QUADS);
glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
glEnd();
}
+6 -1
View File
@@ -41,12 +41,17 @@ public:
CVector3D v=m_Data[1]-m_Data[0];
return v.X*v.Y*v.Z;
}
// return the centre of this bounding box
void GetCentre(CVector3D& centre) const {
centre=(m_Data[0]+m_Data[1])*0.5f;
}
/**
* Render: Render the surfaces of the bound object as polygons.
*/
void Render();
private:
CVector3D m_Data[2];
};
+5 -5
View File
@@ -25,7 +25,7 @@ public:
float _data2d[4][4];
// (Be aware that m(0,2) == _data2d[2][0] == _13, etc. This is to be considered a feature.)
};
public:
// constructors
CMatrix3D();
@@ -79,7 +79,7 @@ public:
// concatenate a rotation described by given quaternion
void Rotate(const CQuaternion& quat);
// set this matrix to given translation
// set this matrix to given translation
void SetTranslation(float x, float y, float z);
void SetTranslation(const CVector3D& vector);
@@ -101,11 +101,11 @@ public:
// return the translation component of this matrix
CVector3D GetTranslation() const;
// return left vector, derived from rotation
// return left vector, derived from rotation
CVector3D GetLeft() const;
// return up vector, derived from rotation
// return up vector, derived from rotation
CVector3D GetUp() const;
// return forward vector, derived from rotation
// return forward vector, derived from rotation
CVector3D GetIn() const;
// return a quaternion representing the matrix's rotation
CQuaternion GetRotation() const;
+37 -16
View File
@@ -588,6 +588,8 @@ void CRenderer::BeginFrame()
// init per frame stuff
m_ShadowRendered=false;
m_ShadowBound.SetEmpty();
m->shadow->SetCameraAndLight(m_CullCamera, m_LightEnv->m_SunDir);
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -846,22 +848,7 @@ void CRenderer::FlushFrame()
if (m_DisplayFrustum)
{
MICROLOG(L"display frustum");
glDepthMask(0);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ub(255,255,255,64);
m_CullCamera.Render(2);
glDisable(GL_BLEND);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
m_CullCamera.Render(2);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_CULL_FACE);
glDepthMask(1);
DisplayFrustum();
oglCheck();
}
@@ -904,6 +891,39 @@ void CRenderer::EndFrame()
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// DisplayFrustum: debug displays
// - white: cull camera frustum
// - red: bounds of shadow casting objects
void CRenderer::DisplayFrustum()
{
glDepthMask(0);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ub(255,255,255,64);
m_CullCamera.Render(2);
// glColor4ub(255,0,0,64);
// m_ShadowBound.Render();
glDisable(GL_BLEND);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3ub(255,255,255);
m_CullCamera.Render(2);
// glColor3ub(255,0,0);
// m_ShadowBound.Render();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
m->shadow->RenderDebugDisplay();
glEnable(GL_CULL_FACE);
glDepthMask(1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// SetCamera: setup projection and transform of camera and adjust viewport to current view
void CRenderer::SetCamera(const CCamera& viewCamera, const CCamera& cullCamera)
@@ -939,6 +959,7 @@ void CRenderer::Submit(CModel* model)
if (model->GetFlags() & MODELFLAG_CASTSHADOWS) {
PROFILE( "updating shadow bounds" );
m_ShadowBound += model->GetBounds();
m->shadow->AddShadowedBound(model->GetBounds());
}
// Tricky: The call to GetBounds() above can invalidate the position
+3
View File
@@ -311,6 +311,9 @@ protected:
void RenderShadowMap();
void ApplyShadowMap();
// debugging
void DisplayFrustum();
// RENDERER DATA:
/// Private data that is not needed by inline functions
CRendererInternals* m;
+109 -5
View File
@@ -42,7 +42,14 @@ struct ShadowMapInternals
CMatrix3D LightTransform;
// transform world space into texture space
CMatrix3D TextureMatrix;
// transform world space into light space
CMatrix3D NewLightTransform;
// transform light space into world space
CMatrix3D InvLightTransform;
// bounding box of shadowed objects in light space
CBound NewShadowBound;
// Helper functions
void BuildTransformation(
const CVector3D& pos,const CVector3D& right,const CVector3D& up,
@@ -69,6 +76,69 @@ ShadowMap::~ShadowMap()
delete m;
}
//////////////////////////////////////////////////////////////////////////////
// SetCameraAndLight: camera and light direction for this frame
void ShadowMap::SetCameraAndLight(const CCamera& camera, const CVector3D& lightdir)
{
CVector3D z = lightdir;
CVector3D y;
CVector3D x = camera.m_Orientation.GetIn();
CVector3D eyepos = camera.m_Orientation.GetTranslation();
z.Normalize();
x -= z * z.Dot(x);
if (x.GetLength() < 0.001)
{
// this is invoked if the camera and light directions almost coincide
// assumption: light direction has a significant Z component
x = CVector3D(1.0, 0.0, 0.0);
x -= z * z.Dot(x);
}
x.Normalize();
y = z.Cross(x);
// X axis perpendicular to light direction, flowing along with view direction
m->NewLightTransform._11 = x.X;
m->NewLightTransform._12 = x.Y;
m->NewLightTransform._13 = x.Z;
// Y axis perpendicular to light and view direction
m->NewLightTransform._21 = y.X;
m->NewLightTransform._22 = y.Y;
m->NewLightTransform._23 = y.Z;
// Z axis is in direction of light
m->NewLightTransform._31 = z.X;
m->NewLightTransform._32 = z.Y;
m->NewLightTransform._33 = z.Z;
// eye is at the origin of the coordinate system
m->NewLightTransform._14 = -x.Dot(eyepos);
m->NewLightTransform._24 = -y.Dot(eyepos);
m->NewLightTransform._34 = -z.Dot(eyepos);
m->NewLightTransform._41 = 0.0;
m->NewLightTransform._42 = 0.0;
m->NewLightTransform._43 = 0.0;
m->NewLightTransform._44 = 1.0;
m->NewLightTransform.GetInverse(m->InvLightTransform);
m->NewShadowBound.SetEmpty();
}
//////////////////////////////////////////////////////////////////////////////
// AddShadowedBound: add a world-space bounding box to the bounds of shadowed
// objects
void ShadowMap::AddShadowedBound(const CBound& bounds)
{
CBound lightspacebounds;
bounds.Transform(m->NewLightTransform, lightspacebounds);
m->NewShadowBound += lightspacebounds;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BuildTransformation: build transformation matrix from a position and standard basis vectors
// TODO: Shouldn't this be part of CMatrix3D?
@@ -195,7 +265,7 @@ void ShadowMapInternals::CalcShadowMatrices(const CBound& bounds)
TextureMatrix.SetTranslation(dx,dy,0); // transform (-0.5, 0.5) to (0,1) - texture space
tmp2.SetScaling(dx,dy,0); // scale (-1,1) to (-0.5,0.5)
TextureMatrix = TextureMatrix*tmp2;
TextureMatrix = TextureMatrix * LightProjection; // transform light -> projected light space (-1 to 1)
TextureMatrix = TextureMatrix * LightTransform; // transform world -> light space
@@ -341,7 +411,7 @@ void ShadowMapInternals::CalcShadowMatrices(const CBound& bounds)
void ShadowMap::SetupFrame(const CBound& visibleBounds)
{
m->CalcShadowMatrices(visibleBounds);
if (!m->Texture)
{
// get shadow map size as next power of two up from view width and height
@@ -374,11 +444,11 @@ void ShadowMap::SetupFrame(const CBound& visibleBounds)
void ShadowMap::BeginRender()
{
// HACK HACK: this depends in non-obvious ways on the behaviour of the caller
CRenderer& renderer = g_Renderer;
int renderWidth = renderer.GetWidth();
int renderHeight = renderer.GetHeight();
// clear buffers
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@@ -428,3 +498,37 @@ const CMatrix3D& ShadowMap::GetTextureMatrix()
{
return m->TextureMatrix;
}
//////////////////////////////////////////////////////////////////////////////
// RenderDebugDisplay: debug visualizations
// - blue: objects in shadow
void ShadowMap::RenderDebugDisplay()
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(&m->InvLightTransform._11);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ub(0,0,255,64);
m->NewShadowBound.Render();
glDisable(GL_BLEND);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3ub(0,0,255);
m->NewShadowBound.Render();
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 50.0);
glEnd();
glBegin(GL_POLYGON);
glVertex3f(0.0, 0.0, 50.0);
glVertex3f(50.0, 0.0, 50.0);
glVertex3f(0.0, 50.0, 50.0);
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPopMatrix();
}
+27 -4
View File
@@ -33,23 +33,40 @@ public:
ShadowMap();
~ShadowMap();
/**
* SetCameraAndLight: Configure light space for the given camera and light direction
*
* @param camera the camera that will be used for world rendering
* @param lightdir the direction of the (directional) sunlight
*/
void SetCameraAndLight(const CCamera& camera, const CVector3D& lightdir);
/**
* AddShadowedBound: Add the bounding box of an object that has to be shadowed.
* This is used to calculate the bounds for the shadow map.
*
* @param bounds world space bounding box
*/
void AddShadowedBound(const CBound& bounds);
/**
* SetupFrame: Setup shadow map texture and matrices for this frame.
*
* @deprecated ???
* @param visibleBounds bound around objects that are visible on the screen
*/
void SetupFrame(const CBound& visibleBounds);
/**
* BeginRender: Set OpenGL state for rendering into the shadow map texture.
*
*
* @todo this depends in non-obvious ways on the behaviour of the call-site
*/
void BeginRender();
/**
* EndRender: Finish rendering into the shadow map.
*
*
* @todo this depends in non-obvious ways on the behaviour of the call-site
*/
void EndRender();
@@ -60,7 +77,7 @@ public:
* @return the texture name of the shadow map texture
*/
GLuint GetTexture();
/**
* GetTextureMatrix: Retrieve the world-space to shadow map texture coordinates
* transformation matrix.
@@ -70,6 +87,12 @@ public:
*/
const CMatrix3D& GetTextureMatrix();
/**
* RenderDebugDisplay: Visualize shadow mapping calculations to help in
* debugging and optimal shadow map usage.
*/
void RenderDebugDisplay();
private:
ShadowMapInternals* m;
};