Tutorial 6: Using Meshes
Complicated geometry is usually modeled using 3-D modeling software and saved to a file. An example of this is the .x file format. Microsoft Direct3D uses meshes to load the objects from these files. The Meshes tutorial project introduces the topic of meshes and shows how to load, render, and unload a mesh.
A mesh contains the data for a complex model. It is an abstract data container that contains resources such as textures and materials, and attributes such as position data and adjacency data. Although meshes are somewhat complicated, Direct3D contains methods that make using meshes easier.
Path
Source location: (SDK root)\Samples\Managed\Direct3D\Tutorials\Tutorial6
Procedure
Note: For information about initializing Direct3D, handling Microsoft Windows messages, rendering, or shutting down, see Tutorial 1: Creating a Device.
Tutorial 5: Using Texture Maps created texture on the Direct3D object. This tutorial adds to the Tutorial 5 code with procedures for handling a mesh from a file, but it drops the OnCreateDevice application-defined method and related device creation calls that were used to create a vertex buffer. The procedure used here handles vertex buffers implicitly within mesh method calls.
Initializing a Mesh Object
This tutorial project initializes multidimensional material and texture arrays as follows. Note also the using declarations of System.ComponentModel and System.IO namespaces.
[C#]
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;
public class Meshes : Form
{
Device device = null; // Rendering device
Mesh mesh = null; // Mesh object in system memory
Direct3D.Material[] meshMaterials; // Materials for the mesh
Texture[] meshTextures; // Textures for the mesh
PresentParameters presentParams = new PresentParameters();
.
.
.
}
The application-defined OnResetDevice method initializes an ExtendedMaterial object that is used to capture the mesh file data to a Material structure. The method sets the directory path to the mesh file, initializes a device, and turns on the z-buffer and white ambient lighting.
[C#]
public void OnResetDevice(object sender, EventArgs e)
{
ExtendedMaterial[] materials = null;
// Set the directory up to load the right data, because the
// default build location is Bin\debug or Bin\release.
Directory.SetCurrentDirectory(Application.StartupPath + @"\..\..\");
Device dev = (Device)sender;
// Turn on the z-buffer.
dev.RenderState.ZBufferEnable = true;
// Turn on ambient lighting.
dev.RenderState.Ambient = System.Drawing.Color.White;
.
.
.
}
Loading a Mesh Object
As shown in the following code fragment, the OnResetDevice method next loads a mesh that represents a texture-mapped 3-D tiger from the tiger.x file. In this Mesh.FromFile method call, the SystemMemory constant of the MeshFlags enumeration indicates that the mesh is to be loaded into system RAM not typically accessible by the device. After the mesh is loaded, a meshMaterials Material object has its members filled with the Material structures of the materials ExtendedMaterial object that came from the mesh file. The material is also set to the ambient color. Finally, a meshTextures Texture object is loaded with the texture the file with a call to the TextureLoader.FromFile method. Both meshMaterials and meshTextures are initialized to the dimension (Length) of the materials structure from the file.
[C#]
public void OnResetDevice(object sender, EventArgs e)
{
.
.
.
// Load the mesh from the specified file.
mesh = Mesh.FromFile("tiger.x",
MeshFlags.SystemMemory,
device,
out materials);
if (meshTextures == null)
{
// Extract the material properties and texture names.
meshTextures = new Texture[materials.Length];
meshMaterials = new Direct3D.Material[materials.Length];
for( int i=0; i<materials.Length; i++ )
{
meshMaterials[i] = materials[i].Material3D;
// Set the ambient color for the material. Direct3D
// does not do this by default.
meshMaterials[i].Ambient = meshMaterials[i].Diffuse;
// Create the texture.
meshTextures[i] = TextureLoader.FromFile(dev,
materials[i].TextureFilename);
}
}
}
Rendering a Mesh Object
After the mesh has been loaded, the private Render method is called to render the mesh object. It first begins the scene and calls the SetupMatrices application-defined method, as was done in Tutorial 5. To render the mesh, it is divided into subsets, one for each material that was loaded. As shown in the following code fragment, a loop is run to render each material subset. The loop does the following for each material:
- The Material property of the device is set to the meshMaterials Material structure.
- The device texture stage 0 is set to the meshTextures Texture structure.
- The material subset is drawn with the DrawSubset method, which inherits from the BaseMesh class.
[C#]
private void Render()
{
.
.
.
for( int i=0; i<meshMaterials.Length; i++ )
{
// Set the material and texture for this subset.
device.Material = meshMaterials[i];
device.SetTexture(0, meshTextures[i]);
// Draw the mesh subset.
mesh.DrawSubset(i);
}
// End the scene.
device.EndScene();
device.Present();
}