GL_ARB_shadow

getShadowMap()

Now it starts to get interesting. To get the shadow map, we need to turn off drawing to the color buffer (it’s a waste of time and we would need to clear it afterwards if we drew to it). We then set up the light source viewpoint using gluLookAt. If you really want to get into it, you would also set up a light specific projection matrix, but GLWindow’s default matrix is good enough for this example. We also set up the polygon offset. To get a better understanding of what this does, I suggest looking it up in the OpenGL 2.0 specs. Basically, it alters the depth value stored in the depth buffer while rendering and helps us avoid problems during the comparison step of shadow mapping. Now that we are all set up, we draw the shadow casters in the scene, copy the depth buffer and set everything back that we changed (color mask, depth buffer, and modelview matrix).

// draws the shadow casters from the light view's
// location and saves depth values to a texture
void getShadowMap()
{
	// turn off drawing to the color buffer
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

	gluLookAt(
		0.0, 0.0, 5.0,
		0.0, 0.0, 0.0,
		0.0, 1.0, 0.0);

	glPolygonOffset(10.0, 4.0);
	glEnable(GL_POLYGON_OFFSET_FILL);

	drawShadowCasters(false);

	glDisable(GL_POLYGON_OFFSET_FILL);

	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, SIZE, SIZE, 0);

	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

	// clear the depth buffer and current matrix
	glClear(GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

}

setupMatrices()

Now we set up all those matrices that we talked about earlier. The bias matrix is created first and is well known. The light’s modelview matrix is taken from the same gluLookAt code used earlier and the light’s projection matrix is read from the current GL_PROJECTION_MATRIX. These three matrices are then multiplied together into the GL_TEXTURE_MATRIX. An identity matrix is then created and loaded into the code that will generate texture coordinates for use. This is the part that gives us the inverse of the camera’s modelview matrix. Look it up in the OpenGL 2.0 specs for more information.

void setupMatrices()
{
	// matrices
	double proj[16];
	double light[16];
	double bias[16] =
	{
		0.5, 0.0, 0.0, 0.0,
		0.0, 0.5, 0.0, 0.0,
		0.0, 0.0, 0.5, 0.0,
		0.5, 0.5, 0.5, 1.0
	};

	double texMatrix[16];

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();

	glGetDoublev(GL_PROJECTION_MATRIX, proj);

	glPushMatrix();
	{
		gluLookAt(
			0.0, 0.0, 5.0,
			0.0, 0.0, 0.0,
			0.0, 1.0, 0.0);
		glGetDoublev(GL_TEXTURE_MATRIX, light);
	}
	glPopMatrix();

	glLoadIdentity();
	glMultMatrixd(bias);
	glMultMatrixd(proj);
	glMultMatrixd(light);

	memset(texMatrix, 0, 16*sizeof(double));
	for(int i = 0; i < 4; i++) texMatrix[i*4 + i] = 1.0;

	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
	glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);

	glTexGendv(GL_S, GL_EYE_PLANE, &texMatrix[0]);
	glTexGendv(GL_T, GL_EYE_PLANE, &texMatrix[4]);
	glTexGendv(GL_R, GL_EYE_PLANE, &texMatrix[8]);
	glTexGendv(GL_Q, GL_EYE_PLANE, &texMatrix[12]);

	glMatrixMode(GL_MODELVIEW);
}

draw()

And finally, we reach the draw method. It was shown earlier, but I'll just metion how it pulls everything together. We start it as we start any draw method: by clearing the depth and color buffers and loading the identity matrix. We then get the shadow map and set up the camera. The matrices are set up after the call to gluLookAt; this is important because it is how we get the inverse of the modelview matrix. Then we draw the scene.

void draw()
{
	// clear buffers and load indentity matrix
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	getShadowMap();

	gluLookAt(
		-5.0, 3.0, 5.0,
		0.0, 0.0, -1.0,
		0.0, 0.0, 1.0);

	setupMatrices();

	drawShadowCasters(true);
	drawShadowRecievers();
}

Pages: 1 2 3 4 5 6

2 Comments »

24

Pingback by BitwiseOR » GL_ARB_shadow_funcs

January 10, 2006 @ 3:10 pm

[...] The GL_ARB_shadow_funcs extension requires GL_ARB_shadow and GL_ARB_depth_texture in order to have any effect. In the GL_ARB_shadow example on this site we use GL_LEQUAL when setting the GL_TEXTURE_COMPARE_FUNC_ARB texture parameter. GL_ARB_shadow allows this comparison function to be GL_GEQUAL as well, but not any of the other comparison functions. [...]

25

Pingback by » OpenGL Transforms and the Inverse Model View

August 14, 2006 @ 9:46 am

[...] It is important to realise that OpenGL’s Model View matrix is actually M * C, so, if we want to get the position of the vertex in world space, we will have to use the modelview matrix to go to camera space, then multiply by C-1 (the inverse of the camera matrix). This gives us V * M * C * C-1 = V * gl_ModelViewMatrix * C-1 = V * M. And world space is exactly what we need to do shadow mapping, refraction, reflectiona and a plethora of other things. OpenGL took care of this for us with the GL_ARB_Shadow extension. By using glTexGen, OpenGL computes the inverse camera matrix and applies it without us having to fuss with inverses. But, now we’ll need to do an inverse ourselves. [...]

RSS feed for comments on this post. TrackBack URI

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>