GL_ARB_shadow
The GL_ARB_shadow extension allows us to create simple shadow maps. It requires the GL_ARB_depth_texture extension. For more information on the theory and implementation of shadow maps see NVidia’s hardware shadow maps document.
The theory behind using shadow maps is very simple and can be summed up in one sentence. Any point that the light can not see is in shadow. To implement this, we take a picture of the scene from the light’s point of view, then compare it to the picture of the scene from the camera’s point of view. Because we never use the color information from the light’s point of view, we can just take the depth information and store it in a texture to compare with later. This is where we need the depth texture. Note that a single depth texture can not cover the entire scene; to do this one would need to use multiple textures. Typically depth textures are used with spotlights, or in games like Guild Wars and Battlefield 2, a depth texture is used on each model that needs a shadow.
In order to speed things up, we break the world into two parts, shadow casters and shadow recievers. When we take the depth texture we make sure to only render the shadow casters. Then we render the entire scene from the camera’s viewpoint, when coloring each pixel, the 3D location of the point in camera space is converted into a 3D point in light space using a well defined method. This, in essence, will give us the distance to the light. If this distance is larger than the distance in the shadow map, then this point is in shadow, and colored appropriatly, otherwise it is colored normally.
In order to convert a point in camera space to a point in light space we simply multiply it by the various matrices that we use to render it to the screen. First, an overview. When we send a vertex into OpenGL using glVertex, it is multiplied by the camera’s modelview matrix MC. In order to get the vertex back, we must multiply by the inverse of the camera’s modelview MC-1. If everything is set up correctly, the result is the same vertex sent into OpenGL when creating the depth texture. The result is then multiplied by the light’s modelview matrix ML and the light’s projection matrix PL. This gives us the exact same result as the depth texture with one caveat. The projected points go from -1 to 1, whereas textures go from 0 to 1. This is easily overcome by scaling the result by half, then translated by 0.5. This is accomplished with the bias matrix B. Now, the point that we are considering is in texture space of the shadow map. If the input was {x, y, z, w} and the output is {s, t, r, q}, then the value of the shadow map at {s, t} is the depth that the light sees, but r is the distance from the point in quiestion to the light. So if we compare the depth in the texture to r, we know whether or not the point is in shadow. This is the reasoning for the texture property added by the extension. We will enable glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB). The way we compare is to say a point is not in shadow when the depth is less than or equal to r, it is in shadow otherwise. Hence glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL).
The matrices above are easily found. ML is given as the the matrix from the gluLookAt command, PL is given with whatever you used to set up the projection matrix (in our example, we keep the projection matrix the same between the light and camera views, so we just grab the current projection matrix). The bias matrix B is well defined and set up in the code below. The only tricky part is finding the inverse of the camera’s modelview matrix. It turns out that if we enable texture coordinate generation with GL_EYE_LINEAR, and GL_EYE_PLANE, OpenGL supplies the inverse for us.
Read more about GL_ARB_shadow