As described in this blog category’s previous posts (cross-platform SDL demos), I did initial development on this project in Nov Dec of 2013.  After the holiday breaks, I was back to being busy with my day job, and doing other learning on the side (such as more general Computer Science algorithms) (one example is algorithms for trees and tries).  Then this weekend, I resurrected my “cross-platform SDL demos” project and implemented shadow mapping.  (Aside – I wrote this on my laptop because in the background I was replacing my desktop computer’s motherboard and reinstalling the OS etc).s

In other blog posts (CG intro Harvard), I’ve mentioned the 2008 Harvard extension school introduction to computer graphics video lectures ( https://itunes.apple.com/us/itunes-u/csci-e-234-introduction-to/id429428034?mt=10 ) ( http://dev.miroguide.com/items/3985688 ).  Lecture 7 gives a great overview of shadow mapping.

Screen shot from 55m 36s shows the idea of doing two draw calls – one from the perspective of the light (draws to the shadow map), and one from the perspective of the camera (draws to the screen).  Screen shot from 54m shows that an object (a position in the vertex shader, or pixel shader) shares object space and world space in both spaces (light space and eye space).  If you want to know, for a particular pixel (fragment) in camera space whether that pixel is in shadow, you need to check the shadow map using that pixel’s position in light space.

Another of my favorite learning resources, Essential Mathematics for Games & Interactive Applications – A Programmer’s Guide (by James M. Van Verth, Lars M. Bishop), doesn’t go into shadow mapping. Section 8.12 (second edition page 367) (in the Lighting chapter) has a one page overview that explains how shadows are different than lighting. The book explains – “Shadowing is generally a multipass technique over the entire scene”.  Also – “Since the real core of shadowing methods lie in the structure of the two-pass algorithms rather than in the mathematics of lighting, the details of this shadowing algorithms are beyond the scope of this book”.

I mention this because one interesting thing about my shadow mapping implementation is that I do not implement lighting (ie no Phong illumination, no bump mapping).  Shadow mapping does an extra off-screen draw call (from the perspective of the light) to create the shadow map. Then each of your scene’s on-screen draw calls (from the perspective of the camera) need to check the shadow map in their shader code, to determine whether a given pixel fragment is in shadow.  It’s optional whether you also do other things in your shader (eg texturing, Phong lighting, bump mapping).

To implement shadow mapping in my SDL project, I looked at this tutorial ( http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ ).  One quirk I noticed with the sample code is that it’s “depthModelMatrix” and "ModelMatrix” happen to both be the identity matrix, so it is okay to do (depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix), then (depthBiasMVP = biasMatrix*depthMVP). However, for my project, I use each object’s own model matrix in the second draw call.

Shadow mapping screen shots with light rays perpendicular to the boxes.  Also shows rendering the shadow map (depth values drawn from the light’s perspective) to the screen:

When I moved the light to a different angle, I got horrible shadow acne:

One way to avoid the shadow acne is to use a depth bias (polygon offset) when rendering the shadow map.
glPolygonOffset(2.0f, 1.0f);
glEnable(GL_POLYGON_OFFSET_FILL);

There’s a good article here ( http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx ) to give more ideas on how to improve a shadow map implementation to reduce artifacts related to precision, aliasing, shadow acne, shimmering edges, peter panning.