0
votes

Previously I was using a separate vertex and index buffer for each mesh, but I'd like to try using a single large vertex buffer to reduce DrawIndexed() calls. Let's say I have the following arrays:

SimpleVertex vertices[] =
{
    { XMFLOAT3(-1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
};

WORD indices[] =
{
    3,1,0,
    2,1,3,

    0,5,4,
    1,5,0,

    3,4,7,
    0,4,3,

    1,6,5,
    2,6,1,

    2,7,6,
    3,7,2,

    6,4,5,
    7,4,6,
};

This works great for a single indexed cube. But, what if I wish to draw two cubes? How do I set up the index buffer to handle that? I'm confused as to whether the indices are local to each cube and thus should just repeat every 36 indices, or if they should be incremented as such:

SimpleVertex vertices[] =
{
    //first cube
    { XMFLOAT3(-1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
    //second cube
    { XMFLOAT3(-2.0f, 2.0f, -2.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(2.0f, 2.0f, -2.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(2.0f, 2.0f, 2.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-2.0f, 2.0f, 2.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-2.0f, -2.0f, -2.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(2.0f, -2.0f, -2.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(2.0f, -2.0f, 2.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-2.0f, -2.0f, 2.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
};
WORD indices[] =
{
    //First cube
    3,1,0,
    2,1,3,

    0,5,4,
    1,5,0,

    3,4,7,
    0,4,3,

    1,6,5,
    2,6,1,

    2,7,6,
    3,7,2,

    6,4,5,
    7,4,6,

    //second cube
    11,9,8,
    10,9,11,

    8,13,12,
    9,13,8,

    11,12,15,
    8,12,11,

    9,14,13,
    10,14,9,

    10,15,14,
    11,15,10,

    14,12,13,
    15,12,14,
};

So basically, I'm trying to understand how to draw one large index buffer with multiple objects. Am I thinking about this correctly or should I have the buffer re-use the same index buffer over and over?

I'm aware of using Instancing, but there are times where the geometry changes, so I need to avoid it in this case.

1

1 Answers

0
votes

Decided to just start writing code to attack the theory blind. Turns out you do indeed need to increment the index array to treat a large vertex array as one mesh. I wrote a function to illustrate this for those interested:

UINT* VertexCompiler::BuildIndexArray()
{
    UINT* indices;

    int indexCount = 0;

    for (int i = 0; i < (int)mVertexObjects.size(); i++)
        indexCount += mVertexObjects[i].NumIndices;

    mIndexCount = indexCount;

    indices = new UINT[indexCount];

    int numObjects = (int)mVertexObjects.size();
    int index = 0;


    for (int i = 0; i < numObjects; i++)
    {
        for (int j = 0; j < (int)mVertexObjects[i].NumIndices; j++)
        {
            indices[index] = mVertexObjects[i].Indices[j] + (mVertexObjects[i].NumVertices * i);
            index++;
        }

    }

    return indices;
}

Be sure to delete the pointer to indices after you're finished with it. Usually it's poor design to allocate memory inside of a function and delete it outside, but this is just for demonstration purposes. Typically you should allocate the index array outside and pass it as a pointer to the function.

One important thing to note is the use of UINT. Most textbooks and articles on the subject allocate smaller index buffers with WORD. Your incremented index array will overflow at index value 65535 using WORD memory allocations. So, if you're rendering a large number of vertices where the index would exceed 16 bits, use UINT and don't forget to switch to DXGI_FORMAT_R32_UINT instead of DXGI_FORMAT_R16_UINT.

E.g.

IASetIndexBuffer(indicesBuffer, DXGI_FORMAT_R32_UINT, 0);