Like many beginner graphics programmers I followed a tutorial which showed me how to set up buffer descriptions and fill out the vertex buffer etc... - the steps involved in drawing a simple indexed cube on the screen. There is a leap however when it comes to drawing more than one of these cubes. My code below is the original cube drawing code, if called more than once, each call overwrites the vertex buffer and only one object is drawn - the last one.
So what are the options for drawing many of these cubes?
Cube::Cube(D3DXCOLOR colour, D3DXVECTOR3 min, D3DXVECTOR3 max)
{
// create eight vertices to represent the corners of the cube
VERTEX OurVertices[] =
{
{D3DXVECTOR3(min.x, max.y, max.z), colour},
{D3DXVECTOR3(min.x, max.y, min.z), colour},
{D3DXVECTOR3(min.x, min.y, max.z), colour},
{min, colour},
{max, colour},
{D3DXVECTOR3(max.x, max.y, min.z), colour},
{D3DXVECTOR3(max.x, min.y, max.z), colour},
{D3DXVECTOR3(max.x, min.y, min.z), colour},
};
// create the vertex buffer
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(VERTEX) * 8;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
device->CreateBuffer(&bd, NULL, &pBuffer);
void* pVoid; // the void pointer
pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid); // map the vertex buffer
memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy the vertices to the buffer
pBuffer->Unmap();
// create the index buffer out of DWORDs
DWORD OurIndices[] =
{
0, 1, 2, // side 1
2, 1, 3,
4, 0, 6, // side 2
6, 0, 2,
7, 5, 6, // side 3
6, 5, 4,
3, 1, 7, // side 4
7, 1, 5,
4, 5, 0, // side 5
0, 5, 1,
3, 7, 2, // side 6
2, 7, 6,
};
// create the index buffer
// D3D10_BUFFER_DESC bd; // redefinition
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(DWORD) * 36;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
device->CreateBuffer(&bd, NULL, &iBuffer);
iBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid); // map the index buffer
memcpy(pVoid, OurIndices, sizeof(OurIndices)); // copy the indices to the buffer
iBuffer->Unmap();
//this is simply a single call to the update method that sets up the scale, rotation
//and translation matrices, in case the cubes are static and you don't want to have to
//call update every frame
Update(D3DXVECTOR3(1, 1, 1), D3DXVECTOR3(0, 0, 0), D3DXVECTOR3(0, 0, 0));
}
Answer
If you want to draw many identical cubes, you would typically create the vertex and index buffer once - for a cube at the origin - and then re-use it for multiple draw calls. The vertex shader for the cube would include a local-to-world transformation matrix set via a shader parameter, and you'd change the transform for each draw, causing the cubes to appear in different locations and orientations.
Another way is to use instancing. For instancing you'd have two vertex buffers, one containing a single cube at the origin as before, and the other containing a list of matrices, one for each cube. With the correct vertex shader and input layout set-up you can then do a single draw call to render all the cubes. The "inner" vertex buffer (the single cube) would be static, and if you wanted the cubes to move around, the "outer" vertex buffer (the transforms) would be dynamic, and you'd update it once per frame using D3D10_MAP_WRITE_DISCARD.
Instancing is more efficient for drawing large numbers of small objects, but it takes a bit more code to set up. I'd recommend starting by drawing one cube at a time, setting the matrix via a shader parameter. Get that working first; you can worry about instancing later.
No comments:
Post a Comment