Original Post
I am learning how to use Vertex and Index buffers with shaders. I am still very new the concept and I am working on a big project course atm.
Basically I have a bunch of tile grid that is 20x15 in size. The tiles depending on what level we load is going to support 1 of 3 different textures. The project is a basic tower defense demonstration. So the tile will either have a Path Straight piece, a Path corner piece, or a plain grass/ground piece.
The corner and straight piece will need to be rotated depending obviously which way the level is designed.
Here is the thing. I have all of this working and displaying the way I want it. (minus the rotation at the moment but I know how I am going to do that). Each tile has their own world matrix to handle the position and rotation of the tile.
Right now I am drawing each of the 300 tiles one by one and because of this my FPS has dropped significantly. I know this is not the way I need to do it, but I am completely lost how I should approach revising this the easiest way. I've heard that I can do everything from combining objects together right before drawing, to building the vertex buffers and index buffers together... I am looking for something that's going to be much more efficient than my approach, but at the same time is simple enough for me to understand, realize again that I am very new to this concept and still learning DirectX.
Here is my Tile class (which is also my grid class) This tile class has a bunch of static methods to work 20x15 grid aspect, as well as it also being used to create Tile objects to hold each tile's properties (world matrix, pointer to texture, etc..)
Here is my header file:
Here is my CPP file
Tile::Initialize() is called at the beginning to setup the buffers and load textures and whatnot.
Tile::generateGrid(); is then call immediately after the initialize to create the grid.
then each frame I call Tile::drawGrid(). Everything else happens internally.
I am planning on talking to my teacher about it tomorrow to see his suggestions on how to make this more efficient, but I figured while I had 24 hours to see if someone had an easy way of explaining it.
If you need anymore information then please let me know!
Thanks
GFT
Basically I have a bunch of tile grid that is 20x15 in size. The tiles depending on what level we load is going to support 1 of 3 different textures. The project is a basic tower defense demonstration. So the tile will either have a Path Straight piece, a Path corner piece, or a plain grass/ground piece.
The corner and straight piece will need to be rotated depending obviously which way the level is designed.
Here is the thing. I have all of this working and displaying the way I want it. (minus the rotation at the moment but I know how I am going to do that). Each tile has their own world matrix to handle the position and rotation of the tile.
Right now I am drawing each of the 300 tiles one by one and because of this my FPS has dropped significantly. I know this is not the way I need to do it, but I am completely lost how I should approach revising this the easiest way. I've heard that I can do everything from combining objects together right before drawing, to building the vertex buffers and index buffers together... I am looking for something that's going to be much more efficient than my approach, but at the same time is simple enough for me to understand, realize again that I am very new to this concept and still learning DirectX.
Here is my Tile class (which is also my grid class) This tile class has a bunch of static methods to work 20x15 grid aspect, as well as it also being used to create Tile objects to hold each tile's properties (world matrix, pointer to texture, etc..)
Here is my header file:
//Tile.h - Used for holding information about each tile.#ifndef TILE_H#define TILE_H#include <d3dx9.h>#include "Vertex.h"#include "DXCamera.h"#include "DXProjection.h"enum TextureType{ //towers TT_TileGrass, TT_TilePathStraight, TT_TilePathCorner,};class Tile{public: //Constructors Tile(int id); ~Tile(); bool occupied; D3DXVECTOR3* getPos(); D3DXMATRIX* getWorld(); IDirect3DTexture9* getCurrentTexture(); int getTextureType(); int getRotationType(); void setTexture(int textureType);private: void generateWorldMatrix(); D3DXVECTOR3 m_xv3Pos; D3DXMATRIX m_m4x4World; IDirect3DTexture9* mp_tCurrentTexture; //pointer to the current texture of that tile int m_iTextureType; int m_iRotationType; int m_iTileID;//static methods and variablespublic: static void initialize(); static void generateGrid(); static void release(); static void onLostDevice(); static void onResetDevice(); static void drawGrid(); static bool SETUP_VARIABLE; static bool SETUP_FUNCTION();private: static vector<Tile*> m_vTileList; //static method calls static void buildIndexBuffer(); static void buildVertexBuffer(); static void buildFX(); static void buildTileBuffers(); //Buffer Member Variables static IDirect3DIndexBuffer9* m_IndexBuffer; static IDirect3DVertexBuffer9* m_VertexBuffer; //FX static ID3DXEffect* m_sFX; //Handles static D3DXHANDLE m_hTech; static D3DXHANDLE m_hWVP; static D3DXHANDLE m_hWorldInvTrans; static D3DXHANDLE m_hLightVecW; static D3DXHANDLE m_hDiffuseMtrl; static D3DXHANDLE m_hDiffuseLight; static D3DXHANDLE m_hAmbientMtrl; static D3DXHANDLE m_hAmbientLight; static D3DXHANDLE m_hSpecularMtrl; static D3DXHANDLE m_hSpecularLight; static D3DXHANDLE m_hSpecularPower; static D3DXHANDLE m_hEyePos; static D3DXHANDLE m_hWorld; static D3DXHANDLE m_hTex; //Lighting static D3DXVECTOR3 m_xv3LightVecW; static D3DXCOLOR m_xcAmbientMtrl; static D3DXCOLOR m_xcAmbientLight; static D3DXCOLOR m_xcDiffuseMtrl; static D3DXCOLOR m_xcDiffuseLight; static D3DXCOLOR m_xcSpecularMtrl; static D3DXCOLOR m_xcSpecularLight; static float m_fSpecularPower; //Textures static IDirect3DTexture9* m_tGrassTile; static IDirect3DTexture9* m_tPathCornerTile; static IDirect3DTexture9* m_tPathStraightTile;};#endifHere is my CPP file
#include "Tile.h"#include "d3dUtil.h"IDirect3DIndexBuffer9* Tile::m_IndexBuffer = NULL;IDirect3DVertexBuffer9* Tile::m_VertexBuffer = NULL;ID3DXEffect* Tile::m_sFX = NULL;D3DXHANDLE Tile::m_hTech = NULL;D3DXHANDLE Tile::m_hWVP = NULL;D3DXHANDLE Tile::m_hWorldInvTrans = NULL;D3DXHANDLE Tile::m_hLightVecW = NULL;D3DXHANDLE Tile::m_hDiffuseMtrl = NULL;D3DXHANDLE Tile::m_hDiffuseLight = NULL;D3DXHANDLE Tile::m_hAmbientMtrl = NULL;D3DXHANDLE Tile::m_hAmbientLight = NULL;D3DXHANDLE Tile::m_hSpecularMtrl = NULL;D3DXHANDLE Tile::m_hSpecularLight = NULL;D3DXHANDLE Tile::m_hSpecularPower = NULL;D3DXHANDLE Tile::m_hEyePos = NULL;D3DXHANDLE Tile::m_hWorld = NULL;D3DXHANDLE Tile::m_hTex = NULL;//LightingD3DXVECTOR3 Tile::m_xv3LightVecW = D3DXVECTOR3(0, 0, 0);D3DXCOLOR Tile::m_xcAmbientMtrl = D3DXCOLOR();D3DXCOLOR Tile::m_xcAmbientLight = D3DXCOLOR();D3DXCOLOR Tile::m_xcDiffuseMtrl = D3DXCOLOR();D3DXCOLOR Tile::m_xcDiffuseLight = D3DXCOLOR();D3DXCOLOR Tile::m_xcSpecularMtrl = D3DXCOLOR();D3DXCOLOR Tile::m_xcSpecularLight = D3DXCOLOR();float Tile::m_fSpecularPower = D3DXCOLOR();//TexturesIDirect3DTexture9* Tile::m_tGrassTile = NULL;IDirect3DTexture9* Tile::m_tPathCornerTile = NULL;IDirect3DTexture9* Tile::m_tPathStraightTile = NULL;vector<Tile*> Tile::m_vTileList;bool Tile::SETUP_VARIABLE = Tile::SETUP_FUNCTION();bool Tile::SETUP_FUNCTION(){ Tile::m_vTileList.push_back(NULL); Tile::m_vTileList.pop_back(); return true;} /***************** ** Constructors ** *****************/Tile::Tile(int id) { m_xv3Pos.x = 0; m_xv3Pos.y = 0; m_xv3Pos.z = 0; m_iTileID = id; Tile::m_vTileList.push_back(this); int a = rand() % 3; setTexture(a);}Tile::~Tile(){ }void Tile::setTexture(int textureType){ //set the current texture pointer for a tile object to one of the 3 defined textures switch(textureType) { case TT_TileGrass: mp_tCurrentTexture = Tile::m_tGrassTile; break; case TT_TilePathStraight: mp_tCurrentTexture = Tile::m_tPathStraightTile; break; case TT_TilePathCorner: mp_tCurrentTexture = Tile::m_tPathCornerTile; break; }}D3DXVECTOR3* Tile::getPos(){ return &m_xv3Pos;}D3DXMATRIX* Tile::getWorld(){ return &m_m4x4World;}IDirect3DTexture9* Tile::getCurrentTexture(){ return mp_tCurrentTexture;}int Tile::getTextureType(){ return m_iTextureType;}int Tile::getRotationType(){ return m_iRotationType;}void Tile::generateWorldMatrix(){ D3DXMATRIX trans; D3DXMatrixTranslation(&trans, m_xv3Pos.x, m_xv3Pos.y, m_xv3Pos.z); m_m4x4World = trans; int a = 0;} /******************* ** Static Methods ** *******************/void Tile::initialize(){ D3DXCreateTextureFromFile(gd3dDevice, "..//Textures//Tile_Grass.dds", &Tile::m_tGrassTile); D3DXCreateTextureFromFile(gd3dDevice, "..//Textures//Tile_PathCorner.dds", &Tile::m_tPathCornerTile); D3DXCreateTextureFromFile(gd3dDevice, "..//Textures//Tile_PathStraight.dds", &Tile::m_tPathStraightTile); Tile::m_xv3LightVecW = D3DXVECTOR3(0.0, 0.0f, -1.0f); Tile::m_xcDiffuseMtrl = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); Tile::m_xcDiffuseLight = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); Tile::m_xcAmbientMtrl = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); Tile::m_xcAmbientLight = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); Tile::m_xcSpecularMtrl = D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f); Tile::m_xcSpecularLight = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f); Tile::m_fSpecularPower = 8.0f; Tile::buildTileBuffers(); Tile::buildFX();}void Tile::generateGrid(){ float x = -2432.0f; float z = 1792.0f; int count = 0; for(int i = 0; i < 15; i++) { for(int j = 0; j < 20; j++) { Tile* temp = new Tile(count); temp->m_xv3Pos.x = x; temp->m_xv3Pos.z = z; x += 256.0f; temp->generateWorldMatrix(); count++; } z -= 256.0f; //decriment Z x = -2432.0f; //reset X } GS::wout << "Size: " << Tile::m_vTileList.size() << endl;}void Tile::release(){ ReleaseCOM(Tile::m_IndexBuffer); ReleaseCOM(Tile::m_VertexBuffer); ReleaseCOM(Tile::m_sFX); ReleaseCOM(Tile::m_tGrassTile); ReleaseCOM(Tile::m_tPathCornerTile); ReleaseCOM(Tile::m_tPathStraightTile); for(int i = 0; i < Tile::m_vTileList.size(); i++) { delete Tile::m_vTileList; }}void Tile::onLostDevice(){ Tile::m_sFX->OnLostDevice();}void Tile::onResetDevice(){ Tile::m_sFX->OnResetDevice();}void Tile::drawGrid(){ /******************** ** START TILE DRAW ** ********************/ gd3dDevice->SetStreamSource(0, Tile::m_VertexBuffer, 0, sizeof(VertexPNT)); gd3dDevice->SetIndices(Tile::m_IndexBuffer); gd3dDevice->SetVertexDeclaration(VertexPNT::Decl); //gd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); gd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); gd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); HR(m_sFX->SetTechnique(m_hTech)); Tile::m_sFX->SetValue(m_hLightVecW, &m_xv3LightVecW, sizeof(D3DXVECTOR3)); Tile::m_sFX->SetValue(m_hDiffuseMtrl, &m_xcDiffuseMtrl, sizeof(D3DXCOLOR)); Tile::m_sFX->SetValue(m_hDiffuseLight, &m_xcDiffuseLight, sizeof(D3DXCOLOR)); Tile::m_sFX->SetValue(m_hAmbientMtrl, &m_xcAmbientMtrl, sizeof(D3DXCOLOR)); Tile::m_sFX->SetValue(m_hAmbientLight, &m_xcAmbientLight, sizeof(D3DXCOLOR)); Tile::m_sFX->SetValue(m_hSpecularLight, &m_xcSpecularLight, sizeof(D3DXCOLOR)); Tile::m_sFX->SetValue(m_hSpecularMtrl, &m_xcSpecularMtrl, sizeof(D3DXCOLOR)); Tile::m_sFX->SetFloat(m_hSpecularPower, m_fSpecularPower); for(int j = 0; j < Tile::m_vTileList.size(); j++) { D3DXMATRIX wvp = (*Tile::m_vTileList[j]->getWorld()) * DXCI->getView() * DXPI->getProj(); Tile::m_sFX->SetMatrix(Tile::m_hWVP, &wvp); D3DXMATRIX worldInvTrans; D3DXMatrixInverse(&worldInvTrans, 0, Tile::m_vTileList[j]->getWorld()); D3DXMatrixTranspose(&worldInvTrans, &worldInvTrans); Tile::m_sFX->SetMatrix(m_hWorldInvTrans, &worldInvTrans); Tile::m_sFX->SetTexture(m_hTex, Tile::m_vTileList[j]->getCurrentTexture()); Tile::m_sFX->SetMatrix(m_hWorld, Tile::m_vTileList[j]->getWorld()); UINT numPasses = 0; Tile::m_sFX->Begin(&numPasses, 0); for(UINT i = 0; i < numPasses; ++i) { Tile::m_sFX->BeginPass(i); gd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12); Tile::m_sFX->EndPass(); } Tile::m_sFX->End(); }}void Tile::buildFX(){ ID3DXBuffer* errors = 0; D3DXCreateEffectFromFile(gd3dDevice, "..//FX//Tile.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_sFX, &errors); if(errors) { MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0); } //m_hTech = m_sFX->GetTechniqueByName("TileTech"); Tile::m_hTech = Tile::m_sFX->GetTechniqueByName("DirLightTexTech"); Tile::m_hWVP = Tile::m_sFX->GetParameterByName(0, "gWVP"); Tile::m_hWorldInvTrans = Tile::m_sFX->GetParameterByName(0, "gWorldInvTrans"); Tile::m_hLightVecW = Tile::m_sFX->GetParameterByName(0, "gLightVecW"); Tile::m_hDiffuseMtrl = Tile::m_sFX->GetParameterByName(0, "gDiffuseMtrl"); Tile::m_hDiffuseLight = Tile::m_sFX->GetParameterByName(0, "gDiffuseLight"); Tile::m_hAmbientMtrl = Tile::m_sFX->GetParameterByName(0, "gAmbientMtrl"); Tile::m_hAmbientLight = Tile::m_sFX->GetParameterByName(0, "gAmbientLight"); Tile::m_hSpecularMtrl = Tile::m_sFX->GetParameterByName(0, "gSpecularMtrl"); Tile::m_hSpecularLight = Tile::m_sFX->GetParameterByName(0, "gSpecularLight"); Tile::m_hSpecularPower = Tile::m_sFX->GetParameterByName(0, "gSpecularPower"); Tile::m_hEyePos = Tile::m_sFX->GetParameterByName(0, "gEyePosW"); Tile::m_hWorld = Tile::m_sFX->GetParameterByName(0, "gWorld"); Tile::m_hTex = Tile::m_sFX->GetParameterByName(0, "gTex");}void Tile::buildTileBuffers(){ // Create the vertex buffer. gd3dDevice->CreateVertexBuffer(24 * sizeof(VertexPNT), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &Tile::m_VertexBuffer, 0); // Write box vertices to the vertex buffer. VertexPNT* v = 0; Tile::m_VertexBuffer->Lock(0, 0, (void**)&v, 0); float halfSize = 256.0f / 2.0f; v[0] = VertexPNT(-halfSize, halfSize, -halfSize, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f); v[1] = VertexPNT(-halfSize, halfSize, halfSize, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); v[2] = VertexPNT(halfSize, halfSize, halfSize, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[3] = VertexPNT(halfSize, halfSize, -halfSize, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f); Tile::m_VertexBuffer->Unlock(); // Create the vertex buffer. gd3dDevice->CreateIndexBuffer(36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &Tile::m_IndexBuffer, 0); // Write box indices to the index buffer. WORD* i = 0; Tile::m_IndexBuffer->Lock(0, 0, (void**)&i, 0); i[0] = 0; i[1] = 1; i[2] = 2; i[3] = 0; i[4] = 2; i[5] = 3; Tile::m_IndexBuffer->Unlock();}Tile::Initialize() is called at the beginning to setup the buffers and load textures and whatnot.
Tile::generateGrid(); is then call immediately after the initialize to create the grid.
then each frame I call Tile::drawGrid(). Everything else happens internally.
I am planning on talking to my teacher about it tomorrow to see his suggestions on how to make this more efficient, but I figured while I had 24 hours to see if someone had an easy way of explaining it.
If you need anymore information then please let me know!
Thanks
GFT