kurt miller's homepage
( My development journal and homepage has moved to a new system here: kurtm.flipcode.com )

Voxel Mesh Creation and Rendering 27 October 2002, 11:30AM

I spent a little time recently working with voxels. My goal was to write a simple converter that takes as input a textured triangle mesh, and outputs a colored voxel representation. When I refer to a voxel, I'm refering to the "volume pixel" definition which exists in 3-space. When I use the term "voxel mesh", I'm refering to a set of colored voxels.

The approach I used to generate the voxel mesh is pretty simple. In a nutshell, it works like this:
  • Generate a grid of cubes over the source mesh.
  • Throw out any empty cubes.
  • Color each of the remaining cubes based on the source mesh's texture.
  • The following screenshot shows an example of the results:


    Each voxel mesh in the screenshot was generated with a different resolution for the cube grid. I'm using Direct3D for rendering. No textures are used, just a set of colored blocks (rendered as triangles.) Below I'll explain the mesh conversion process in a bit more detail.

    Generating the grid of cubes is straight-forward. The source mesh is scaled to a fixed cube size. Given a resolution parameter N, a grid of NxNxN cubes is fit over the mesh. Triangles from the mesh are then checked against cubes for overlap, and any empty cubes are thrown out. In my work, the converter did most of this by brute-force, but you could speed it up and lighten the memory load considerably using a hierarchical octree-like structure, or any of many other optimizations. I wasn't really worried about conversion efficiency, my aim was just to get decent results. The following image shows the resulting non-empty cubes rendered over a textured source mesh:


    The next step is to color each of the cubes so that the texture map is no longer needed. The approach I used works by taking the center point of each cube, and finding the closest point to it on the triangle that intersects the cube. If more than one triangle is intersecting the cube, the closest out of all of those closest point calculations for each triangle is used. This results in a point on a triangle that intersects the cube. The color of the cube is determined by looking up the color of the texture pixel at that point on the triangle.

    To look up the color given a texture, a triangle (points T1, T2, T3, each with TU/TV coordinates), and a point (PT) on the triangle, barycentric coordinates can be used.

    One way to think of barycentric coordinates is to first consider the triangle areas formed by connecting each of the vertices to the point PT. In the following image, consider the triangles [T2, T3, PT], [T3, T1, PT], and [T1, T2, PT]. Barycentric coordinates bu : bv : bw can be thought of as the ratio of the areas of those three triangles.


    Which means the following simple calculations will get us the weights we want:

    a = area(Source Triangle)

    bu = area([T2, T3, PT]) / a
    bv = area([T3, T1, PT]) / a
    bw = area([T1, T2, PT]) / a

    The sum of the smaller triangle areas will of course result in the area of the source triangle, which means (bu + bv + bw) will equal 1.

    Given the above weights, the texture TU and TV coordinates for the point can be calculated like this:

    TU = (bu * T1.TU) + (bv * T2.TU) + (bw * T3.TU)
    TV = (bv * T1.TV) + (bv * T2.TV) + (bw * T3.TV)

    Now you can simply look up the pixel color in the texture image at 2D coordinate (TU * TEXTURE_WIDTH, TV * TEXTURE_HEIGHT), and set the color of the cube to that color. For a more complete description of barycentric coordinates, check out the links in the reference section at the end of this entry.

    Here's a screenshot showing the newly colored cubes, rendered as wireframe then as solid colored cubes:


    So that's the conversion process. I haven't read much of anything on voxel techniques, so there might be much better ways of doing this, but I'm pretty happy with the results I've come up with so far. As for rendering, there are a lot of ways to do it. In the screenshots above, I've rendered an actual colored cube (made up of untextured triangles) for each voxel, which adds up to a lot of triangles pretty quickly. You could however, just as easily use any other primitives for the visualization, such as billboards. Some pretty stylish special effects could be done by rendering different kinds of billboards at the voxel locations.

    Given that the screenshots above look like old-school dos graphics, and are actually rendering a lot more triangles than the original mesh version, what's the point? Who knows, I just felt like experimenting. There's a lot of fun stuff you can do with voxels since it takes away some of the "limitations" of working with polygons. Its also fun not having to load any textures. Some effects related to lighting, (de)construction, animation, etc, turn out to be pretty simple when working with "pixels" in 3D rather than triangles.

    On a somewhat related note, I've been thinking about trying something similar to this, but still using triangles. The triangles of the mesh would just keep subdividing until each one is under some area A, so at a high enough resolution, the colors of the triangles would capture the texture detail.

    Below are a bunch of other screenshots from the viewer showing some different meshes at different resolutions. Most of the objects used in the screenshots were modeled by Max Shelekhov for use in my game Strayfire.




    You can download a little test version of the Voxel Mesh Viewer here (2.3MB). The demo includes a few voxel meshes at different resolutions. It requires DirectX 8 and a decent 3D accelerator. The left mouse button allows you to rotate the model, and the 'A' and 'Z' keys zoom in and out. The title bar displays the statistics for each mesh, including the voxel count, the number of vertices, and the number of triangles being rendered.

    References and suggested reading:
  • Fast 3D Triangle-Box Overlap Testing
  • World of Mathematics - Barycentric Coordinates
  • Computation of Interpolation Weights
  • Usenet Discussion of Barycentric Coordinates
  • Area of a Triangle via the Cross Product




  • Complete List Of Journal Updates:
  • Auto-Terrain Texturing (15 November 2004, 12:27PM)
  • On Orientation Interfaces (14 November 2004, 7:30PM)
  • Basic Terrain Generation (10 November 2004, 4:39AM)
  • Engine Tool Interface (07 November 2004, 2:37AM)
  • Render Buffer Ranges (02 November 2004, 5:15AM)
  • wxWidgets GUI Toolkit (29 October 2004, 2:31AM)
  • Generic Rendering Interfaces (27 October 2004, 6:55PM)
  • Source Documentation with Doxygen (25 October 2004, 6:34PM)
  • Signs of Life? (25 October 2004, 5:14PM)
  • Key Value Scripts (08 November 2003, 4:32PM)
  • Octrees for Potential Colliders (01 November 2003, 4:09PM)
  • Flexporter and Game Levels (31 October 2003, 12:14PM)
  • New Project and More Updates (31 October 2003, 6:14AM)
  • HSL Color Space (07 May 2003, 6:14AM)
  • A Couple Graphics Books (02 December 2002, 5:12PM)
  • Texture Detail Using Colored Triangles (02 November 2002, 3:26AM)
  • Voxel Mesh Creation and Rendering (27 October 2002, 11:30AM)
  • Development Journal (25 October 2002, 10:57AM)



  • Site Contents Copyright (c) 2002-2004 Kurt Miller. Please do not reprint this jibberish anywhere.