Texture Mapping

  CU_MDX_TextureMapping.zip (81.3 KiB, 2,977 hits)


  CUnitFramework.zip (101.1 KiB, 20,514 hits)

Extract the C-Unit Framework
inside the project (not solution) directory.

Texture mapping is how the objects, characters, etc in games and movies look more realistic. In case you hadn’t noticed, all the tutorials preceding this one rendered geometry that was simply colored. With texture mapping, instead of creating a simple cube with pretty colors, I can slap some pictures of a crate on each side and voila, I have a crate to put in my game. And we all know a game isn’t complete without a crate.

Texture coordinatesTextures are created from images loaded into the application. The Internet has tons of textures that are free to download or you can make your own in a paint program or go out and take a picture of something. Each image has its own coordinates called texture coordinates. Texture coordinates tell the video drivers what part of the image to render onto the polygon. Texture coordinates are in the range [0,1]. The point (0,0) is the top left corner of the image and the coordinates increase left to right and top to bottom.

Usually, vertex data is created by a modeling program such as Maya, 3DS Max, or Milkshape 3D so you don’t need to code in all the coordinates. You just read in the file and store the data directly into the vertex buffer. However, since we haven’t yet learned how to load in this data, we’ll just do it the old fashion way: by hand.

 

///
/// This event will be fired immediately after the Direct3D device has been
/// created, which will happen during application initialization. This is the best
/// location to create_ Pool.Managed resources since these resources need to be
/// reloaded whenever the device is destroyed. Resources created  
/// here should be released in the OnDetroyDevice callback.
///

/// The Direct3D device
public override void OnCreateDevice( Device device )
{
// Well this isn’t going to be fun…
PositionColoredTextured[] verts = {
new PositionColoredTextured( –1.0f,  1.0f, –1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured(  1.0f,  1.0f, –1.0f, Color.White, 1.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f, –1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured( –1.0f,  1.0f, –1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f, –1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured( –1.0f, –1.0f, –1.0f, Color.White, 0.0f, 1.0f ),

new PositionColoredTextured(  1.0f,  1.0f, –1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured(  1.0f,  1.0f,  1.0f, Color.White, 1.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f,  1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured(  1.0f,  1.0f, –1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f,  1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured(  1.0f, –1.0f, –1.0f, Color.White, 0.0f, 1.0f ),

new PositionColoredTextured(  1.0f,  1.0f,  1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured( –1.0f,  1.0f,  1.0f, Color.White, 1.0f, 0.0f ),
new PositionColoredTextured( –1.0f, –1.0f,  1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured(  1.0f,  1.0f,  1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured( –1.0f, –1.0f,  1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured(  1.0f, –1.0f,  1.0f, Color.White, 0.0f, 1.0f ),

new PositionColoredTextured( –1.0f,  1.0f,  1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured( –1.0f,  1.0f, –1.0f, Color.White, 1.0f, 0.0f ),
new PositionColoredTextured( –1.0f, –1.0f, –1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured( –1.0f,  1.0f,  1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured( –1.0f, –1.0f, –1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured( –1.0f, –1.0f,  1.0f, Color.White, 0.0f, 1.0f ),

new PositionColoredTextured( –1.0f,  1.0f,  1.0f, Color.Blue,  0.0f, 0.0f ),
new PositionColoredTextured(  1.0f,  1.0f,  1.0f, Color.Green, 1.0f, 0.0f ),
new PositionColoredTextured(  1.0f,  1.0f, –1.0f, Color.Red,   1.0f, 1.0f ),
new PositionColoredTextured( –1.0f,  1.0f,  1.0f, Color.Blue,  0.0f, 0.0f ),
new PositionColoredTextured(  1.0f,  1.0f, –1.0f, Color.Red,   1.0f, 1.0f ),
new PositionColoredTextured( –1.0f,  1.0f, –1.0f, Color.Yellow,0.0f, 1.0f ),

new PositionColoredTextured( –1.0f, –1.0f, –1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f, –1.0f, Color.White, 1.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f,  1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured( –1.0f, –1.0f, –1.0f, Color.White, 0.0f, 0.0f ),
new PositionColoredTextured(  1.0f, –1.0f,  1.0f, Color.White, 1.0f, 1.0f ),
new PositionColoredTextured( –1.0f, –1.0f,  1.0f, Color.White, 0.0f, 1.0f )
};

// Define vertex buffer
m_vb = new VertexBuffer( device, verts.Length * PositionColoredTextured.StrideSize, Usage.WriteOnly, PositionColoredTextured.Format, Pool.Managed, null );
GraphicsBuffer buffer = m_vb.Lock( 0, 0, LockFlags.None );
buffer.Write( verts );
m_vb.Unlock();
buffer.Dispose();

// Load the texture
m_tex = new Texture( device, Utility.GetMediaFile( “panel.jpg” ) );
}

First we define our vertices. As you can see, it’s a bit tedious not to use a modeling program. Since we’re going to be using textures, we create_ an array of PositionColoredTextured vertices. With this type of vertex, we need to specify a position, a color, and a set of texture coordinates. When a vertex has both a color and a set of texture coordinates, the color modulates the texture. When the color is white, the texture will be shown in full color. For any other color, the specified color will be overlaid on top of the texture. For the top of the crate, I specified a few different colors so you can see the effect it has on the texture.

After creating the VertexBuffer and setting its data, I create_ a Texture object. You’ll notice that I get my file with Utility.GetMediaFile. This is a helper function taken from the DirectX SDK. I have extremely shortened it for our purposes, but it will work fine for what we are doing. The GetMediaFile method is useful because applications look for files relative to the executing assembly. In Visual Studio, when you compile and run a program, the executable is placed in “bin/Debug/” or “bin/Release” by default, which would mean you would have to either copy in your media file hierarchy in this folder or copy the executable back to the root of the project directory. The GetMediaFile method searches the folders in the vicinity of the executable to find the file you are looking for. When you add new media files to your project, just place them into the “media” folder and use the Utility.GetMediaFile method to make sure you find them. Check out the source code to view the Utility class.

/// Renders the current frame.
/// The Direct3D device
/// Time elapsed since last frame
public override void OnRenderFrame( Device device, float elapsedTime )
{
device.Clear( ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0 );
device.BeginScene();

// Clip…

// Render buffer
device.VertexFormat = PositionColoredTextured.Format;
device.SetTexture( 0, m_tex );
device.Transform.World = m_transform.Transform;
device.SetStreamSource( 0, m_vb, 0, PositionColoredTextured.StrideSize );
device.DrawPrimitives( PrimitiveType.TriangleList, 0, 12 );

// Clip…

device.EndScene();
device.Present();
}

Before we render we have to tell DirectX which texture to render the current geometry with. This is done with the Device.SetTexture method.

///
/// This callback function will be called immediately after the Direct3D device has
/// been destroyed, which generally happens as a result of application termination.
/// Resources created in the OnCreateDevice callback should be released here, which
/// generally includes all Pool.Managed resources.
///

private void OnDestroyDevice()
{
if ( m_vb != null )
{
m_vb.Dispose();
m_vb = null;
}
if ( m_tex != null )
{
m_tex.Dispose();
m_tex = null;
}
}

Don’t forget to be nice and clean up after yourself.

As you can see it doesn’t take much to use textures in our programs. With simple geometry, it is easy to write out the vertices by hand. However, as we start using more complex geometry, we will have all the vertex data generated for us by a modeling program.