Книга: DirectX 8 Programming Tutorial

Implementing an Index Buffer in DirectX

Implementing an Index Buffer in DirectX

The first thing that we are going to do is add an index buffer to our CCuboid class. To do this, we need to add the following code:

Step 1: Creating the Index Buffer

First of all, create two new member variables: one LPDIRECT3DINDEXBUFFER8 called m_pIndexBuffer and a DWORD called m_dwNumOfIndices. m_pIndexBuffer will be a pointer to our index buffer and m_dwNumOfIndices will be the total number of indices for our object, in this case 36 (6 faces x 2 triangles per face x 3 vertices per triangle), which will be set in the constructor.

Then we have a new method called CreateIndexBuffer. We'll call this method once at start-up (in the constructor) before we set our vertex values in our vertex buffer. We populate the values in an index buffer in the same way that we populate vertices in a vertex buffer. First we create the index buffer and get a pointer to it (m_pIndexBuffer). We then store the 36 indices in a temporary WORD array ready to be copied into the index buffer. Then we lock the index buffer, copy the stored indices into it and then unlock it.

LPDIRECT3DINDEXBUFFER8 m_pIndexBuffer;
DWORD m_dwNumOfIndices;
bool CCuboid::CreateIndexBuffer() {
 VOID* pBufferIndices;
 //Create the index buffer from our device
 if (FAILED(m_pD3DDevice->CreateIndexBuffer(m_dwNumOfIndices * sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pIndexBuffer))) {
  return false;
 }
 //Set values for the index buffer
 WORD pIndices[] = {
  0, 1, 2, 3, 2, 1, //Top
  4, 5, 6, 7, 6, 5, //Face 1
  8, 9,10,11,10, 9, //Face 2
  12,13,14,15,14,13, //Face 3
  16,17,18,19,18,17, //Face 4
  20,21,22,23,22,21}; //Bottom
 //Get a pointer to the index buffer indices and lock the index buffer
 m_pIndexBuffer->Lock(0, m_dwNumOfIndices * sizeof(WORD), (BYTE**)&pBufferIndices, 0);
 //Copy our stored indices values into the index buffer
 memcpy(pBufferIndices, pIndices, m_dwNumOfIndices * sizeof(WORD));
 //Unlock the index buffer
 m_pIndexBuffer->Unlock();
 return true;
}

Step 2: Modify the Vertex Buffer

In our UpdateVertices method, we need to make a few changes. First, and most importantly, notice that we are only defining 24 vertices in our cvVertices array rather than 36. As in the last tutorial, we initialise our vertex normals to zero.

The other difference in this tutorial is that we will calculate the average normal for shared vertices. We don't really need to do this for a cube's shared vertices, but we will as a demonstration of how to do it. To do this, we need to new arrays: pNumOfSharedPolygons and pSumVertexNormal. These arrays are used in parallel, pNumOfSharedPolygons will keep a count of how many times a given vertex is used (shared) and pSumVertexNormal will add together each triangle normal for faces that share a given vertex. We'll then use these arrays to calculate the average normal for each vertex.

Once we have defined our vertices, we loop through the indices in our index buffer. So, for each triangle we calculate its face normal, increment the vertices count for each of the three vertices and add the face normal to the vertices normal array.

Then we loop through each vertex, and calculate it's average normal by dividing the sum of face normals by the number of times it has been used. We then normalize this value to ensure that the x, y and z parts of the normal vector are between 0 and 1. Finally, we apply the average normal to each vertex and copy the vertices into our vertex buffer as before.

