Loading and Rendering a Mesh


1.

Determine the media path.

2.

Declare the mesh variables.

3.

Load the mesh and textures from files.

4.

Render the mesh.

Step 1 is determining the media path. In the included CD, you will notice a Blockers folder in the media folder. This folder includes all the game media, so you need to copy it onto your hard drive somewhere (or use the installation application from the CD). After you copy the media to your hard drive, you need to add an application configuration file to your project, much as you did in previous chapters. Choose Project, Add New Item, and add an application configuration file to your project. Replace the Extensible Markup Language (XML) that was automatically generated with the following:

 <?xml version="1.0" encoding="utf-8" ?> <configuration>   <appSettings>     <add key="MediaPath" value="..\..\..\..\Media\Blockers\" />   </appSettings> </configuration> 

Obviously, you want the MediaPath value to match wherever you have copied the media on your hard drive. If you used the installation program, the value shown here will work for you. With the configuration file in your project, you need a variable to actually access this key, so add this variable to your game engine class:

 public static readonly string MediaPath =  ConfigurationSettings.AppSettings.Get("MediaPath"); 

For Step 2, you declare the mesh variables. One of the media files in the folder is an X file called level.x. The X files are used to store geometry data, which can then be easily rendered with DirectX. This particular X file is simply your sky box, with a series of textures, marking each wall of the "level." In Direct3D, the Mesh class will be used to hold the actual geometry data, and the Texture class will be used to hold each texture. A single mesh can have 0 to many textures, so you want to declare the following variables in your game engine class:

 // The information for the mesh that will display the level private Mesh levelMesh = null; private Texture[] levelTextures = null; 

As you can see, you have a single Mesh object that will be used to store the geometry and an array of textures to store the texture for the walls. Before continuing, however, you might find yourself wondering, what exactly is a mesh? When rendering 3D graphics, everything that is rendered onscreen consists of one to many triangles. A triangle is the smallest closed polygon that will always be coplanar. (Rendering primitives that are not coplanar isn't very efficient.) You can build virtually any object by using a large number of triangles. A mesh is simply a data store for this triangle (or geometry) data.

Step 3 is loading the mesh and textures from files. You are now ready to load your mesh data into the variables you just created. Take the code in Listing 4.7, and include it in the OnCreateDevice method you've already written.

Listing 4.7. Loading the Sky Box Mesh
 // Create the mesh for the level ExtendedMaterial[] mtrls; levelMesh = Mesh.FromFile(MediaPath + "level.x", MeshFlags.Managed, device,                           out mtrls); // Store the materials for later use, and create the textures if ((mtrls != null) && (mtrls.Length > 0)) {     levelTextures = new Texture[mtrls.Length];     for (int i = 0; i < mtrls.Length; i++)     {         // Create the texture         levelTextures[i] = TextureLoader.FromFile(device, MediaPath +             mtrls[i].TextureFilename);     } } 

For the mesh you are creating, you want to load this from a file, using the media path variable that was declared earlier in this chapter. The second parameter of this call is any flag you might want to pass in. Because this mesh is simply static, you can use the MeshFlags.Managed flag, which informs Direct3D that it should manage the mesh. You also need the created device when creating this mesh, so that is what you pass in as the third parameter. The final parameter is extended material information about the mesh. Because a mesh can have more than one set of material information, it is returned as an array.

After the mesh is created, ensure that the extended material array has members. If it does, you can create the texture array, scroll through each of the members of the extended material array, and load the appropriate texture from a file. Notice that the texture loading method has only two parameters: the rendering device and the location of the file. The texture filename normally doesn't include path information, so to ensure that it loads the texture from the correct location, it's a good idea to include the media path here as well.

Step 4 is rendering the mesh. The actual rendering of this mesh is pretty simple. Take the code in Listing 4.8, and include it in your render method. Place the code between the calls to BeginScene and EndScene to ensure that it is rendered correctly.

Listing 4.8. Rendering the Sky Box Mesh
 // First render the level mesh, but before that is done, you will need // to turn off the zbuffer. This isn't needed for this drawing device.RenderState.ZBufferEnable = false; device.RenderState.ZBufferWriteEnable = false; device.Transform.World = Matrix.Scaling(15,15,15); device.RenderState.Lighting = false; for(int i = 0; i < levelTextures.Length; i++) {     device.SetTexture(0, levelTextures[i]);     levelMesh.DrawSubset(i); } // Turn the zbuffer back on device.RenderState.ZBufferEnable = true; device.RenderState.ZBufferWriteEnable = true; // Now, turn back on our light device.RenderState.Lighting = true; 

There's actually quite a bit of new stuff in here. First, if you remember the discussion on depth buffers earlier in this chapter, you learned that the depth buffer stores the depth of each of the objects in a scene. Because the sky box is a single object that will always be behind any other objects in the scene, you can simply turn off the depth buffer and render it first. In many cases, simply turning the depth buffer off (setting the ZBufferEnable render state to false) is adequate; however, in some cases, drivers still write to the depth buffer even if it is off. To handle this case, you can simply turn off writing to the depth buffer as well.

Next, you want to actually size the sky box. The mesh that has been loaded has all the triangle information stored in what is called object space. The mesh itself has no knowledge of any other objects that might or might not be in a scene. To enable you to render your objects anywhere in your scene, Direct3D provides a transform, which allows you to move from one coordinate system to another. In this case, you want to scale the sky box 15 units for each of the axes. (I discuss transforms more in depth in later chapters.)

Because the sky box is textured, you don't want any lighting calculations that the scene might need to affect the box. To ensure that no lighting calculations are used when rendering the sky box, you simply set the Lighting render state to false. Next, you are ready to draw your mesh.

You'll notice here that you want to go through each texture in your array. First, call the SetTexture method to let Direct3D know which texture you expect to be using for rendering this portion of the mesh. Then, you call DrawSubset on the mesh itself, passing in the index to the texture inside the array you are currently rendering.



Beginning 3D Game Programming
Beginning 3D Game Programming
ISBN: 0672326612
EAN: 2147483647
Year: 2003
Pages: 191
Authors: Tom Miller

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