Before reading this you should have read how to create your custom vertex, FVF and how to create and fill your vertex and index buffers, Buffers.
When we come to render our triangles we will have created a vertex buffer and filled it with all the details of each vertex. We will also have created an index buffer and filled it with the indices of each vertex used by each triangle. We now need to send this data down the rendering pipeline, it is sent down a stream.
Note: these examples use the Fixed Function Pipeline (FFP) for rendering our triangles. If required we could define parts of that pipeline ourselves using vertex or pixel shaders. This is beyond the scope of these notes, however it is worth noting that it is in this rendering section that you would specify your vertex or pixel shader and then follow a process very similar to that described here. I will add shader notes to this site soon as they have really taken over from the FFP and the FFP has been completely removed from Direct3D 10..
An example here will help, this is an example from a cube drawing graphic entity I have written. This cube is coloured by a material and uses no texture. It has 24 vertices and is made up of 12 triangles (2 per side). It uses a custom vertex that contains position and a normal (for lighting). This does not share vertex which is why there are 24 vertex defined (I need separate normals).
void CGfxEntityCube::Render()
{
gD3dDevice->SetMaterial( &m_material );
gD3dDevice->SetTexture(0,NULL);
gD3dDevice->SetStreamSource( 0, m_vb,0, sizeof(CUBEVERTEX) );
gD3dDevice->SetFVF( D3DFVF_CUBEVERTEX );
gD3dDevice->SetIndices( m_ib);
// draw a triangle list using 24 vertices and 12 triangles
gD3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,0,0,24,0,12);
}
Note: since the vertex are never shared between triangles we could avoid using an index buffer completely and instead call the simpler DrawPrimitive function, but here I want to demonstrate the use of index buffers so have included one.
These are simple calls just to indicate which material and texture you will use. You can actually set more than one texture if required by passing the texture stage into the SetTexture call and then set flags to indicate how the textures will be combined (multi-texturing) This, however, is beyond the scope of these notes.
For more information on materials see here: materials
For more information on textures see here: textures
After setting our material and texture we need to specify the stream we are going to send our triangle data down. This is achieved using the SetStreamSource call:
HRESULT SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9 *pStreamData,UINT OffsetInBytes,UINT Stride );
We need to tell Direct3D how our vertex structure was created. We have done that previously by combining flags into our own FVF define, see the FVF notes for more details. The reason we have to do this is that we are sending all our vertex down a stream, the stream does not know how big each piece of information is or how to interpret it. So by passing the FVF we indicate the make up of our custom vertex.
HRESULT SetFVF(DWORD fvf)
fvf - the definition of our fixed function vertex type.
If we are using an index buffer we need to tell Direct3D about it, this is simply:
HRESULT SetIndices( IDirect3DIndexBuffer9 *pIndexData );
Now that we have told the device all about our data and provided pointers to that data we can now ask for that data to be rendered. There are a two main functions available:
DrawPrimitive - use this if you don't need to include an index buffer
DrawIndexedPrimitive - use this if you want to include an index buffer
The parameters to each are much the same, we will look at the DrawIndexedPrimitive function here as this is the one you will use most often:
HRESULT DrawIndexedPrimitive( D3DPRIMITIVETYPE Type, INT BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount );
This function provides methods to allow you to just use sections of your vertex and index buffer. The reason for this is simply for speed. Normally the data for one 3D entity would fill one vertex and index buffer. So every entity maintains its own vertex and index buffer, one per entity. This is normally fine, however for maximum performance it is a good idea to avoid changing vertex and index buffers all the time - graphic cards like a big chunk of data they can work with and don't like changing chunks so much. So what advanced graphics programmers do is pack vertex buffers and index buffers with the data for as many entities as they can. To render each entity they then set the material and texture and use the above call to just render the correct section of each buffer. This is an advanced technique but explains the reason for the index and offset parameters.
Here is an example for drawing a cube with the whole of the render function defined:
void CGfxEntityCube::Render(const D3DXVECTOR3 &pos)
{
// Set our material
gD3dDevice->SetMaterial( &m_material );
// Set the matrix to convert from model space to world space
D3DXMATRIXA16 matWorld
D3DXMatrixTranslation(&matWorld,pos.x,pos.y,pos.z);
gD3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
gD3dDevice->SetStreamSource( 0, m_vb,0, sizeof(CUBEVERTEX) );
gD3dDevice->SetFVF( D3DFVF_CUBEVERTEX );
gD3dDevice->SetIndices( m_ib);
// draw a triangle list using our 24 vertices and 12 triangles
gD3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,0,0,24,0,12);
}
So that's it for rendering primitives. Again remember to check return codes for errors. If it does not work check the debug output in Viz to see if Direct3D is passing you error messages (to get this you must have DirectX in debug mode and run your game using F5 (debug) and not the execute exclamation mark). Often it can be baffling when your code looks correct but you see nothing on the screen, there are a number of reasons this might happen so I have written some notes specifically to help you track down the problem: Invisible geometry
On this site: Materials, Textures, FVF, Buffers, Invisible geometry, Lighting, Matrices, Z Buffer
Other: DrawIndexedPrimitive Demystified