This tutorial is part of a Collection: 01. DirectX 9 - Braynzar Soft Tutorials
3176
views
10. Textures
It would be pretty hard to make a detailed game without using textures. Here we shall cover how to apply textures to our primitives.
To add a ton more detail to our game, we can apply textures to our triangles. Applying textures to primitives is called Texture Mapping. The IDirect3DTexture9 interface is what represents a texture in Direct3D. Textures use two coordinates to map out the image data onto a triangle, the u-axis and v-axis. The u-axis is horizontal, and the v-axis is verticle. The u-axis goes positively to the right, and the v-axis goes positively down. This is shown in the image below. +[http://www.braynzarsoft.net/image/100128][Texture Coordinates] Each vertice that makes up the triangle or primitive will define the texture coordinates, (u,v), of the triangle. u and v represent how many images that will be mapped over and down on the triangle. Specifying a one for the u-axis tells Direct3D to map one whole image across. The next image shows what would happen if you changed the one's to two's. +[http://www.braynzarsoft.net/image/100129][Texture Coordinates] First thing we need to do is make a pointer to the IDirect3DTexture9 interface so we can store our texture data. We do this with the following line. IDirect3DTexture9* cubetex = 0; We have to change our Vertex Structure a little bit. We need to take out the color members because our texture will color the primitive for us. Then we need to add in our texture coordinates, (u, v). struct Vertex { FLOAT x, y, z; FLOAT u, v; }; Change our Flexible Vertex Format (FVF) so Direct3D knows how to use our vertex structure. We will take out the D3DFVF_DIFFUSE and add in D3DFVF_TEX1. It should look like this: #define VERTEXFVF (D3DFVF_XYZ | D3DFVF_TEX1) In our SetupScene() Function, we use the D3DX function D3DXCreateTextureFromFile to load our image into a IDirect3DTexture9 object. The function is as follows. HRESULT D3DXCreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCSTR pSrcFile, LPDIRECT3DTEXTURE9* ppTexture ); **pDevice **- The device that will make the texture. **pSrcFile **- The Image File. **ppTexture **- Pointer that will hold the texture data. The D3DXCreateTextureFromFile function can load any of the following image formats: TGA, BMP, DDS, JPG, PNG, and DIB. D3DXCreateTextureFromFile( d3dDevice, "braynzar.jpg", &cubetex); Textures are mapped to triangles in screen space. So sometimes the texture that you are using is larger than the primitive on the screen. When this happens, the texture must be minified to fit onto the primitive. Sometimes the texture is smaller than the primitive on the screen. The texture must be magnified to fit onto the primitive. Either way, the texture will get messed up or distorted. Luckily there is something called filters which will smooth this out. Direct3D has three filters. Each filter has a different level of quality. The Better looking the filter is, the slower your program will run. Filters are set with the IDirect3DDevice9::SetSamplerState method. Nearest point sampling - This is the fasted filter, and also the default. It has the least quality of filtering though. These lines will set the minification and magnification filters to nearest point sampling. d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); Linear filtering - Produces alright results. Very fast for most of todays computers. It is recomended you use this as the minimum filter. This is the code to set the filters to linear. d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Anisotropic filtering - Slowest to computer, but makes the best results. This filter needs an extra line to define the quality of the Anisotropic Filtering. This extra line sets D3DSAMP_MAXANISOTROPY level. The higher the level the better the quality. You can check the D3DCAPS9 to see how high your graphics card will support. This sets the quality to 2. d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); d3dDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 2); I used linear filtering. d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); We can use Mipmaps too, which will pretty much take a texture and make a series of smaller and lower resolution textures and customize the filters for each to preserve the most importants details. The mipmap filter is defines how Direct3D will use mipmaps. You can set a mipmap filter with the following code: d3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, filter); Where filter is one of the following: **D3DTEXF_NONE **- No mipmap filter. **D3DTEXF_POINT **- Direct3D will choose the mipmap closest in size to the primitive on the screen. Then Filter that texture with the specified minification and magnification filters. **D3DTEXF_LINEAR **- This will take the two closest mipmaps to the primitive on screen, filter them with the min and mag filters, then linearly combine them to produce the final texture. Using D3DXCreateTextureFromFile will automatically make mipmaps, so mipmaps are pretty much already set up and ready for you to use. d3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); All we gotta do now is set our texture. We set it in the RenderScene() function just before we draw our primitive. Direct3D lets us set up to 8 textures at once. This is called multi-texturing and we will get into that later. d3dDevice->SetTexture(0, cubetex); If you want to disable a texture at a givin time, maybe to render an object without textures, you would do this: d3dDevice->SetTexture(0, 0); Now we are able to apply textures to make our scenes look much more realistic and detailed. I hope you understood all this. Next lesson i plan on covering lighting, hope to see you then! Here's the final code: main.cpp ... ... IDirect3DTexture9* cubetex = 0; //Pointer to store texture data ... ... //The New Vertex structure struct Vertex { FLOAT x, y, z; FLOAT u, v; }; //The New Flexible Vertex Format #define VERTEXFVF (D3DFVF_XYZ | D3DFVF_TEX1) bool SetupScene(){ //Set up our Scene void* pVoid; d3dDevice->CreateVertexBuffer( 36 * sizeof(Vertex), D3DUSAGE_WRITEONLY, VERTEXFVF, D3DPOOL_MANAGED, &CubeVertexBuffer, 0); Vertex squarevertices[] = { //front face { 1.0f,-1.0f,-1.0f, 1.0f, 1.0f}, {-1.0f,-1.0f,-1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f,-1.0f, 0.0f, 0.0f}, { 1.0f,-1.0f,-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f,-1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f,-1.0f, 1.0f, 0.0f}, //right side { 1.0f,-1.0f, 1.0f, 1.0f, 1.0f}, { 1.0f,-1.0f,-1.0f, 0.0f, 1.0f}, { 1.0f, 1.0f,-1.0f, 0.0f, 0.0f}, { 1.0f,-1.0f, 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f,-1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, //left side {-1.0f,-1.0f,-1.0f, 1.0f, 1.0f}, {-1.0f,-1.0f, 1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, {-1.0f,-1.0f,-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, {-1.0f, 1.0f,-1.0f, 1.0f, 0.0f}, //back side {-1.0f,-1.0f, 1.0f, 1.0f, 1.0f}, { 1.0f,-1.0f, 1.0f, 0.0f, 1.0f}, { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, {-1.0f,-1.0f, 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, {-1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, //top side { 1.0f, 1.0f,-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f,-1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f,-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, //bottom side { 1.0f,-1.0f, 1.0f, 1.0f, 1.0f}, {-1.0f,-1.0f, 1.0f, 0.0f, 1.0f}, {-1.0f,-1.0f,-1.0f, 0.0f, 0.0f}, { 1.0f,-1.0f, 1.0f, 1.0f, 1.0f}, {-1.0f,-1.0f,-1.0f, 0.0f, 0.0f}, { 1.0f,-1.0f,-1.0f, 1.0f, 0.0f}, }; CubeVertexBuffer->Lock(0, 0, (void**)&pVoid, 0); //copy the squarevertices[] array into the vertex buffer memcpy(pVoid, squarevertices, sizeof(squarevertices)); CubeVertexBuffer->Unlock(); D3DXCreateTextureFromFile( // Create texture. d3dDevice, "braynzar.jpg", &cubetex); d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); d3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); D3DXMATRIX matView; // the view transform matrix D3DXMatrixLookAtLH(&matView, // the camera position &D3DXVECTOR3 (0.0f, 0.0f, 10.0f), // the look-at position &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the up direction &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // set the view transform to matView d3dDevice->SetTransform(D3DTS_VIEW, &matView); // the projection transform matrix D3DXMATRIX matProjection; D3DXMatrixPerspectiveFovLH(&matProjection, D3DXToRadian(45), // the horizontal field of view (FLOAT)Width / (FLOAT)Height, // aspect ratio 1.0f, // the near view-plane 100.0f); // the far view-plane // set the projection d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjection); d3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); d3dDevice->SetRenderState(D3DRS_LIGHTING, false); return true; } void CleanUpScene(){ //Release memory CubeVertexBuffer->Release(); cubetex->Release(); return; } bool RenderScene(float timeDelta) //Renders a single frame { if( d3dDevice ) { ... ... d3dDevice->SetTexture(0, cubetex); //set texture d3dDevice->SetStreamSource(0, CubeVertexBuffer, 0, sizeof(Vertex)); d3dDevice->SetFVF(VERTEXFVF); d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,12); ... ... } return true; }
Sign in to comment