52880.fb2
In this tutorial we will learn about textures, what they are and how to use them. Textures can be used to add realism to your scenes. From our example from the last tutorial, we will add a different texture to each rotating cube, numbering them from 1 to 5 in different colours. You can download the full source code by clicking the "Download Source" link above.
A texture in 3D graphics is a 2D bitmap that can be applied to a polygon (or a number of polygons) to increase realism. For example, lets say that you want to have a brick wall in your scene. You could create a square object in front of the camera and colour it red. Hmm… that looks more like a red square than a brick wall, what you really want to see are the bricks and maybe a window. You can do this using textures. All you need is an object (your square) and a wall texture. You can create your texture in any art package that will save .bmp files, I use Adobe Photoshop but you can use any software you like, even Microsoft Paint that comes with Windows.
You can create a texture in any size you like. But to improve efficiency you should (where possible) keep your textures small and square and to a power of 2: 16×16, 32×32, 64×64, 128×128, 256×256 etc. 256×256 is the most efficient size, but only use this size of texture if you need to. Remember: the smaller the texture, the better.
What are texture coordinates? Well, texture coordinates are used to specify a point on a texture. Because a texture is 2D we only need two values to specify any point: U and V. U is the number of units across (columns) and V is the number of units down (rows). The values of U and V should be between 0 and 1 (you can specify other values to create special effects, more on this later). The top left corner of the texture is (0, 0) and the bottom right corner is (1, 1) in the form (U, V). Fig 6.1 below shows the texture coordinates of nine points of a texture.
Fig 6.1
Now that we know about texture coordinates, we can apply our texture to an object in our scene, this is called Texture Mapping. The process of texture mapping is to map texture coordinates to vertices in a scene, therefore each vertex will have two extra values, U and V. Fig 6.2 below, shows an example of mapping a texture on to a cube. The example uses one texture placed on each side of a cube. The cubes vertices have been numbered in the same way as our cube structure in http://www.andypike.com/tutorials/directx8/003.htm and our code for this tutorial.
Therefore, the texture coordinates for each vertex are as follows (where vertex number = (U, V)):
0 = (0, 1) 9 = (0, 0)
1 = (0, 0) 10 = (1, 1)
2 = (1, 1) 11 = (1, 0)
3 = (1, 0) 12 = (0, 1)
4 = (0, 1) 13 = (0, 0)
5 = (0, 0) 14 = (0, 1)
6 = (1, 1) 15 = (0, 0)
7 = (1, 0) 16 = (1, 1)
8 = (0, 1) 17 = (1, 0)
Fig 6.2
Step 1: Modify FVF and Custom Vertex
This first thing that we need to do is change our custom vertex structure to hold the texture coordinates U and V, these are the two new FLOAT values tu and tv. We also need to modify our FVF to match by adding the D3DFVF_TEX1 flag.
//Define a FVF for our cuboids
#define CUBIOD_D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
//Define a custom vertex for our cuboids
struct CUBIOD_CUSTOMVERTEX {
FLOAT x, y, z;
DWORD colour;
FLOAT tu, tv;
};
Step 2: Load Texture
We need to add a new member variable to our CCuboid class to hold a pointer to the texture once it is loaded. The new member is called m_pTexture and is of type LPDIRECT3DTEXTURE8. We then need a new method to set the texture by passing in a filename, remember that the file needs to be a .bmp.
LPDIRECT3DTEXTURE8 m_pTexture;
bool CCuboid::SetTexture(const char *szTextureFilePath) {
if (FAILED(D3DXCreateTextureFromFile(m_pD3DDevice, szTextureFilePath, &m_pTexture))) {
return false;
}
return true;
}
Step 3: Set Texture Coordinates
In our UpdateVertices method of CCudoid, we need to set the texture coordinates for each vertex. Notice that after the colour value for each vertex we have added two new values, these are the U and V values of our texture coordinates. These texture coordinates match the values from Fig 6.2.
bool CCuboid::UpdateVertices() {
VOID* pVertices;
//Store each point of the cube together with it's colour and texture coordinates
//Make sure that the points of a polygon are specified in a clockwise direction,
//this is because anti-clockwise faces will be culled
//We will use a three triangle strips to render these polygons (Top, Sides, Bottom).
CUBIOD_CUSTOMVERTEX cvVertices[] = {
//Top Face
{m_rX – (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(0, 0, 255), 0.0f, 1.0f,}, //Vertex 0 – Blue
{m_rX – (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 0.0f, 0.0f,}, //Vertex 1 – Red
{m_rX + (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 1.0f, 1.0f,}, //Vertex 2 – Red
{m_rX + (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0.0f,}, //Vertex 3 – Green
//Face 1
{m_rX – (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 0.0f, 1.0f,}, //Vertex 4 – Red
{m_rX – (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(0, 0, 255), 0.0f, 0.0f,}, //Vertex 5 – Blue
{m_rX + (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(0, 255, 0), 1.0f, 1.0f,}, //Vertex 6 – Green
{m_rX + (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0.0f,}, //Vertex 7 – Red
//Face 2
{m_rX + (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(0, 0, 255), 0.0f, 1.0f,}, //Vertex 8 – Blue
{m_rX + (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(0, 255, 0), 0.0f, 0.0f,}, //Vertex 9 – Green
//Face 3
{m_rX – (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(0, 255, 0), 1.0f, 1.0f,}, //Vertex 10 – Green
{m_rX – (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0.0f,}, //Vertex 11 – Red
//Face 4
{m_rX – (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 0.0f, 1.0f,}, //Vertex 12 – Red
{m_rX – (m_rWidth/2), m_rY + (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(0, 0, 255), 0.0f, 0.0f,}, //Vertex 13 – Blue
//Bottom Face
{m_rX + (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(0, 255, 0), 0.0f, 1.0f,}, //Vertex 14 – Green
{m_rX + (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(0, 0, 255), 0.0f, 0.0f,}, //Vertex 15 – Blue
{m_rX – (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ – (m_rDepth/2), D3DCOLOR_XRGB(255, 0, 0), 1.0f, 1.0f,}, //Vertex 16 – Red
{m_rX – (m_rWidth/2), m_rY – (m_rHeight/2), m_rZ + (m_rDepth/2), D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0.0f,}, //Vertex 17 – Green
};
//Get a pointer to the vertex buffer vertices and lock the vertex buffer
if (FAILED(m_pVertexBuffer->Lock(0, sizeof(cvVertices), (BYTE**)&pVertices, 0))) {
return false;
}
//Copy our stored vertices values into the vertex buffer
memcpy(pVertices, cvVertices, sizeof(cvVertices));
//Unlock the vertex buffer
m_pVertexBuffer->Unlock();
return true;
}
Step 4: Rendering
The final code change is in the Render method of CCuboid. We need to set the texture that we want to render using SetTexture. Then we need to set how the texture should be rendered by using the SetTextureStageState method of our device. We have selected that our texture should be rendered without any blending or similar effects. You can blend your texture with other textures or the colour of the vertices depending on which flags to select.
//Set how the texture should be rendered.
if (m_pTexture != NULL) {
//A texture has been set. We don't want to blend our texture with
//the colours of our vertices, so use D3DTOP_SELECTARG1
m_pD3DDevice->SetTexture(0, m_pTexture);
m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
} else {
//No texture has been set. So we will disable texture rendering.
m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
Once you have made these changes, you should finish up with five rotating cubes, each with a different texture (shown below).
In this tutorial we've learnt all about textures. There is more to textures in DirectX than that, and we'll take a look at these topics in a future tutorial. In the next tutorial, we'll look into lighting.