Rendering from Vertex and Index Buffers |
Microsoft Direct3D supports both indexed and nonindexed drawing methods. The indexed methods use a single set of indices for all vertex components. Vertex data is stored in vertex buffers, and index data is stored in index buffers. Listed below are a few common scenarios for drawing primitives using vertex and index buffers. These examples compare the use of Device.DrawPrimitives and Device.DrawIndexedPrimitives.
Suppose you want to draw the following quad.
If you use the Triangle List primitive type to render the two triangles, each triangle is stored as three individual vertices, resulting in a vertex buffer similar to this.
To perform the drawing call, draw two triangles, starting at location 0 within the vertex buffer. If culling is enabled, the order of the vertices is important. This example assumes the default counterclockwise culling state, so visible triangles must be drawn in clockwise order. The Triangle List primitive type simply reads three vertices in linear order from the buffer for each triangle, so the following C# call draws triangles (0, 1, 2) and (3, 4, 5).
[C#]
Device.DrawPrimitives(PrimitiveType.TriangleList, // PrimitiveType 0, // StartVertex 2); // PrimitiveCount
As you will notice, the vertex buffer contains duplicate data in locations 0 and 4, 2 and 5. This makes sense because the two triangles share two common vertices. This duplicate data is wasteful, and the vertex buffer can be compressed by using an index buffer. A smaller vertex buffer reduces the amount of vertex data that must be sent to the graphics adapter. Even more importantly, using an index buffer allows the adapter to store vertices in a vertex cache; if the primitive being drawn contains a recently used vertex, that vertex can be fetched from the cache instead of reading it from the vertex buffer, which results in a significant performance increase.
An index buffer 'indexes' into the vertex buffer so that each unique vertex needs to be stored only once in the vertex buffer. Here is an indexed approach to the drawing scenario above.
The index buffer stores VB Index values, which reference a particular vertex within the vertex buffer. A vertex buffer can be thought of as an array of vertices, so the VB Index is simply the index into the vertex buffer for the target vertex. Similarly, an IB Index is an index into the index buffer. This can get very confusing very quickly if you are not careful, so be sure you are clear on the vocabulary being used: VB Index values index into the vertex buffer, IB Index values index into the index buffer, and the index buffer itself stores VB Index values.
The drawing call is shown below. The meanings of all of the arguments are discussed at length for the next drawing scenario; for now, just note that this call is again instructing Direct3D to render a triangle list that contains two triangles, starting at location 0 within the index buffer. The following C# call draws the same two triangles in the exact same order as before, ensuring a proper clockwise orientation.
[C#]
Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, // PrimitiveType 0, // BaseVertexIndex 0, // MinIndex 4, // NumVertices 0, // StartIndex 2); // PrimitiveCount
Suppose now that you want to draw only the second triangle, but you want to use the same vertex buffer and index buffer you used when drawing the entire quad.
For this drawing call, the first IB Index used is 3; this value is called the StartIndex. The lowest VB Index used is 0; this value is called the MinIndex. Even though only three vertices are required to draw the triangle, those three vertices are spread across four adjacent locations in the vertex buffer; the number of locations within the contiguous block of vertex buffer memory required for the drawing call is called NumVertices, and is set to 4 in this call. The MinIndex and NumVertices values are really just hints to help Direct3D optimize memory access during software vertex processing, and could simply be set to include the entire vertex buffer at the price of performance.
Here is the drawing C# call for the single triangle case. The meaning of the BaseVertexIndex argument will be explained next.
[C#]
Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, // PrimitiveType 0, // BaseVertexIndex 0, // MinIndex 4, // NumVertices 3, // StartIndex 1); // PrimitiveCount
BaseVertexIndex is a value that is effectively added to every VB Index stored in the index buffer. For example, if a value of 50 had been passed in for BaseVertexIndex during the previous call, that would functionally be the same as using the following index buffer for the duration of the Device.DrawIndexedPrimitives call.
This value is rarely set to anything other than 0, but it can be useful if you want to decouple the index buffer from the vertex buffer: If, when filling in the index buffer for a particular mesh, the location of the mesh within the vertex buffer is not yet known, you can simply pretend that the mesh vertices will be located at the start of the vertex buffer. When it is time to make the draw call, simply pass the actual starting location as the BaseVertexIndex.
This technique also can be used when drawing multiple instances of a mesh using a single index buffer; for example, if the vertex buffer contained two meshes with identical draw orders but slightly different vertices (perhaps different diffuse colors or texture coordinates), both meshes could be drawn by using different values for BaseVertexIndex. Taking this concept one step further, you could use one index buffer to draw multiple instances of a mesh, each contained in a different vertex buffer, simply by cycling which vertex buffer is active and adjusting the BaseVertexIndex as needed. Note that the BaseVertexIndex value also is automatically added to the MinIndex argument, which makes sense when you see how it is used.
Suppose now that you again want to draw only the second triangle of the quad using the same index buffer as before; however, a different vertex buffer is being used in which the quad is located at VB Index 50. The relative order of the quad vertices remains unchanged, and only the starting location within the vertex buffer is different. The index buffer and vertex buffer would look like this.
Here is the appropriate draw C# call; note that BaseVertexIndex is the only value that has changed from the previous scenario:
[C#]
Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, // PrimitiveType 50, // BaseVertexIndex 0, // MinIndex 4, // NumVertices 3, // StartIndex 1); // PrimitiveCount
Send comments about this topic to Microsoft. © Microsoft Corporation. All rights reserved.
Feedback? Please provide us with your comments on this topic.
For more help, visit the DirectX Developer Center