Marching Cubes is an algorithm for rendering isosurfaces in volumetric data. The basic notion is that we can define a voxel(cube) by the pixel values at the eight corners of the cube. If one or more pixels of a cube have values less than the user-specified isovalue, and one or more have values greater than this value, we know the voxel must contribute some component of the isosurface. By determining which edges of the cube are intersected by the isosurface, we can create triangular patches which divide the cube between regions within the isosurface and regions outside. By connecting the patches from all cubes on the isosurface boundary, we get a surface representation.
There are two major components of this algorithm. The first is deciding how to define the section or sections of surface which chop up an individual cube. If we classify each corner as either being below or above the isovalue, there are 256 possible configurations of corner classifications. Two of these are trivial; where all points are inside or outside the cube does not contribute to the isosurface. For all other configurations we need to determine where, along each cube edge, the isosurface crosses, and use these edge intersection points to create one or more triangular patches for the isosurface.
If you account for symmetries, there are really only 14 unique configurations in the remaining 254 possibilities. When there is only one corner less than the isovalue, this forms a single triangle which intersects the edges which meet at this corner, with the patch normal facing away from the corner. Obviously there are 8 related configurations of this sort (e.g. for configuration 2 - you may need to tweak the colormap to see the plane between the spheres/pixels). By reversing the normal we get 8 configurations which have 7 corners less than the isovalue. We don't consider these really unique, however. For configurations with 2 corners less than the isovalue, there are 3 unique configurations (e.g. for configuration 12), depending on whether the corners belong to the same edge, belong the same face of the cube, or are diagonally positioned relative to each other. For configurations with 3 corners less than the isovalue there are again 3 unique configurations (e.g. for configuration 14), depending on whether there are 0, 1, or 2 shared edges (2 shared edges gives you an 'L' shape). There are 7 unique configurations when you have 4 corners less than the isovalue, depending on whether there are 0, 2, 3 (3 variants on this one), or 4 shared edges (e.g. for configuration 30 - again you may need to tweak the colors to see the triangle for the isolated (far) inside sphere/pixel).
Each of the non-trivial configurations results in between 1 and 4 triangles being added to the isosurface. The actual vertices themselves can be computed by interpolation along edges, or, as I did, default their location to the middle of the edge. The interpolated locations will obviously give you better shading calculations and smoother surfaces.
Now that we can create surface patches for a single voxel, we can apply this process to the entire volume. We can process the volume in slabs, where each slab is comprised of 2 slices of pixels. We can either treat each cube independently, or we can propagate edge intersections between cubes which share the edges. This sharing can also be done between adjacent slabs, which increases storage and complexity a bit, but saves in computation time. The sharing of edge/vertex information also results in a more compact model, and one that is more amenable to interpolated shading.
Students in CS563 can find my implementation of this algorithm in /cs/courses/cs563/software/march_cubes [NOTE TO OTHERS: THIS CODE IS NOT AVAILABLE FOR GENERAL DISTRIBUTION - I WILL IGNORE ALL REQUESTS FOR COPIES OF THE CODE]. It is loosely based on the description presented in the text by Watt and Watt (see below). The file cube.new contains 1 row of information for each of 256 configurations. The first number gives the configuration ID, which is simply an 8-bit number based on which of 8 corners are inside the isosurface. The numbers after that are triplets, identifying the edges which contain the vertices for each triangle patch to be used for that configuration (terminated by a -1). The file hydrogen.dat is a sample volume file which is distributed with AVS. The first three bytes give the dimensions, and the rest is just row-major, 1 byte per data point.
The program mcube.c accepts a data file and an isovalue, reads the configuration table, and "marches" through the volume, classifying cubes and outputting triangles as it goes (each row of output is the number 3, followed by 3 sets of 3-D floating point coordinates). No attempt is made to share vertices or edges between triangles, which leads to pretty large output files. The program tri_inventor.c takes this output and creates a scene graph that can be imported into IRIS Inventor or Open Inventor. This can make a REALLY large file, based on your data set and isovalue (press here for some sample output).
[size="5"]Problems and Alternatives
One obvious problem with marching cubes is the amount of memory needed to store the resulting surface. As each boundary cube can generate up to 4 sub-pixel facets, the result is quite large. We can reduce this somewhat by sharing vertices and edges, or even merging coplanar patches into larger facets. Another solution might be to try and fit parametric surfaces to groups of boundary points, though this may be difficult for complex surface geometries.
Another problem arises when you don't have a filled space of voxels. Depending on how the volume data was acquired there may be voids which need to be assigned values or circumnavigated in the surface generation algorithm. Any interpolated value used may reduce the validity of the resulting surface.
A final alternate strategy would be to ray trace the original volume data, which may be the topic of a future presentation.
Lorensen, W.E. and Cline, H.E., "Marching Cubes: a high resolution 3D surface reconstruction algorithm," Computer Graphics, Vol. 21, No. 4, pp 163-169 (Proc. of SIGGRAPH), 1987. Watt, Alan, and Watt, Mark, Advanced Animation and Rendering Techniques, Addison-Wesley, 1992.