Direct3D, Part 3: Using Meshes to Save and Load Complex Scenes
Direct3D's Mesh class lets you manage, save, and load complex scenes quickly and easily.
by Rod Stephens
Mar 5, 2008
Page 1 of 4
n Part 1 of this series, you saw how to get started with Direct3D, Microsoft's high-performance three-dimensional graphics library. Part 2 explained how to make scenes more realistic by adding lighting and textures to objects. The result of applying those two techniques is often a complex scene containing many objects displayed with different colors, textures, and material characteristics, such as reflectivity.
Because building such complex scenes takes time, it might be nice to be able to save the results so you can load them again later. While it would be simple to save the result as a bitmap file, it would be better if you could save the scene's geometry and texture information so you could load the scene and manipulate it in three dimensions later.
Direct3D's Mesh class lets you do just that. A Mesh object saves information about the vertices, faces, normals, and texture data that you need to draw a complex scene. It groups the faces into subsets that you can draw individually; each subset can have its own materials and textures. Finally, the Mesh class provides methods to save and load scenes to and from .x (pronounced "dot X") files.
This article explains how to use code to build a Mesh object that represents a scene. It also explains how to load and save Mesh objects in .x files.
Introduction to Meshes
A Mesh object contains three buffers that hold key information about the scene that the Mesh represents:
The vertex buffer holds information about the scene's points. This includes the points' X, Y, and Z coordinates. Depending on how you want to display the scene, it may also include normal and texture coordinate data for each point. In other words, the vertex buffer can accept more than one format. In this article, I'm going to skip to a fairly advanced vertex format and store position, normal, and texture information for each vertex so the program can use lighting and textures discussed in Part 2.
The index buffer contains information about the points that make up the scene's faces. Normally a scene's faces are triangles, so the index buffer typically contains a list of the vertex indices that make up each triangle. For example, if the first triangle includes the vertices with indexes 10, 39, and 7 in the vertex buffer, then the first three entries in the index buffer are 10, 39, and 7.
The attribute buffer contains an integer value for each scene face that indicates that face's mesh subset. For example, suppose you build a scene that contains a brick courtyard, which, in turn contains a pool of water. In this case, the triangles composing the courtyard would make up one subset, and the triangles composing the pool would make up a second subset. When a program needs to draw the scene, it can call the Mesh object's DrawSubset method twice, once to draw each subset. Before it calls DrawSubset, the program selects the appropriate material and texture for each subset.
To fill these buffers, the Mesh class provides two methods, SetVertexBufferData and SetIndexBufferData, that define the scene's vertex and index data. For simple scenes such as a cube, it's easy enough to build the arrays that these methods use to define the vertex and index data manually; however, you'll find it's far simpler to build complex scenes in pieces—it's not easy to just sit down and write out these arrays. Instead you should use code to build them as much as possible. Rather than building the arrays directly, you save data into two generic List objects and, when you're finished building the scene, you can copy those values into arrays.
Setting the attribute buffer is just a little trickier. The Mesh class has a SetAttributeTable method but I had trouble getting it to work. To avoid using SetAttributeTable, the sample code that accompanies this article calls the Mesh object's LockAttributeBuffer method to get an array of attribute values for the scene's faces. It sets the appropriate subset values and calls UnlockAttributeBuffer to apply the changes to the Mesh.