Chapter 5: Complex 3D Objects


In Chapter 4, we looked at creating and rendering simple objects consisting of only a few polygons. While this is enough to create our basic terrain and sky, it is not enough to create an entire game. The game engine must also support complex models made up of hundreds or even thousands of polygons. Microsoft has included a class called Mesh that supports the manipulation of such objects. This chapter introduces the Model class of the game engine that encapsulates the Mesh class for the engine.

Looking at Mesh Basics

Before we dive into using the Mesh class as part of our own Model class, we should explore exactly what the Mesh class is and what it can do. The capabilities of the class that we are concerned with can be broken down into three categories: loading a mesh, gathering information about the mesh, and rendering the mesh.

Loading a Mesh

A mesh, by Microsoft s definition, is made up of several components . The first component is a list of vertices for all of the points that define the mesh. These vertices are held in a vertex buffer that is normally stored in the video card if there is sufficient memory capacity on the card. The second component is an index buffer that is also loaded into video memory if possible. The index buffer describes how the vertices are combined to form the triangles that make up the object. Since the shape of a mesh object usually is complex, each vertex tends to be part of a number of adjacent triangles . The use of an index buffer allows the system to reuse one instance of a vertex as many times as necessary. This greatly reduces the number of vertices that are needed to describe the object. Reducing the number of vertices increases performance, since each vertex needs to be transformed from a local mesh-oriented value into world coordinates through matrix multiplication.

The combination of the vertex buffer and the index buffer provide the definition of the basic shape of the object. In order for the mesh to look like something, we must also define what colors should be used for each rendered pixel in the object. This information is held in the material definition associated with each vertex. The material is actually a combination of color values (ambient, diffuse, emissive , and specular) and texturing information.

Microsoft provides three methods in the Mesh class for loading. Two methods (FromStream and FromX) are built for loading the mesh from memory in the form of a data stream or an XfileData structure. We will concentrate on the third method, which loads from a disk file. The Mesh class s FromFile method has eight overloaded variations. All of the variations of the method have the first three arguments in common. The signatures of the eight variations are shown in Listing 5 “1.

Listing 5.1: Mesh Class FromFile Method Signatures
start example
 public Mesh FromFile (String, MeshFlags, Device, EffectInstance)  public Mesh FromFile (String, MeshFlags, Device, GraphicsStream, EffectInstance)  public Mesh FromFile (String, MeshFlags, Device, ExtendedMaterial,     EffectInstance)  public Mesh FromFile (String, MeshFlags, Device)  public Mesh FromFile (String, MeshFlags, Device, GraphicsStream)  public Mesh FromFile (String, MeshFlags, Device, ExtendedMaterial)  public Mesh FromFile (String, MeshFlags, Device, GraphicsStream,     ExtendedMaterial)  public Mesh FromFile (String, MeshFlags, Device, GraphicsStream,     ExtendedMaterial, EffectInstance) 
end example
 

The string in the first argument is the fully qualified path and filename for the .X mesh data file for the object. Chapter 11 will discuss the creation of these data files. The second argument is a combination of one or more flags that lets us tailor where the components of the mesh are stored and how the mesh might be optimized. There are over 30 values in the enumeration. I highly recommend studying the DirectX SDK documentation for the details. The third argument is the Direct3D device to be used with the operation. The other three possible arguments allow us to get extra information about the mesh after it is loaded. The GraphicsStream object provides accessibility to the vertex information for the mesh. The ExtendedMaterial object provides access to the color and texture information for the mesh. The EffectInstance value exposes an Effect class instance associated with the mesh. This is an advanced feature, and therefore I will not cover it in this book.

The FromFile method loads the vertex and index information for the mesh, but it does not load any textures required by the mesh. What it does load is the name of the files containing the textures. Later in the chapter, we will look at how we go about loading the textures for the mesh as we explore the implementation of the Model class.

Gathering Information About a Mesh

