mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 03:06:29 +00:00
- add CBound::Render()
- fix CBound::Transform() math - beginnings of new shadow bound calculations This was SVN commit r3436.
This commit is contained in:
+61
-21
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user