3
votes

I've got a bit of a conundrum that is just flat out stumping me. Let's say i have a couple of shaders all with different vertex types like this:

// light shader
struct vertexInputType
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;
};

// color shader
struct vertexInputType
{
    float4 position : POSITION;
    float4 color : COLOR;
};

// bump mapping shader
struct vertexInputType
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;
    float3 binormal : BINORMAL;
    float3 tangent : TANGENT;
};

Now let's say i have a model with all of this data available. I can't exactly have it all be in the same buffer and render with all 3 as i choose because the data isn't laid out correctly for all of them. I only see two options to make this possible, both of them just as painful.

1) i could have a big buffer in ram that holds all the data, and then every draw call, i grab from the shader object, the vertex type and create a new vertex buffer with the correct information. This, as you can see, would be HORRIBLY slow.

or...

2) i could create multiple ID3D11Buffers when the model is initialized, where one buffer has the position and color, one has position, texcoord, and normal, one has position, texcoord, normal, binormal, and tangent, and also as many buffers needed for any other vertex types the model has information for. This in comparison, obliterates your available vram, making this a nogo as well.

I can't see any other way of doing this. How do you other d3d guys do this?

2

2 Answers

2
votes

It's a good thing you're asking about this in a DX11 context - ID3D11InputLayout simplifies this concept a LOT from previous versions. You can use CreateInputLayout to create multiple layouts of your vertex data (one for each of the structs you've provided above) and call IASetInputLayout with the correct layout at the point(s) you want the same vertex buffer to be interpreted differently.

Edit: Look here for an example of creating the Input-Layout object.

Hope this helps!

1
votes

The trick is to separate your data into streams: P, T, A.

Stream P contains position and normal. This data is required to render the vertices with lighting. You may also include binormals and vertex colour data.

Stream T contains texture information, so can be UP TO 8 TU channels. Care should be taken to store how many channels are encoded in this stream, to ensure memory bandwidth is not wasted copying empty channels across the GPU bus.

Stream A contains animation info, bone weights, etc.

You can have more or less channels depending on the architecture of your rendering pipeline. The trick here is to use FVF's to dynamically define your data layout. One advantage of this architecture is optimum memory bandwidth usage. This is of particular relevance when multiple render passes are required, but not all data is required for each pass.