Shadow Experts,
I implemented an OpenGL Performer program that makes shadows using the shadow mapping method. The program works fine if the polygons in the scene are not textured, but I don't get any shadows if the polygons are textured.
Below are fragments from my source code (modified from
Paul's Project). Please let me know if you find any errors.
Function that initializes the shadow texture:
//Called for initiation
bool Init(void)
{
//Shading states
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
//Depth states
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
//We use glScale when drawing the scene
glEnable(GL_NORMALIZE);
//Create the shadow map texture
glGenTextures(1, &shadowMapTexture);
glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapSize, shadowMapSize, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
return true;
}
Here are the 3 draw passes that generate shadows:
// Draw process callback
void DrawChannel (pfChannel *chan, void *)
{
//First pass - from light's point of view
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// set the modelview matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixd(light_proj_mat);
// set the modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd(light_view_mat);
//Use viewport the same size as the shadow map
glViewport(0, 0, shadowMapSize, shadowMapSize);
//Draw back faces into the shadow map
glPolygonOffset(2.5, 5);
glEnable(GL_POLYGON_OFFSET_FILL);
//Disable color writes, and use flat shading for speed
glShadeModel(GL_FLAT);
glColorMask(0, 0, 0, 0);
//Draw the scene
pfDraw();
//Read the depth buffer into the shadow map texture
glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize);
glDisable(GL_POLYGON_OFFSET_FILL);
glShadeModel(GL_SMOOTH);
glColorMask(1, 1, 1, 1);
//------------------------------------------------------------
//2nd pass - Draw from camera's point of view
glClear(GL_DEPTH_BUFFER_BIT);
// set the modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd(eye_view_mat);
glViewport(0, 0, shadowMapSize, shadowMapSize);
//Use dim light to represent shadowed areas
glLightfv(GL_LIGHT1, GL_POSITION, lightPosition);
glLightfv(GL_LIGHT1, GL_AMBIENT, black);
glLightfv(GL_LIGHT1, GL_DIFFUSE, black);
glLightfv(GL_LIGHT1, GL_SPECULAR, black);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
pfDraw();
//------------------------------------------------------------
//3rd pass
//Draw with bright light
glLightfv(GL_LIGHT1, GL_DIFFUSE, white);
glLightfv(GL_LIGHT1, GL_SPECULAR, white);
//Calculate texture matrix for projection
//This matrix takes us from eye space to the light's clip space
//It is postmultiplied by the inverse of the current view matrix when specifying texgen
double bias_mat[16]={0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f}; //bias from [-1, 1] to [0, 1]*/
double *tex_mat1;//=bias_mat*lightProjectionMatrix*lightViewMatrix;
double *tex_mat;//=bias_mat*lightProjectionMatrix*lightViewMatrix;
tex_mat1=matrixMultiplication(bias_mat, light_proj_mat);
tex_mat=matrixMultiplication(tex_mat1, light_view_mat);
//Set up texture coordinate generation.
GLfloat tempS[4]={tex_mat[0], tex_mat[4], tex_mat[8], tex_mat[12]};
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_S, GL_EYE_PLANE, tempS);
glEnable(GL_TEXTURE_GEN_S);
GLfloat tempT[4]={tex_mat[1], tex_mat[5], tex_mat[9], tex_mat[13]};
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_T, GL_EYE_PLANE, tempT);
glEnable(GL_TEXTURE_GEN_T);
GLfloat tempR[4]={tex_mat[2], tex_mat[6], tex_mat[10], tex_mat[14]};
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_R, GL_EYE_PLANE, tempR);
glEnable(GL_TEXTURE_GEN_R);
GLfloat tempQ[4]={tex_mat[3], tex_mat[7], tex_mat[11], tex_mat[15]};
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_Q, GL_EYE_PLANE, tempQ);
glEnable(GL_TEXTURE_GEN_Q);
//Bind & enable shadow map texture
glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
glEnable(GL_TEXTURE_2D);
//Enable shadow comparison
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
//Shadow comparison should be true (ie not in shadow) if r<=texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
//Shadow comparison should generate an INTENSITY result
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
//Set alpha test to discard false comparisons
glAlphaFunc(GL_GEQUAL, 0.99f);
glEnable(GL_ALPHA_TEST);
pfDraw();
//Disable textures and texgen
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
//Restore other states
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
//Restore other states
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
}