bool CCuboid::UpdateVertices() {
 DWORD i;
 VOID* pVertices;
 WORD* pBufferIndices;
 D3DXVECTOR3 vNormal;
 DWORD dwVertex1;
 DWORD dwVertex2;
 DWORD dwVertex3;
 WORD* pNumOfSharedPolygons = new WORD[m_dwNumOfVertices]; //Array holds how many times this vertex is shared
 D3DVECTOR* pSumVertexNormal = new D3DVECTOR[m_dwNumOfVertices]; //Array holds sum of all face normals for shared vertex
 //Clear memory
 for (i = 0; i < m_dwNumOfVertices; i++) {
  pNumOfSharedPolygons[i] = 0;
  pSumVertexNormal[i] = D3DXVECTOR3(0,0,0);
 }
 CUBOID_CUSTOMVERTEX cvVertices[] = {
  //Top Face
  {m_rX – (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,}, //Vertex 0
  {m_rX – (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,}, //Vertex 1
  {m_rX + (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,}, //Vertex 2
  {m_rX + (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,}, //Vertex 3
  //Face 1
  {m_rX – (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,}, //Vertex 4
  {m_rX – (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,}, //Vertex 5
  {m_rX + (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,}, //Vertex 6
  {m_rX + (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,}, //Vertex 7
  //Face 2
  {m_rX + (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,}, //Vertex 8
  {m_rX + (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,}, //Vertex 9
  {m_rX + (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,}, //Vertex 10
  {m_rX + (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,}, //Vertex 11
  //Face 3
  {m_rX + (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,}, //Vertex 12
  {m_rX + (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,}, //Vertex 13
  {m_rX – (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,}, //Vertex 14
  {m_rX – (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,}, //Vertex 15
  //Face 4
  {m_rX – (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,}, //Vertex 16
  {m_rX – (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,}, //Vertex 17
  {m_rX – (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,}, //Vertex 18
  {m_rX – (m_rWidth / 2), m_rY + (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,}, //Vertex 19
  //Bottom Face
  {m_rX + (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,}, //Vertex 20
  {m_rX + (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,}, //Vertex 21
  {m_rX – (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ – (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,}, //Vertex 22
  {m_rX – (m_rWidth / 2), m_rY – (m_rHeight / 2), m_rZ + (m_rDepth / 2), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,}, //Vertex 23
 };
 //Get a pointer to the index buffer indices and lock the index buffer
 m_pIndexBuffer->Lock(0, m_dwNumOfIndices * sizeof(WORD), (BYTE**)&pBufferIndices, D3DLOCK_READONLY);
 //For each triangle, count the number of times each vertex is used and
 //add together the normals of faces that share a vertex
 for (i = 0; i < m_dwNumOfIndices; i += 3) {
  dwVertex1 = pBufferIndices[i];
  dwVertex2 = pBufferIndices[i + 1];
  dwVertex3 = pBufferIndices[i + 2];
  vNormal = GetTriangeNormal(&D3DXVECTOR3(cvVertices[dwVertex1].x, cvVertices[dwVertex1].y, cvVertices[dwVertex1].z), &D3DXVECTOR3(cvVertices[dwVertex2].x, cvVertices[dwVertex2].y, cvVertices[dwVertex2].z), &D3DXVECTOR3(cvVertices[dwVertex3].x, cvVertices[dwVertex3].y, cvVertices[dwVertex3].z));
  pNumOfSharedPolygons[dwVertex1]++;
  pNumOfSharedPolygons[dwVertex2]++;
  pNumOfSharedPolygons[dwVertex3]++;
  pSumVertexNormal[dwVertex1].x += vNormal.x;
  pSumVertexNormal[dwVertex1].y += vNormal.y;
  pSumVertexNormal[dwVertex1].z += vNormal.z;
  pSumVertexNormal[dwVertex2].x += vNormal.x;
  pSumVertexNormal[dwVertex2].y += vNormal.y;
  pSumVertexNormal[dwVertex2].z += vNormal.z;
  pSumVertexNormal[dwVertex3].x += vNormal.x;
  pSumVertexNormal[dwVertex3].y += vNormal.y;
  pSumVertexNormal[dwVertex3].z += vNormal.z;
 }
 //Unlock the index buffer
 m_pIndexBuffer->Unlock();
 //For each vertex, calculate and set the average normal
 for (i = 0; i < m_dwNumOfVertices; i++) {
  vNormal.x = pSumVertexNormal[i].x / pNumOfSharedPolygons[i];
  vNormal.y = pSumVertexNormal[i].y / pNumOfSharedPolygons[i];
  vNormal.z = pSumVertexNormal[i].z / pNumOfSharedPolygons[i];
  D3DXVec3Normalize(&vNormal, &vNormal);
  cvVertices[i].nx = vNormal.x;
  cvVertices[i].ny = vNormal.y;
  cvVertices[i].nz = vNormal.z;
 }
 //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();
 //Clean up
 delete pNumOfSharedPolygons;
 delete pSumVertexNormal;
 pNumOfSharedPolygons = NULL;
 pSumVertexNormal = NULL;
 return true;
}

Step 3: Render

Our render function stays the same apart form two things, first of all, we need to tell DirectX that we want to render our polygons from an index buffer. We do this with a call to SetIndices, passing in the index buffer pointer that we want to use. Also, we need to use the DrawIndexedPrimitive method rather than DrawPrimitive to render our polygons.

//Select index buffer
m_pD3DDevice->SetIndices(m_pIndexBuffer, 0);
//Render polygons from index buffer
m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, m_dwNumOfVertices, 0, m_dwNumOfPolygons);

Оглавление книги


Генерация: 1.154. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз