1
\$\begingroup\$

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));
}
\$\endgroup\$
8
  • \$\begingroup\$ This is a really localized question, and it's missing a lot of information to answer it (how pBuffer and iBuffer are defined, what Update does, how objects are rendered, et cetera). \$\endgroup\$
    – user1430
    Commented Oct 13, 2011 at 16:26
  • 1
    \$\begingroup\$ That said, creating one set of buffers per cube is not the way to go. You generally would want to have one buffer representing a cube at the origin, and each cube instance has a model-to-world transformation matrix that positions/rotates the cube in the world. \$\endgroup\$
    – user1430
    Commented Oct 13, 2011 at 16:27
  • 1
    \$\begingroup\$ @JoshPetrie I don't see a reason to DV. Debugging tricky situations is something we should be able to help each other out with. Someone might have C++ DX10 experience who ran into something similar before. \$\endgroup\$
    – ashes999
    Commented Oct 13, 2011 at 16:28
  • \$\begingroup\$ Related discussion: meta.gamedev.stackexchange.com/questions/641/… \$\endgroup\$
    – user1430
    Commented Oct 13, 2011 at 16:29
  • \$\begingroup\$ In case I wasn't clear, I downvoted because I don't believe there's enough information here to provide an answer that isn't conjecture or speculation. \$\endgroup\$
    – user1430
    Commented Oct 13, 2011 at 16:39

1 Answer 1

2
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ So are you saying that there is only a small difference between instanced cubes and the vertex-shader translated one? If the difference is simply that you store the transforms in a list of matrices, why is instancing so much better? Is it because it's all done on the GPU or something? \$\endgroup\$ Commented Oct 14, 2011 at 8:27
  • \$\begingroup\$ Instancing lets you do the whole thing in one draw call. There's a small memory and performance cost for each draw call, so reducing the total number of them is generally good. \$\endgroup\$ Commented Oct 14, 2011 at 16:41
  • \$\begingroup\$ Thanks, I've got it working the first way. very helpful! \$\endgroup\$ Commented Oct 14, 2011 at 18:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .