Projective Shadows Problem

Started by
-1 comments, last by Chacha 19 years, 7 months ago
I have implemented simple projective shadows using OpenGL (described in 'OpenGL Game Programming', and also described here), but I'm having problems with projecting shadows onto more than one plane. Projecting one shadow is no problem, but if I have more than one shadow, the shadows appear incorrectly (they appear infront of the shadow plane). I know that I need to use the depth buffer to correctly draw multiple shadows, but I don't know how. In what order should I draw the objects/shadows so that it looks right? And how do I use the depth buffer correctly to achieve this? Here is my rendering code, just in case:

/* Here is some relevant information regarding my rendering code:

Functions:
		
	- DrawShadowPlane1(): draws the floor plane
	- DrawShadowPlane2(): draws the wall plane
	- DrawShadowedObjects(): draws the object/s that will cast shadows

Planes:

	- Plane plane1;    (a = 0, b = 1, c = 0, d = 0)  --> this is the floor plane
	- Plane plane2;    (a = 1, b = 0, c = 0, d = 20) --> this is the wall plane
			
Projection matrices:

	- float projectionMatrix1[16];
	- float projectionMatrix2[16];

And I have a single point light source:

	- float lightPos[4] = { ... };
*/

////////////////////////////////////////////////////////////////

    // Firstly, I create the projection matrices:

    // Create the first projection matrix (for projection onto the floor plane)
    Vector3 normal = plane.GetNormal();
    float distance = plane.GetDistance();

    float dot = (lightPos[0] * normal.x) + (lightPos[1] * normal.y) + (lightPos[2] * normal.z) + (lightPos[3] * distance);

    projectionMatrix[0] = dot - lightPos[0] * normal.x;
    projectionMatrix[1] = -lightPos[1] * normal.x;
    projectionMatrix[2] = -lightPos[2] * normal.x;
    projectionMatrix[3] = -lightPos[3] * normal.x;

    projectionMatrix[4] = -lightPos[0] * normal.y;
    projectionMatrix[5] = dot -lightPos[1] * normal.y;
    projectionMatrix[6] = -lightPos[2] * normal.y;
    projectionMatrix[7] = -lightPos[3] * normal.y;

    projectionMatrix[8] = -lightPos[0] * normal.z;
    projectionMatrix[9] = -lightPos[1] * normal.z;
    projectionMatrix[10] = dot -lightPos[2] * normal.z;
    projectionMatrix[11] = -lightPos[3] * normal.z;

    projectionMatrix[12] = -lightPos[0] * distance; 
    projectionMatrix[13] = -lightPos[1] * distance;
    projectionMatrix[14] = -lightPos[2] * distance; 
  
    // Create the second projection matrix (for projection onto the wall plane)
    normal = plane2.GetNormal();
    distance = plane2.GetDistance();

	dot = (lightPos[0] * normal.x) + (lightPos[1] * normal.y) + (lightPos[2] * normal.z) + (lightPos[3] * distance);

    projectionMatrix2[0] = dot - lightPos[0] * normal.x;
    projectionMatrix2[1] = -lightPos[1] * normal.x;
    projectionMatrix2[2] = -lightPos[2] * normal.x;
    projectionMatrix2[3] = -lightPos[3] * normal.x;

    projectionMatrix2[4] = -lightPos[0] * normal.y;
    projectionMatrix2[5] = dot -lightPos[1] * normal.y;
    projectionMatrix2[6] = -lightPos[2] * normal.y;
    projectionMatrix2[7] = -lightPos[3] * normal.y;

    projectionMatrix2[8] = -lightPos[0] * normal.z;
    projectionMatrix2[9] = -lightPos[1] * normal.z;
    projectionMatrix2[10] = dot -lightPos[2] * normal.z;
    projectionMatrix2[11] = -lightPos[3] * normal.z;

    projectionMatrix2[12] = -lightPos[0] * distance; 
    projectionMatrix2[13] = -lightPos[1] * distance;
    projectionMatrix2[14] = -lightPos[2] * distance; 
    projectionMatrix2[15] = dot -lightPos[3] * distance;


    // DRAW SHADOW 1 ///////////////////////////////////////////////

    // Draw the plane that the shadow will project onto
    DrawShadowPlane1();

    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);
    glEnable(GL_STENCIL_TEST);
    
    // Draw the shadow plane into the stencil buffer
    glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
    DrawShadowPlane1();
    
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glDepthMask(GL_TRUE);
    
    // Restrict drawing to the shadow plane
    glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    // Draw the shadow (blended with the shadow plane)
    // The depth buffer is disabled to prevent z-fighting
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
    glPushMatrix();
	    glMultMatrixf(projectionMatrix1);
	    DrawShadowedObjects();
    glPopMatrix();
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_STENCIL_TEST);

    // DRAW SHADOW 2 ///////////////////////////////////////////////

    // Draw the plane that the shadow will project onto
    DrawShadowPlane2();

    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);
    glEnable(GL_STENCIL_TEST);
	
    // Draw the shadow plane into the stencil buffer
    glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
    DrawShadowPlane2();
	
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glDepthMask(GL_TRUE);
	
    // Restrict drawing to the shadow plane
    glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    // Draw the shadow (blended with the shadow plane)
    // The depth buffer is disabled to prevent z-fighting
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
    glPushMatrix();
	    glMultMatrixf(projectionMatrix2);
	    DrawShadowedObjects();
    glPopMatrix();
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_STENCIL_TEST);


    ////////////////////////////////////////////////////////////////

    // And lastly I draw the objects that cast the shadows
    glColor3f(1.0f, 1.0f, 1.0f);
    DrawShadowedObjects();


And here are some screenshots I took of my problem: Clicky Any help is appreciated.

This topic is closed to new replies.

Advertisement