Controlling the Level of Detail with Progressive Meshes

There are cases where you'd only want to simplify a mesh (for example, imagine a model for a rocket you've fired). However, if you are only simplifying, it means the object's detail never needs to be increased, which isn't as common as the cases where you may need to progressively lower or raise the level of detail. I'm sure you can see where the name of the progressive mesh came from.

To show the behavior of the progressive meshes, we will write a similar application to the one we wrote for the simplification mesh a moment ago. However, instead of just simplifying, we will also allow you to raise the level of detail by bringing the model closer to the camera as well. Once again we will start with the example to load a mesh from a file.

The ProgressiveMesh class derives from the BaseMesh class just like the Mesh class does. You can use the progressive mesh class to draw your objects, unlike the SimplificationMesh object. Knowing this, we can replace the declaration for your mesh object with this one:

 private ProgressiveMesh progressiveMesh = null; 

You will also need to replace each instance of the old mesh variable with the new progressiveMesh variable. With the new variable name and type, we obviously need to update the LoadMesh method, since our code won't even compile right now. We will use a similar method; we will just generate our progressive mesh at the end. Use the code shown in Listing 9.3.

Listing 9.3 Loading a Progressive Mesh
 private void LoadMesh(string file) {     ExtendedMaterial[] mtrl;     GraphicsStream adj;     // Load our mesh     using(Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device,                 out adj, out mtrl))     {         // If we have any materials, store them         if ((mtrl != null) && (mtrl.Length > 0))         {             meshMaterials = new Material[mtrl.Length];             meshTextures = new Texture[mtrl.Length];             // Store each material and texture             for (int i = 0; i < mtrl.Length; i++)             {                 meshMaterials[i] = mtrl[i].Material3D;                 if ((mtrl[i].TextureFilename != null) &&                     (mtrl[i].TextureFilename != string.Empty))                 {                     // We have a texture, try to load it                     meshTextures[i] = TextureLoader.FromFile(device,                         @"..\..\" + mtrl[i].TextureFilename);                 }             }         }         // Clean our main mesh         using(Mesh tempMesh = Mesh.Clean(mesh, adj, adj))         {             // Create our progressive mesh             progressiveMesh = new ProgressiveMesh(tempMesh, adj,                 null, 1, MeshFlags.SimplifyVertex);             // Set the initial mesh to the max             progressiveMesh.NumberFaces = progressiveMesh.MaxFaces;             progressiveMesh.NumberVertices = progressiveMesh.MaxVertices;         }     } } 

Notice that we use two temporary mesh objects to generate our progressive mesh. We use the cleaned mesh to do the actual generation of our progressive mesh. The fourth parameter is the important one for the progressive mesh constructor: It is the minimum number of vertices or faces we want in the generated mesh, depending on the MeshFlags option you pass in (either SimplifyFace or SimplifyVertex). Naturally, this is just an approximation, and even if it's not possible to simplify the mesh to that degree, this method should still succeed.

You'll also notice that immediately we set the number of vertices and facesto the maximum values. Generating the mesh leaves it simplified. Setting the number of faces and/or vertices on a progressive mesh will update the current level of detail used to render the mesh. Since we want to initially start out at full detail, we naturally update the number of faces and vertices to their maximums.

To get the application to compile, you'll need to change the DrawSubset call in your DrawMesh method as follows:

 progressiveMesh.DrawSubset(i); 

Running the application now, you should notice that it behaves exactly as the original sample did. Our model spins around and is fully detailed. Now, we need to handle our keypresses and camera movement. We will use code similar to what we used in our simplification mesh example. You will need the declarations for the camera position variable and the move amount constant:

 private float cameraPos = 580.0f; private const int MoveAmount = 100; 

You'll once again need to modify your view transform to allow the camera position to be updated. Replace the view transform line with the following:

 device.Transform.View = Matrix.LookAtLH(new Vector3(0,0, cameraPos),     new Vector3(), new Vector3(0,1,0)); 

Finally, you'll need to handle the keystrokes and react accordingly. Use the override in Listing 9.4:

Listing 9.4 KeyPress Event Handler
 protected override void OnKeyPress(KeyPressEventArgs e) {     if (e.KeyChar == '+')     {         cameraPos += (MoveAmount * 2);         progressiveMesh.NumberVertices =             ((BaseMesh)progressiveMesh).NumberVertices - MoveAmount;         progressiveMesh.NumberFaces =             ((BaseMesh)progressiveMesh).NumberFaces - MoveAmount;     }     if (e.KeyChar == '-')     {         cameraPos -= (MoveAmount * 2);         progressiveMesh.NumberVertices =             ((BaseMesh)progressiveMesh).NumberVertices + MoveAmount;         progressiveMesh.NumberFaces =             ((BaseMesh)progressiveMesh).NumberFaces + MoveAmount;     }     if (e.KeyChar == 'w')         device.RenderState.FillMode = FillMode.WireFrame;     if (e.KeyChar == 's')         device.RenderState.FillMode = FillMode.Solid; } 

Once again, we allow you to switch between wire-frame mode and solid mode by pressing the "w" or "s" key. We also keep the "+" key as our "decrease level of detail" key. When the "+" key is pressed, we move our camera farther away, and update the number of vertices and faces. You'll notice that when we are attempting to actually get the number of faces or vertices, we must first cast our progressive mesh to a BaseMesh object. Since the set property exists on the progressive mesh object, while the get property exists on the base object, this cast is necessary.

We also added the capability to increase our level of detail now as well. Naturally, we used the " " key for this operation. It essentially does the exact opposite of what the "+" keys does. It moves the camera closer, and increases the number of vertices and faces in the mesh.

STORING MULTIPLE LEVELS OF DETAIL

It's common to store multiple meshes of varying levels of detail rather than having one large progressive mesh controlling the entire range of details. If you look at the Progressive Mesh sample that ships with the DirectX SDK, you will see an example of this implementation. You can use the TrimByFaces and TrimByVertices methods on the progressive mesh object to change the level of details that any particular progressive mesh supports.

It would also be nice to add some rendered text to the application to show the number of vertices and meshes currently being rendered. Rather than repeat the code here, you can look earlier in this chapter for the declaration and initialization of a font variable. Once those are in your application, you can use the following in your rendering method:

 font.DrawText(null, string.Format("Number vertices in mesh: {0}",     ((BaseMesh)progressiveMesh).NumberVertices), new Rectangle(10, 10, 0, 0),     DrawTextFormat.NoClip, Color.BlanchedAlmond); font.DrawText(null, string.Format("Number faces in mesh: {0}",     ((BaseMesh)progressiveMesh).NumberFaces), new Rectangle(10, 30, 0, 0),     DrawTextFormat.NoClip, Color.BlanchedAlmond); 


Managed DirectX 9 Graphics and Game Programming, Kick Start
Managed DirectX 9 Kick Start: Graphics and Game Programming
ISBN: B003D7JUW6
EAN: N/A
Year: 2002
Pages: 180
Authors: Tom Miller

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