MULTIMEDIA

DirectX 10 Game Programming : 3D Introduction - Optimizing the Drawing Using Index Buffers

2/24/2013 6:52:53 PM

Now that you know how to draw an object using a vertex buffer, it’s time to take it a step further. You’ll notice as you advance to more complicated objects you’ll end up using some vertices more than once, sharing them between triangles. For instance, drawing a square consisting of two triangles equates to six vertices. Two of these vertices are used twice, so there’s not really a reason that they need to be stored in the vertex buffer more than once. Removing the extra shared vertices and redrawing the object though would give less than desired results. Index buffers give you the power to refer to any vertex in the vertex buffer and use it over and over.

The four unique vertices that make up the square can be stored in the vertex buffer and when the two triangles are created they both just reference the common vertices. While the savings on a small object like a simple square won’t be very much, imagine if you’re eliminating duplicate vertices from a complicated object containing thousands of triangles.

There are four vertices in the following array declaration. Each of these vertices represents a corner of a square.

// Create vertex buffer
VertexPosStruct vertices[] =
{
    D3DXVECTOR3(-0.5f, 0.5f, 0.5f), // 0
    D3DXVECTOR3(0.5f, 0.5f, 0.5f),   // 1
    D3DXVECTOR3(0.5f, -0.5f, 0.5f),   // 2
    D3DXVECTOR3(-0.5f, -0.5f, 0.5f),    // 3
};

Since it would take two triangles to draw the square, there are not enough vertices listed. By introducing an index buffer though, the square can be drawn properly. The following declaration sets up the indices needed for the square.

DWORD indices[] =
{
    0,1,3,
    1,2,3
};

Note

Triangle strips are not always the answer to solving a problem of too many vertices. Most 3D objects can’t be broken down in a single triangle strip but can be optimized using indices.


Creating an Index Buffer

Index buffers and vertex buffers are virtually identical except for the type of data they contain. Being as they are both seen by Direct3D as buffer resources, index buffers are created in a similar fashion to vertex buffers using the CreateBuffer function. The biggest change in the creation process comes in the filling out of the D3D10_BUFFER_DESC structure. Since the buffer being created is an index buffer, the value being passed into the BindFlags variable should be D3D10_BIND-INDEX_BUFFER. This lets Direct3D know the type of buffer to create. An example of how to create an index buffer is shown next.

// The indices that will be in the buffer
DWORD indices[] =
{
    0,1,3,
    1,2,3
};

// Get the number of indices based on the size of the index array
numIndices = sizeof(indices) / sizeof(DWORD);

// The structure describing how the index buffer should be created
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof(DWORD) * numIndices;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;

D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = indices;

// Create the index buffer
HRESULT hr = pD3DDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer);
if (FAILED(hr))
{
    return false;
}

					  

Since each object you create will now need to store the index buffer object as well as the number of indices in the buffer, two new variables can be added to the ModelObject structure. The new variables are in bold.

typedef struct
{
    ID3D10Effect* pEffect;
    ID3D10EffectTechnique* pTechnique;

    // Vertex information
    ID3D10Buffer* pVertexBuffer;
    UINT numVertices;
    ID3D10InputLayout*     pVertexLayout;

    // Index information
						ID3D10Buffer* pIndexBuffer;
						UINT numIndices;
}ModelObject;

DrawIndexed

The Draw function you used previously has a limitation, it can’t draw indexed objects. The DrawIndexed function is used to draw objects using an index buffer. DrawIndexed is very similar to the Draw function discussed earlier except it draws based on indices. The DrawIndexed function takes three parameters.

The first parameter is the number of indices to use. This will normally be a value equal to the number of indices in your index buffer.

The second parameter is the starting index offset. You don’t have to use all the indices in the index buffer, so this value allows you to begin anywhere in the buffer.

The final parameter is the starting index for the vertices. This value is the same as the vertex index parameter that you pass to the Draw function.

An example DrawIndexed call is shown here:

pD3DDevice->DrawIndexed(numIndices, 0, 0);

Before DrawIndexed can correctly draw your objects, you need to make sure that your vertex layout and vertex and index buffers have been set correctly. The following code shows the calls that should be made right before you attempt to draw your object.

// Set the input layout
pD3DDevice->IASetInputLayout(pVertexLayout);

// Set vertex buffer
UINT stride = sizeof(VertexPosStruct);
UINT offset = 0;
pD3DDevice->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);

// Set index buffer
pD3DDevice->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

// Set primitive topology
pD3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

The IASetIndexBuffer function is similar in functionality to IASetVertexBuffers, except the indices are being applied to the hardware.

Although index buffers can definitely benefit you in terms of optimizing your objects, they have one major downside. Because index buffers promote vertex sharing, problems can arise concerning some vertex properties such as colors or texture coordinates. In the case of a cube, a single vertex will affect three different sides. If that single vertex contained blue color data, all three sides will be blending blue. If you then wanted to make each side of the cube a completely separate color, you would need to duplicate the vertices that make up those sides and set them with new vertex color data.

A full example of how to use index buffers can be found in the Chapter6\example2 directory on the CD-ROM.

Figure 1 shows a square created by drawing two triangles using the DrawIndexed function.

Figure 1. A square created using DrawIndexed.

Other  
 
Video tutorials
- How To Install Windows 8 On VMware Workstation 9

- How To Install Windows 8

- How To Install Windows Server 2012

- How To Disable Windows 8 Metro UI

- How To Change Account Picture In Windows 8

- How To Unlock Administrator Account in Windows 8

- How To Restart, Log Off And Shutdown Windows 8

- How To Login To Skype Using A Microsoft Account

- How To Enable Aero Glass Effect In Windows 8

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen
programming4us programming4us
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th