Once a mesh has been loaded, we will likely need to query the instance for information about the mesh. At a minimum, we will need to load any textures required by the mesh. The ExtendedMaterial array available in the FromFile method is the preferred way to obtain this information. This argument is an array of ExtendedMaterial class instances. Each instance of the class contains both a Material definition and a texture filename. Iterating through the array allows us access to all of the texture filenames that we will need.

The other basic type of information we probably need to access is the vertex information. Because this information is likely to reside in video memory, we are required to lock the vertex buffer before we are allowed to manipulate it. The process of locking the buffer provides a reference to the data that is safe from possible manipulation by other threads in our application. There are two different ways in which we may lock either a vertex or an index buffer. We may acquire a reference to the buffer from the Mesh class and then call its Lock method. However, an easier way is to use either the LockVertexBuffer or the LockIndexBuffer methods of the Mesh class to access the information more directly. Either way, we gain access to the buffer information as a GraphicsStream or an array of values. Which we choose is largely determined by what we will be doing with the buffer once it is locked. The implementation of the Model class will demonstrate both approaches.

Once we have a locked vertex buffer, we can establish the extents of the mesh and even modify the mesh by modifying the vertices. We will use the information in the vertex buffer to calculate both a bounding radius around the mesh as well as an object-aligned bounding box (OABB). The radius is useful for determining the placement of the mesh within our Quadtree as well as the first step in determining collisions with other objects in our scene. The OABB is useful for more precise collision detection. If for some reason you need very precise collision detection, you must access both buffers. Precise collision detection requires that we test each edge of one mesh against the other mesh to see if the edge intersects a face. The Mesh class provides the Intersect method to support this process. Precise collision detection is computationally expensive and usually not needed for most games . Most of the time the OABB or a simplified version of the model built specifically for collision detection is used. This book s sample game simply checks for OABB intersection once bounding radius detection has provided an intersection.

Optimizing a Mesh

The mesh as loaded from the data file is ready to be rendered. Unfortunately (depending on the skill of the modeler who created the mesh), it may not be ready to be efficiently rendered. During the modeling process, it is possible for multiple vertices to be created at the same position. The Mesh class includes a method called WeldVertices that checks the mesh for any vertices that are the same within a given tolerance. Each vertex that is not needed and can be removed is a small boost to the performance of our game.

Note

The WeldVertices method operates in a manner similar to some tools that are available to simplify a mesh during the design of the mesh. They are normally referred to as polygon reduction tools .

The order of the mesh faces also impacts the performance of the rendering process. Anything that causes a state change in the rendering pipeline has an impact on performance. By sorting the faces so that all faces that use a given texture are rendered together, we reduce the state change cost of changing textures. The Mesh class has the Optimize and OptimizeInPlace methods that perform this sort for us. The Optimize method creates a new mesh instance that is properly sorted. The OptimizeInPlace method alters the original mesh.

Another way to improve performance is to reduce the number of vertices used by the mesh as the mesh moves farther from the viewpoint. Microsoft provides the progressive mesh for the development of multiple levels of mesh detail. The ProgressiveMesh class is built from an instance of the Mesh class. It includes methods for retrieving the minimum and maximum number of vertices that the mesh can have. We can then use the TrimByVertices method of the class to create a version of the mesh with fewer vertices. By rendering simpler meshes as the object gets farther from the viewpoint, we increase performance by not transforming and rendering detail that can t be seen at a distance.

Rendering a Mesh

The rendering of a mesh is quite straightforward. The mesh internally has separated itself into a collection of subsets . Each subset has a specific material and texture. To render the mesh, we are required to loop through the list of materials for that mesh. For each material, we simply set that material and texture as the current value for the device and have the mesh draw the associated subset.




Introduction to 3D Game Engine Design Using DirectX 9 and C#
Introduction to 3D Game Engine Design Using DirectX 9 and C#
ISBN: 1590590813
EAN: 2147483647
Year: 2005
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net