Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

If I have two Vertex Arrays, one for Square, and one for Triangle; what is the best way to bind them to the VertexBuffer?

What are the patterns used to write multiple vertices to the VertexBuffer? Streams? Vectors? Is there an Add, (+) overload that can be used like .pSysMem += anotherMesh.GetVertices()?

  1. Is this possible with objects that have different numbers of Vertices?
  2. Is this possible with objects that have different buffer element descriptions, (one with float4 position data, and another with float3 and texcoords, etc)?

Currently, I am binding one Shape, (a triangle), to the subresource like this:

ModelRenderer::StaticBufferDescription.ByteWidth = bufferSize;
ModelRenderer::StaticBufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER; 


ModelRenderer::StaticSubResourceData.SysMemPitch = 0;
ModelRenderer::StaticSubResourceData.SysMemSlicePitch = 0;
ModelRenderer::StaticSubResourceData.pSysMem = model->GetVertices(); 

DeviceManager::Device->CreateBuffer(
    & ModelRenderer::StaticBufferDescription, 
    & ModelRenderer::StaticSubResourceData, 
    & ModelRenderer::StaticBuffer);
share|improve this question
1  
You may want to convert all the data to triangles on import, it'll make things a whole lot easier. –  Byte56 Jan 29 '13 at 0:19
    
Yeah, I imagine that will be a huge research effort all by itself, how to auto generate indices, or import them, etc. Don't suppose you know different ways for getting different models onto the same buffer? I am looking into using streams now. –  Wind And Flame Jan 29 '13 at 1:22
    
No, sorry, I don't know DirectX that well. I wrote all my own importers so I just convert to triangles and have whatever I want in one buffer (with openGL). –  Byte56 Jan 29 '13 at 1:45

3 Answers 3

up vote 0 down vote accepted

In the example below, individual mesh/instance data is being copyied into a big memory buffer, which is then assigned to the subresource. Alternatively, the instance data could already be in a memory buffer so this wouldn't have to be done every "draw".

Also, a vector is guaranteed to be contiguous in C++11 so you can assign the vector to the subResource.pSysMem = vector, rather than a fixed size array.

If you want to go further than this, you can can stream into the memory buffer being used from a flat file. Just be careful of buffer overruns.

void ModelRenderer::UpdateInstanceBuffer()
    {
        NS::InstanceStateFactory<int> * stateFactory = nullptr;
        stateFactory = (NS::InstanceStateFactory<int> *) NS::ModelFacade::GetInstanceStateFactory();

        // std::vector<NS::Vertex> instances;

        unsigned int memoryAllocationSizeInBytes = sizeof(Position) * 10;

        std::vector<int8_t> buffer(memoryAllocationSizeInBytes);

        int instanceCount = 0;
        int stride = sizeof(Position);

        for(auto & kv : stateFactory->Instances)
        {
            // Push vector arrays into Memory Buffer
            memcpy(&buffer[0] + instanceCount * stride, & kv.second->Position, stride);

            instanceCount ++;
        }

        D3D11_MAPPED_SUBRESOURCE resource;

        HRESULT hResult = DeviceManager::DeviceContext->
            Map(ModelRenderer::InstanceBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);

        // resource.pData = instances.data();
        memcpy(resource.pData, buffer.data(), sizeof(Position) * instanceCount);

        DeviceManager::DeviceContext->Unmap(ModelRenderer::InstanceBuffer.Get(), 0);

        // ModelRenderer::BindInstanceBuffer();

        // delete instances.data();
    }
share|improve this answer

The easiest solution for you is to just settle on a common vertex type for all of your objects, which would be a superset of all the different vertex types you currently have. Yes, I know that right about now you're thinking something like "but that would waste memory!" but always remember - this is a tradeoff, and what you're losing in memory usage you're gaining by not having to call IASetVertexBuffers multiple times with different strides and offsets. Memory isn't everything, buffer changes can be potentially expensive (if nothing else you'll need to break the current batch to do one), and avoiding so many buffer changes can potentially give you much more performance than saving a few lousy kilobytes.

From there you just need to adjust the parameters of your Draw () call as appropriate.

share|improve this answer
    
Thanks, but I think I really am asking something a little more basic. I understand what you said, and the implications... But right now, I am just trying to optimize getting the different Mesh Vertices to the same buffer, even if they are all the same type. I edited and tried to clarify the question a bit. Thanks for your patience. –  Wind And Flame Jan 30 '13 at 1:28

You can definitely put multiple objects in a vertex buffer, even with different numbers of vertices. A vertex buffer doesn't know or care where the "objects" are in it - it's nothing more than a list of vertices. If you have a fixed set of objects you want to draw, you can simply concatenate all your vertices together and put them in one big vertex buffer; when you do your Draw() call, you'll specify the range of vertices to draw from the buffer. Or if you use index buffers and DrawIndexed(), the same applies.

All the vertices in a buffer have to be the same format, though (i.e. the same size and order of components like position, normal, UV etc). You can't mix and match different vertex formats in one buffer. Well, technically perhaps you could, but you'd have to re-call IASetVertexBuffers() with different strides and offsets, and do a separate draw call, for each format. That would pretty much negate the point of putting everything in one big vertex buffer; it would be simpler just to have several buffers.

Now, you brought up instancing, so I'll say a little about that. Instancing is designed to let you repeat an "inner" vertex buffer many times, each time pairing it with a different "outer vertex" (i.e. an instance). Across all the instances drawn in a single draw call, the inner vertex buffer must be the same. So if you have triangles in one buffer and squares in another, you would not be able to draw multiple instances of both of them in one draw call, using hardware instancing. You would have to do one draw call for all the triangles, and one for all the squares.

You have a couple options here. First, you could do the instancing manually, by constructing a huge vertex buffer and copying in the triangle vertices as many times as you have triangles, and the square vertices as many times as you have squares, etc.

The other option, which is advanced, is to use some tricks in the vertex shader to look up the inner vertices from a different place in the buffer depending on a value set in the outer vertex data. This requires all the different instance meshes to be padded out to a common vertex size by adding degenerate triangles. This approach was used in Just Cause 2. For more information see Emil Persson's presentation Graphics Gems for Games (slides 19-24).

share|improve this answer
    
How do you actually assign the vertices to the buffer? Right now, the syntax that I am using seems to be optimized to assign one vertex to pSysMem ... What are ways that could be used, like, could I read vertices from a stream, and dynamically write vertices to that stream while/before the stream is read? How do I get pSysMem to read from a vertice? Or is there an Add overload, pSysMem += anotherMesh().GetVertices()... or should I combine all of my vertices in a Vector ... Or ... :) I am just trying to identify the patterns that are commonly used. ... –  Wind And Flame Jan 30 '13 at 1:25
    
@WindAndFlame I don't know how your framework/engine works. Whatever model->GetVertices() is, that's your code, not D3D. A vertex buffer is simply an array of structs. You just make an array, put your vertices in it, and pass in the pointer and size of the array when you create the buffer. I'm not sure what you mean about reading vertices from a "stream". If you're talking about dynamically updating the vertices each frame, that's done with dynamic vertex buffers. Google that and you'll find plenty of articles on how to do it; it's a common topic. –  Nathan Reed Jan 30 '13 at 1:30
    
my getVertices function returns an array of structs, that is correct, but I am trying to return a LOT of those vertices from different meshes. So, I need I am trying to find a way to efficiently assign all of those vertices to the vertex buffer's array of structs... Perhaps setting the stream as an input to the vertexbuffer. –  Wind And Flame Jan 30 '13 at 4:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.