Basically, a vertex buffer is a piece of memory that is either located in system memory or video memory, and as the name may suggest you, it holds the vertex informations for the object you want to draw. Starting from the first DirectX 9 release, it is possible to store more than one entity in the same vertex buffer, because the support functions accepts an offset parameters that let you choose from which vertex you want to start to operate.
To create a vertex buffer, the CreateVertexBuffer method is used. Here’s its prototype:
HRESULT IDirect3DDevice9::CreateVertexBuffer ( // Length of the vertex buffer UINT Length, // Usage flags DWORD Usage, // Vertex format DWORD FVF, // Memory pool D3DPOOL Pool, // Pointer to a vertex buffer interface object pointer IDirect3DVertexBuffer9** ppVertexBuffer, // Reserved, must be null HANDLE* pSharedHandle );
The Usage parameter is used to tell DirectX what we’re going to do with the object we want to create. If i had created a software vertex processing device, i would have to add the D3DUSAGE_SOFTWAREPROCESSING flag; since i’ve specified hardware processing instead, this flag is not set, and the default approach (hardware) will be used. The next flag i’ve specified into the source code (D3DUSAGE_WRITEONLY) will be explained later when i speak about the memory pools.
The FVF (Flexible Vertex Format) parameter can be set to a valid FVF identifier in case you want to use a standard vertex format. Here’s the one i used in the source code:
DWORD g_dwVertexFormat = D3DFVF_XYZ | D3DFVF_DIFFUSE;
It tells DirectX that for each vertex stored in the buffer, 3 float data types will be reserved for the XYZ coordinates, and a double-word (4 bytes) will be used to define the color. I will not explain here what happen when you set it to zero; refer to the documentation or wait for the next tutorials.
Now that we have decided the format we want to use, we must create a vertex structure.
// Structure of a D3DFVF_XYZ | D3DFVF_DIFFUSE vertex
typedef struct __VERTEX
{
// Position
FLOAT fX, fY, fZ;
// Color
DWORD dwDiffuseColor;
} VERTEX, *LPVERTEX;
Note that DirectX expects to find the structure fields in a specific order; if you swap two variables, the vertex buffer will not be read in the correct way, and the geometry will appear corrupted. This is the order you must use:
- Position
- RHW value (only for already transformed vertices)
- Blending values (up to 5)
- Vertex normal
- Vertex point size
- Diffuse color
- Specular color
- Texture coordinates (up to 8 pairs of UV coordinates)
The memory pool field defines where the created object will be stored; valid values are:
- D3DPOOL_DEFAULT: DirectX will automatically store the resource in the best position available according to the specified usage flags (usually, it is placed into video memory). When using this pool for vertex buffer, the D3DUSAGE_WRITEONLY must be specified to improve performances. Default memory pool resources must be released everytime a lost device status is detected; if you do not release them before calling the Reset method, you will deadlock the application (TestCooperativeLevel will return a D3DERR_DEVICENOTRESET status but the Reset method will always fail).
- D3DPOOL_MANAGED: The resources will be stored in system memory and copied into video memory as needed. Managed resources does not need to be released and recreated when the device is reset.
- D3DPOOL_SYSTEMMEM: This memory pool is located into the system memory. The resources will not be copied into video memory and does not need to be created after a lost device. The pourpose of this memory pool is to store data used to update surfaces or textures.
- D3DPOOL_SCRATCH: It’s nearly the same as the previous one; the contents of the resources created here are indipendent from the DirectX device and can only be created, copied and locked. They can’t be set as textures or render targets.
The vertex buffer has been created but it doesn’t contains anything yet; in order to fill it with our vertices, we first need to define them in some way. Here’s where the vertex structure we created before comes in handy:
VERTEX g_a_vxVertices[] =
{
// First vertex (red) of the first triangle
-5.0f, 5.0f, 0.0f, 0xFFFF0000,
// Second vertex (blue) of the first triangle
5.0f, 5.0f, 0.0f, 0xFF0000FF,
// Third vertex (green) of the first triangle
-5.0f, -5.0f, 0.0f, 0xFF00FF00,
// First vertex (yellow) of the second triangle
5.0f, 5.0f, 0.0f, 0xFFFFF200,
// Second vertex (purple) of the second triangle
5.0f, -5.0f, 0.0f, 0xFF8F00FF,
// Third vertex (orange) of the second triangle
-5.0f, -5.0f, 0.0f, 0xFFFF8F00
};
Now that we have defined the geometry for our object, we need to store it inside the vertex buffer. The vertices have to be copied to the buffer returned from the Lock method; here’s the prototype:
HRESULT IDirect3DVertexBuffer9::Lock ( // Offset into the vertex data UINT OffsetToLock, // Size of the vertex data to lock UINT SizeToLock, // Pointer to a memory buffer containing the returned vertex data VOID **ppbData, // Flags DWORD Flags );
A simple memcpy call will do the job:
memcpy(ReturnedPointer, ArrayOfVertices, sizeof(ArrayOfVertices))
The vertex buffer is ready to be drawn, we just need to call the Unlock() method; this will update the vertex data with the user-supplied buffer and release the lock. Everything i’ve explained now takes place inside the vInitializeDeviceObjects function.
Before we can render the vertices, we need to call BeginScene and tell DirectX the format we used to declare the vertices:
DirectX9Device->SetFVF(g_D3DFVF_XYZ | D3DFVF_DIFFUSE)
The last step is to set the stream source and call the draw method:
DirectX9Device->SetStreamSource ( // Stream number 0, // Vertex buffer VertexBuffer, // Offset into the vertex buffer 0, // Can be used for instancing, we will set this to the vertex size sizeof(VERTEX) ) DirectX9Device->DrawPrimitive ( // Type of primitive to render D3DPT_TRIANGLELIST, // First vertex to draw 0, // Primitive count sizeof(g_a_vxVertices) / sizeof(VERTEX) )
The scene can now be drawn to screen calling EndScene and Present.
Source code: http://insanedevelopers.net/downloads/Sources/DirectX9Tutorials/02 – Vertex Buffers.zip