Rendering a Track and Multiple Go-Karts


Before you can do any of those things, first you need something interesting to be rendered. You currently have a single go-kart being rendered, which is all well and good, but it doesn't give you much opportunity to see anything if you render a scene into your texture. To change this situation, first you should set up your code to create and render multiple go-karts.

Find the declaration to your go-kart variables for the mesh and textures and replace them with these:

 // Kart mesh private const int NumberKarts = 5; private Mesh[] kartMeshes = null; private Texture[][] kartTextures = null; // Track mesh private Mesh trackMesh = null; private Texture[] trackTextures = null; 

Along with creating an array of meshes for the kart and textures, you also add a constant to describe the number of karts that will be rendered, plus a mesh and array of textures for the track. Because you changed the names and types of the parameters that you had previously declared, nothing will compile now. First, you can fix the creation of the meshes, so find the OnNewGame method in your class, and replace it with the one found in Listing 22.1.

Listing 22.1. Creating Meshes
 private void OnNewGame(object sender, EventArgs e) {     ExtendedMaterial[] materials = null;     GraphicsStream adj = null;     // Load an array of karts     kartMeshes = new Mesh[NumberKarts];     kartTextures = new Texture[NumberKarts][];     for (int meshes = 0; meshes < NumberKarts; meshes++)     {         // Create the kart mesh and textures         using (Mesh tempMesh = Mesh.FromFile(MediaPath + "kart.x",                     MeshFlags.Managed, sampleFramework.Device,                     out adj, out materials))         {             if ( (materials != null) && (materials.Length > 0) )             {                 // Create the textures                 kartTextures[meshes] = new Texture[materials.Length];                 for(int i = 0; i < materials.Length; i++)                 {                     kartTextures[meshes][i] =                         ResourceCache.GetGlobalInstance().CreateTextureFromFile(                         sampleFramework.Device,  MediaPath +                         gameUI.GetComboBox(                         PickKartControl).GetSelectedData() as string);                 }             }             string errors = null;             kartMeshes[meshes] = Mesh.Clean(CleanType.Optimization,                 tempMesh, adj, adj, out errors);             if ( (errors != null) && (errors.Length > 0) )                 throw new InvalidOperationException("Error cleaning mesh: "                                                     + errors);             // Now optimize the mesh in place             kartMeshes[meshes].OptimizeInPlace(                                MeshFlags.OptimizeVertexCache, adj);         }     }     // Now load the track mesh and textures     using (Mesh tempMesh = Mesh.FromFile(MediaPath +                 gameUI.GetComboBox(PickLevelControl).GetSelectedData() as string,                 MeshFlags.Managed, sampleFramework.Device,                 out adj, out materials))     {         if ( (materials != null) && (materials.Length > 0) )         {             // Create the textures             trackTextures = new Texture[materials.Length];             for(int i = 0; i < materials.Length; i++)             {                 if ( (materials[i].TextureFilename != null) &&                     (materials[i].TextureFilename.Length > 0) )                 {                     trackTextures[i] =                         ResourceCache.GetGlobalInstance().CreateTextureFromFile(                         sampleFramework.Device,  MediaPath +                         materials[i].TextureFilename);                 }             }         }         string errors = null;         trackMesh = Mesh.Clean(CleanType.Optimization,             tempMesh, adj, adj, out errors);         if ( (errors != null) && (errors.Length > 0) )             throw new InvalidOperationException("Error cleaning mesh: "                                                 + errors);         // Now optimize the mesh in place         trackMesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adj);     }     currentState = GameState.Gameplay; } 

The big changes here are twofold: first, instead of creating a single mesh and set of textures for the go-kart, you're now creating an array of each. Notice that the textures have turned into an array of arrays because each mesh can have zero to many textures. Each mesh is loaded, each of the textures is loaded (based on the input from the user interface), and then each mesh is cleaned for optimization and optimized.

After that, the track mesh is created. It is also loaded from the data in the user interface screen. (track.x was loaded as the data of the pick-the-level combo box.) It too is cleaned and optimized before it is ready to be rendered. I hope you noticed earlier that you never cleaned up the go-kart mesh and textures. In all reality, cleaning up the textures isn't required because the ResourceCache class handles that, but cleaning up the meshes is. Find the OnDestroyDevice method and add the cleanup code from Listing 22.2 to that method.

Listing 22.2. Cleaning Up Meshes
 if (kartMeshes != null) {     // Clean up kart meshes/textures     for(int i = 0; i < kartMeshes.Length; i++)     {         if (kartMeshes[i] != null)         {             kartMeshes[i].Dispose();             kartMeshes[i] = null;         }     }     // Clean up track mesh/textures     if (trackMesh != null)     {         trackMesh.Dispose();         trackMesh = null;     } } 

If you want to just see what rendering the go-kart and track would be like (see Figure 22.1), simply find the OnFrameRender method and update the two compile errors left, by adding a [0] to the variables:

 for (int i = 0; i < kartTextures[0].Length; i++) {     effect.SetValue("SceneTexture", kartTextures[0][i]);     effect.CommitChanges();     kartMeshes[0].DrawSubset(i); } 

Figure 22.1. Go-kart and track.


You also need to render the track (this code before the EndPass call):

 // Move the track up some Matrix worldMatrix = Matrix.Translation(0, 4.5f, 0); effect.SetValue("worldViewProjection", worldMatrix *     world * view * proj); // Render the track for (int i = 0; i < trackTextures.Length; i++) {     effect.SetValue("SceneTexture", trackTextures[i]);     effect.CommitChanges();     trackMesh.DrawSubset(i); } 

You've moved (translated) the track up 4.5 units as well.

That code isn't robust because it cannot render more than that one kart, so that's something you should address first. Because you'll be required to render the scene twice anyway (once for the main screen and once for the rear-view screen), you should encapsulate this rendering into a new method. Add the method in Listing 22.3 to your class file now.

Listing 22.3. Rendering Your Scene
 private void RenderScene(Matrix world, Matrix view, Matrix proj) {     // Update the effect's variables. Instead of using strings, it would     // be more efficient to cache a handle to the parameter by calling     // Effect.GetParameter     effect.SetValue("worldViewProjection", world * view * proj);     effect.SetValue("worldMatrix", world);     effect.SetValue("lightDirection", LightDirection);     effect.Technique = "RenderScene";     int passes = effect.Begin(0);     for (int pass = 0; pass < passes; pass++)     {         effect.BeginPass(pass);         // Render the karts         for (int kart = 0; kart < kartMeshes.Length; kart++)         {             Matrix kartMatrix = Matrix.Translation(kart * -5.5f, 0,                                                    kart * -40.0f);             effect.SetValue("worldViewProjection", kartMatrix *                 world * view * proj);                 for (int i = 0; i < kartTextures[kart].Length; i++)                 {                     effect.SetValue("SceneTexture", kartTextures[kart][i]);                     effect.CommitChanges();                     kartMeshes[kart].DrawSubset(i);                 }         }         // Move the track up some         Matrix worldMatrix = Matrix.Translation(0, 4.5f, 0);         effect.SetValue("worldViewProjection", worldMatrix *             world * view * proj);         // Render the track         for (int i = 0; i < trackTextures.Length; i++)         {             effect.SetValue("SceneTexture", trackTextures[i]);             effect.CommitChanges();             trackMesh.DrawSubset(i);         }         effect.EndPass();     }     effect.End(); } 

The method here is similar to the code you had within that if statement in the OnFrameRender method earlier. Now, however, you also have a loop to render each of the meshes for the various go-karts. Notice that each kart is offset some by updating the matrix passed in to your vertex shader. Updating your OnFrameRender method to remove the code you had in the else statement and replacing it with the following line of code renders a scene much like you see in Figure 22.2:

 // Now render the scene normally RenderScene(camera.WorldMatrix, camera.ViewMatrix, camera.ProjectionMatrix); 

Figure 22.2. Go-karts and trackspaced out.


Construction Cue

You've created a new mesh for each kart you're rendering. This work isn't required because you could have just re-used the same kart mesh/texture combination over and over again. You did it so you can use different kart mesh/texture combinations in the future, if you want.




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