Horizon Mapping: Fast Terrain Lighting

Horizon Mapping using Gouraud Shading
The first work on this project was done quite some time ago. The goal was to implement terrain lighting and shadowing using only gouraud shading. This allows the terrain to be rendered by any down stream scenegraph/utility that can render per vertex colors.

The project computes the horizon for each point in a DEM file by maintaining a horizon contour as it sweeps across the DEM. At each point it computes the lighting and shadowing for the given location in the DEM, and converts it into a color which is stored at the vertex.

The key to this project is that the sun position and all of the lighting can be updated very quickly, allowing for dynamic movement of the sun.

The image to the right shows the results. Notice that the shadows improve the perception of the terrain height, but suffer from the limitation that the gouraud shading can't provide hard shadow edges. A major limitation to this technique is that as we reduce the number of triangles that are used to represent the terrain, the shadow definition decreases also.

Gouraud shaded Horizon Mapping.
Horizon Mapping using Fragment Programs
With the advent of fragment programs on graphics hardware, I decided to revisit this project to update it with a better implementation of horizon mapping. This phase of the project involved using all of the same code from the previous phase, including the horizon tracing code, but to utilize a slightly different approach to actually rendering the terrain shadows.

The project computes the height of the shadow boundary at each location in the terrain, same as in the previous implementation. Instead of computing whether the point is in the shadow at that time, the algorithm saves this height at each vertex and computes the full lighting for the vertex. At render time, a fragment program is run which compares the pixel's height versus the shadow boundary height. If the pixel's height is below the shadow boundary, it reduces the lighting at that point to an ambient/shadowed lighting. This technique is a per pixel shadow boundary comparison which produces hard edge shadows.

A texture map can be used to store the shadow boundary/horizon values but this project sends the data in an unused texture coordinate which will be interpolated across the triangles. This eliminates the texture look-up, which can be used for detail textures instead. This short-cut works because the terrain is being rendered at the same resolution as the horizon map. If we reduce the number of triangles used to represent the terrain, we have to switch to the horizon map in a texture to maintain the quality.

This technique is extremely simple to implement and provides greatly improved shadow boundaries. The technique also works well when the triangulation of the terrain is reduced unlike the previous approach. The image to the right shows the results.

Fragment Program Horizon Mapping.
Soft Shadows using Fragment Programs
In the above approach, we were able to achieve good shadow definition using the fragment program and horizon mapping. One minor distraction is that the shadow boundaries are hard / sharp. The shadow abruptly stops, when passing into or out of the shadowed regions. Typically this is not the case for outdoor shadows especially not for terrains. There should be a softness to the shadow edge.

This project modified the fragment program in the previous project to cause a ramp between the unshadowed and shadowed values when the pixel height was within a specific range of the shadow height. The fragment program in the previous approach was 5 instructions, and this approach's program is only 6 instructions! By using a clamped linear expression, it was possible to keep the cost of this feature down to only one instruction.

The image to the right illustrates how the technique has improved the appearance of the shadow edges by softening the transition. It also helps improve the appearance of some of the small dips which were barely within the shadow region, but previously appeared completed shadowed.

Soft Shadows with Fragment Programs