Yes I do that. But I don’t see why it would be a bias problem as that wrongly shadowed area faces the light completely. Here is the scene from light’s perspective:
I did try to play around with some offset values using glPolygonOffset() but it seems that the correct and uncorrect shadow is connected tightly together, as they come out and disappear at the same values:
Here is the rendering code if anybody cares to look at it.
/* File: Renderer.cpp | Author: Dogan Demir | 2008 */
#include "Renderer.h"
#include "Polygon.h"
#include "SystemManager.h"
//Biggest power of two texture with a 800x600 window is 512x512
#define DEPTH_TEXTURE_WIDTH 512
#define DEPTH_TEXTURE_HEIGHT 512
#define SCENE_SIZE 40.f
Renderer::Renderer( EntityManager* entityManager ) : entityManager_(entityManager)
{
activeShader_ = 0;
}
bool
Renderer::initialize()
{
glEnable( GL_TEXTURE_2D );
glEnable( GL_DEPTH_TEST );
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
glClearColor( 0.0, 0.0, 0.0, 1.f );
_initializeApplicationSpecific();
return true;
}
void
Renderer::_initializeApplicationSpecific()
{
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
lightPosition_ = Vec4D( 10.f, 50.0f, 40.f );
lightTarget_ = Vec4D( 0.2f, 0.3f, 0.4f );
//Calculate light view and projection matrices
glPushMatrix();
//Light matrices
glLoadIdentity();
gluPerspective( 45.0f, 1.0f, 1.0f, 100.0f );
glGetFloatv( GL_MODELVIEW_MATRIX, reinterpret_cast<float*>( &lightProjMatrix_ ) );
glLoadIdentity();
gluLookAt( lightPosition_.x, lightPosition_.y, lightPosition_.z, lightTarget_.x, lightTarget_.y, lightTarget_.z, 0.f, 1.f, 0.f );
glGetFloatv( GL_MODELVIEW_MATRIX, reinterpret_cast<float*>( &lightViewMatrix_ ) );
glPopMatrix();
glGenTextures( 1, &depthTexture_ );
glBindTexture( GL_TEXTURE_2D, depthTexture_ );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, DEPTH_TEXTURE_WIDTH, DEPTH_TEXTURE_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
glClearDepth( 1.0f );
glDepthFunc( GL_LEQUAL );
biasMatrix_ = Mat44( Vec4D( 0.5, 0, 0, 0.5 ),
Vec4D( 0.0, 0.5, 0, 0.5 ),
Vec4D( 0, 0, 0.5, 0.5 ),
Vec4D( 0, 0, 0, 1 ) );
}
void
Renderer::destroy()
{
glDeleteTextures( 1, &depthTexture_ );
}
void
Renderer::draw()
{
glClear( GL_DEPTH_BUFFER_BIT );
_drawToDepthTexture();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glActiveTextureARB( GL_TEXTURE1 );
glMatrixMode( GL_TEXTURE );
glLoadMatrixf( reinterpret_cast<float*>( &biasMatrix_ ) );
glMultMatrixf( reinterpret_cast<float*>( &lightProjMatrix_ ) );
glMultMatrixf( reinterpret_cast<float*>( &lightViewMatrix_ ) );
glMatrixMode( GL_MODELVIEW );
glActiveTextureARB( GL_TEXTURE0 );
_drawScene( RG_ALL );
//_drawDepthMap();
glutSwapBuffers();
glutPostRedisplay();
}
void
Renderer::_drawToDepthTexture()
{
glViewport( 0, 0, DEPTH_TEXTURE_WIDTH, DEPTH_TEXTURE_HEIGHT );
glColorMask( 0, 0, 0, 0 );
//glEnable( GL_POLYGON_OFFSET_FILL );
//glPolygonOffset( 100.0f, 555.0f );
glCullFace( GL_FRONT );
glMatrixMode( GL_PROJECTION_MATRIX );
glPushMatrix();
glLoadMatrixf( reinterpret_cast<float*>( &lightProjMatrix_ ) );
glMatrixMode( GL_MODELVIEW_MATRIX );
glPushMatrix();
glLoadMatrixf( reinterpret_cast<float*>( &lightViewMatrix_ ) );
_drawScene( RG_ALL );
glBindTexture( GL_TEXTURE_2D, depthTexture_ );
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, DEPTH_TEXTURE_WIDTH, DEPTH_TEXTURE_HEIGHT );
glMatrixMode( GL_PROJECTION_MATRIX );
glPopMatrix();
glMatrixMode( GL_MODELVIEW_MATRIX );
glPopMatrix();
glCullFace( GL_BACK );
//glDisable( GL_POLYGON_OFFSET_FILL );
glColorMask( 1, 1, 1, 1 );
Vec2D winSize = SystemManager::getInstance().getGlutManager()->getWindowSize();
glViewport( 0, 0, winSize.x, winSize.y );
}
void
Renderer::_drawScene( RENDER_GROUP renderGroup )
{
Vector< Vector<Entity*> > renderQueue = entityManager_->getRenderQueue();
Vector< Vector<Entity*> >::iterator iterQ;
Vector<Entity*>::iterator iterE;
//All queues...
for( iterQ = renderQueue.begin(); iterQ != renderQueue.end(); iterQ++ )
{
//All entities...
for( iterE = iterQ->begin(); iterE != iterQ->end(); iterE++ )
{
if( (*iterE)->isVisible() )
{
if( renderGroup == RG_ALL )
{
_drawEntity( *iterE );
}
}
}
}
}
void
Renderer::_drawEntity( Entity* entity )
{
//Apply transformation
glPushMatrix();
glMultMatrixf( reinterpret_cast<float*>( entity->getTransform() ) );
glActiveTexture( GL_TEXTURE1 );
glMatrixMode( GL_TEXTURE );
glPushMatrix();
glMultMatrixf( reinterpret_cast<float*>( entity->getTransform() ) );
glMatrixMode( GL_MODELVIEW );
//For each mesh...
Mesh* mesh = entity->getMesh();
Vector<Polygon>* polygons = mesh->getPolygonList();
Vector<Vertex>* vertices = mesh->getVertexList();
//Apply shader
uInt shader = entity->getShader();
if( shader != NO_SHADER )
{
//Don't bother calling OpenGL if we're gonna use the previous shader
if( shader != activeShader_ )
{
glUseProgram( shader );
activeShader_ = shader;
}
Map<String, ParameterInfo> parameters = entity->getShaderParameters();
Map<String, ParameterInfo>::iterator iter;
float values[3];
for( iter = parameters.begin(); iter != parameters.end(); iter++ )
{
switch( iter->second.type )
{
case PT_3FV:
{
values[0] = iter->second.value[0];
values[1] = iter->second.value[1];
values[2] = iter->second.value[2];
glUniform3fv( glGetUniformLocation( shader,
iter->first.c_str() ),
1,
values );
}
break;
case PT_F:
{
values[0] = iter->second.value[0];
glUniform1fv( glGetUniformLocation( shader,
iter->first.c_str() ),
1,
values );
}
break;
}
}
//Depth map hack
int dUniformLocation = glGetUniformLocation( shader, "depthMap" );
glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, depthTexture_ );
glUniform1i( dUniformLocation, 1 );
}
else
{
if( activeShader_ != 0 )
{
activeShader_ = 0;
glUseProgram(0);
}
}
//Apply texture
Vector<uInt>* textureList = entity->getTextureList();
uInt texture;
String tString;
for( uInt t = 0; t < textureList->size(); t++ )
{
texture = (*textureList)[t];
if( texture != NO_TEXTURE )
{
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, texture );
if( shader != NO_SHADER )
{
char tChar[] = { 'a', '\0' };
_itoa_s( t, tChar, 2, 10 );
tString += "texture";
tString += tChar;
int dUniformLocation = glGetUniformLocation( shader, tString.c_str() );
glUniform1i( dUniformLocation, 0 );
tString.clear();
}
}
}
//For each polygon of the mesh...
Vector<int>* indices;
Vector<Vec2D>* texCoord;
uInt polyCount = polygons->size();
uInt indxCount;
Vertex v;
Polygon polygon;
for( uInt j = 0; j < polyCount; j++ )
{
polygon = (*polygons)[j];
indices = polygon.getIndices();
indxCount = indices->size();
texCoord = polygon.getTexCoord();
glBegin( GL_TRIANGLES );
//For each vertex in each polygon of the mesh...
for( uInt k = 0; k < indxCount; k++ )
{
v = (*vertices)[(*indices)[k]];
glColor3f( v.color.x, v.color.y, v.color.z );
if( texCoord->size() )
{
Vec2D vTex = (*texCoord)[k];
glTexCoord2f( vTex.x, vTex.y );
}
else
{
glTexCoord2f( v.texCoord.x, v.texCoord.y );
}
glNormal3f( v.normal.x, v.normal.y, v.normal.z );
glVertex3f( v.position.x, v.position.y, v.position.z );
}
glEnd();
}
glPopMatrix();
glActiveTexture( GL_TEXTURE1 );
glMatrixMode( GL_TEXTURE );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glActiveTextureARB( GL_TEXTURE0 );
}
void
Renderer::_drawDepthMap()
{
Vec2D winSize = SystemManager::getInstance().getGlutManager()->getWindowSize();
//We will go from perspective to orthogonal projection to align the quad to the screen
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, winSize.x, 0, winSize.y );
activeShader_ = 0;
glUseProgram(0);
//Clear any previous model and view transformations
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glDisable( GL_DEPTH_TEST );
//Set additive blending
glBindTexture( GL_TEXTURE_2D, depthTexture_ );
//Draw the quad using 'screen' coordinates - resulting from orthogonal projection
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 ); glVertex3f( 0, 0, 0 );
glTexCoord2f( 1, 0 ); glVertex3f( winSize.x, 0, 0 );
glTexCoord2f( 1, 1 ); glVertex3f( winSize.x, winSize.y, 0 );
glTexCoord2f( 0, 1 ); glVertex3f( 0, winSize.y, 0 );
glEnd();
//Go back to perspective projection
glEnable( GL_DEPTH_TEST );
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}