Sheet 05: Shadows

Exercise: Shadows (30 Points)

Reuse your submission for assignment 4 as your codebase for this assignment or start from the fifth project from github.

Add shadows to the scene implemented with shadow mapping. It is required that the teapot casts a shadow onto itself and onto the ground plane. The light source's default position should be changed to (-80, 60, 80) and by pressing the space bar it should start rotating as usual. It is sufficient to use a single shadow map. Similar to the previous assignments: Do not change the initial viewing angle of the scene for your submission!

To implement shadow mapping split the rendering process into two passes. In the first pass the shadow map is rendered and in the second pass the previously rendered shadow map is used to apply shadows to the scene.

A shadow map is a depth rendering of the scene from a light's view. For rendering the shadow map create a framebuffer object and configure it accordingly. Create a texture that stores depth values and attach it as a GL_DEPTH_ATTACHMENT to that framebuffer. You may want to take a look at the GLFramebuffer and GLDepthTexture-classes in the Utils-folder. Then render all shadow casting objects to that framebuffer. For the view matrix you can use the provided Mat4::lookAt function and as projection use a perspective projection. The attached texture will be used as depth buffer when rendering to that framebuffer and ultimately represents the shadow map.

In the second rendering pass use the rendered shadow map to shade the fragments accordingly. In the phong vertex shader transform in addition the vertex position into light space. This can be achieved using a view-to-light-matrix or world-to-light-matrix (depending on what space you want to use), see Figure 1 for an explanation of the view-to-light-matrix. The resulting coordinates represent the vertex position seen from the light's view. In addition a bias is applied such that the coordinates can be used for sampling a texture. In the fragment shader you can use this coordinate to sample the shadow map. To know whether a fragment is in shadow or lit by the light, the sampled value must be compared to the fragments depth. If a fragment is in shadow apply to the diffuse and specular color term a factor of 0 such that the fragment only gets contribution from the ambient term. This fragment shader part can also be done using built in OpenGL functionality. To use this functionality you need a different sampler2D for the shadow map named sampler2DShadow and further set additional texture parameter to the depth texture.

Transform a view-space position back to world space, then into light view and projection space; a bias maps clip coordinates to shadow texture coordinates.

Figure 1: The View To Light Matrix.

Loading

Solution.
Use the mouse to interact with the scene. Spacebar: Toggles animation on/off R key: Resets the animation and the view

Text description and demo controls

A teapot and a textured ground plane are lit by a point light. A shadow map stores scene depths as seen from the light. In the final view, a fragment is shadowed when its light-space depth lies behind the stored surface depth.

Shadowed fragments keep the ambient contribution, while direct diffuse and specular contributions are removed. When the light moves, the shadow moves across the ground. A small depth bias prevents surfaces from incorrectly shadowing themselves.

Focus the demo with Tab. Space starts or pauses the light animation; R resets animation and view. Camera rotation and panning currently require mouse dragging.