Displacement Maps For Subdivided Surfaces

By John Hartquist

Overview

This is a final project for CSC572 - Computer Graphics, a course taught by Zoe Wood at Cal Poly, San Luis Obispo in Winter 2011. I began this project by extending a surface subdivision lab to be dynamic. The input to my program is a quad-mesh, a list of points and four-sided faces made up from the points. Optionally, the mesh may contain image files which are used as displacement maps to add fine detail to the original geometry.

The main sections of this project are divided into the following sections:

Surface Subdivision

Basic Algorithm

The original lab that this project stemmed from used the Catmull and Clark subdivision algorithm. The steps for the algorithm are as follows:

Original mesh of 4 faces:

New faces:

Adjustment of original points:

With lighting effects added:

Making it Dynamic

This original lab was set up as a grid of points so that only a finite set of subdivisions could occur. I extended this so that a surface could theoretically be subdivided infinitely. To do this, I store a list of points and a list of faces, and at each level of subdivision, I add to my list of points, and create an entirely new set of faces. This new set of faces has enough data associated with it to maintain the heirarchy of the original surface which is important in the later sections where I implement displacement maps.

After 4 levels of subdivision:

More levels, surface begins to look smooth:

Adding Displacement Maps

One way to add fine detail to a smooth mesh is to use a displacement map. This is typically a grayscale image where each pixel will correspond to a specific point in the mesh. Then, before rendering the final image, each point in the mesh is moved a distance proportional to the shade of its corresponding pixel, in the direction of the surface normal.

In my project, I assign one displacement map to every original face in the mesh. Also, each displacement map must be a square with sides that are a power of two in pixel length. Then, I subdivide the mesh until the original face is divided into the same number of subfaces as there are pixels in the displacement map.

A displacement map (256 by 256 pixels) Resulting image with displacement map applied

Displacement maps are useful because they can be edited in a standard image editor. By changing the displacement map, you can easily change appearance of the geometry.

Simulating Geometry with Normals

Once the new mesh is calculated from the dispacement map, we need to calculate the normal for every face in order to render lighting effects. Instead of rendering these new points, we can take this new normal information, and associate them with the mesh before it was displaced. To put it another way, we are rending the smooth faces, but giving OpenGL the normal information from the diplaced mesh.

In the examples below, the images rendered with displacement maps are listed on the left, and the images using only the normal information are rendered on the right:

In general, the images on the right look very accurate when looking at the objects straight on. As soon as you start getting closer to the surface and viewing it at an angle, it looks less realistic. I implemented camera controls into this project so that a user could fly around in the scene and observe how the surfaces look from different viewing angles. The images below illustrate the differences more clearly.

Future Work

This project could be extended in a few different ways. It would be nice to export the resulting meshes and normal information. It would also be interesting to implement a simplification algorithm, and be able to modify individual points in the mesh. Colored displacement maps can also be used to displace points where RGB values map to XYZ offsets.

Conclusion

I learned a lot about the Clark and Catmull subdivision algorithm, as well as displacement maps. It was a challenge to extend the algorithm to be dynamic, and I gained useful C++ and OpenGL experience.

References