diff --git a/source/maths/Bound.cpp b/source/maths/Bound.cpp index ecc6f4f0b0..2f1a9092fd 100755 --- a/source/maths/Bound.cpp +++ b/source/maths/Bound.cpp @@ -10,6 +10,8 @@ // necessary includes +#include "ogl.h" + #include #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[1][1])) + if (dir[1]==0 && (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 (t1tnear) + if (t1>tnear) tnear = t1; - if (t2tfar || tfar<0) + if (tnear>tfar || tfar<0) return false; } - if (dir[2]==0 && (origin[2]m_Data[1][2])) + if (dir[2]==0 && (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 (t1tnear) + if (t1>tnear) tnear = t1; - if (t2tfar || 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 (ashadow->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 diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 6250571faa..93f0913ac3 100755 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -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; diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp index 6ab8271588..785345fe32 100644 --- a/source/renderer/ShadowMap.cpp +++ b/source/renderer/ShadowMap.cpp @@ -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(); +} diff --git a/source/renderer/ShadowMap.h b/source/renderer/ShadowMap.h index fc59e96b2d..dab1ee9e5e 100644 --- a/source/renderer/ShadowMap.h +++ b/source/renderer/ShadowMap.h @@ -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; };