Direct3D11 and SharpDX - How to pass a model instance's world matrix as an input to a vertex shader

Using Direct3D11, I'm trying to pass a matrix into my vertex shader from the instance buffer that is associated with a given model's vertices and I can't seem to construct my InputLayout without throwing an exception.

cbuffer ConstantBuffer : register(b0)
{
matrix World;
matrix View;
matrix Projection;
}

struct VIn
{
float4 position: POSITION;
matrix instance: INSTANCE;
float4 color: COLOR;
};

struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};

{
VOut output;
output.position = mul(input.position, input.instance);
output.position = mul(output.position, View);
output.position = mul(output.position, Projection);
output.color = input.color;
return output;
}


The input layout looks like this:

var elements = new[]
{
new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, InputClassification.PerVertexData, 0),
new InputElement("INSTANCE", 0, Format.R32G32B32A32_Float, 0, 0, InputClassification.PerInstanceData, 1),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0)
};
InputLayout = new InputLayout(device, signature, elements);


The buffer initialization looks like this:

public ModelDeviceData(Model model, Device device)
{
Model = model;
var vertices = Helpers.CreateBuffer(device, BindFlags.VertexBuffer, model.Vertices);
var instances = Helpers.CreateBuffer(device, BindFlags.VertexBuffer, Model.Instances.Select(m => m.WorldMatrix).ToArray());
VerticesBufferBinding = new VertexBufferBinding(vertices, Utilities.SizeOf<ColoredVertex>(), 0);
InstancesBufferBinding = new VertexBufferBinding(instances, Utilities.SizeOf<Matrix>(), 0);
IndicesBuffer = Helpers.CreateBuffer(device, BindFlags.IndexBuffer, model.Triangles);
}


The buffer creation helper method looks like this:

public static Buffer CreateBuffer<T>(Device device, BindFlags bindFlags, params T[] items)
where T : struct
{
var len = Utilities.SizeOf(items);
var stream = new DataStream(len, true, true);
foreach (var item in items)
stream.Write(item);
stream.Position = 0;
var buffer = new Buffer(device, stream, len, ResourceUsage.Default,
bindFlags, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
return buffer;
}


The line that instantiates the InputLayout object throws this exception:

*HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.*

Note that the data for each model instance is simply an instance of SharpDX.Matrix.

EDIT

Based on Tordin's answer, it sems like I have to modify my code like so:

var elements = new[]
{
new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, InputClassification.PerVertexData, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0),
new InputElement("INSTANCE0", 0, Format.R32G32B32A32_Float, 0, 1, InputClassification.PerInstanceData, 1),
new InputElement("INSTANCE1", 1, Format.R32G32B32A32_Float, 16, 1, InputClassification.PerInstanceData, 1),
new InputElement("INSTANCE2", 2, Format.R32G32B32A32_Float, 32, 1, InputClassification.PerInstanceData, 1),
new InputElement("INSTANCE3", 3, Format.R32G32B32A32_Float, 48, 1, InputClassification.PerInstanceData, 1),
};


struct VIn
{
float3 position: POSITION;
float4 color: COLOR;
matrix instance: INSTANCE;
};

{
VOut output;
output.position = mul(input.position, input.instance);
output.position = mul(output.position, View);
output.position = mul(output.position, Projection);
output.color = input.color;
return output;
}


However I still get an exception.

• Have you turned on the D3D11 debug layer? It should provide a more informative error message than just "The parameter is incorrect." – Nathan Reed Nov 1 '13 at 17:56
• @NathanReed unfortunately in this case the debugger doesn't tell me anything useful at all. I'm on Windows 8, with VS2012, so I'm assuming you meant Debug -> Graphics -> Start Diagnostics. screencast.com/t/UgVqCz9cWy1 – Nathan Ridley Nov 1 '13 at 18:04
• No, that's not what I meant. The D3D11 debug layer is turned on by passing a flag when you create the device (at least in C++; I'm not sure how to get to it in SharpDX). It causes internal D3D errors/warnings to be printed to the Output window in VS. They usually give a lot more information than the error codes returned from D3D calls (which is what SharpDX is generating the exception from). – Nathan Reed Nov 1 '13 at 18:06
• I have that turned on as well, but it doesn't seem to be providing any additional information in the output window. At least not by the time the crash occurs. – Nathan Ridley Nov 1 '13 at 18:14
• @NathanReed Possible success - when I change the four input parameters in my C# code to all be named "INSTANCE", the thing runs, though I have no 3D cube on the screen anymore, but that might be a different bug. – Nathan Ridley Nov 1 '13 at 18:20

in your input layout, you are only specifying one part of the matrix. you have to specif the other three. You are saying that you have a VECTOR, not a matrix. to build a matrix, you must have 4 elements for a matrix, and saying that they belong into a specific register.

Reading this link, says on the second argument "a 4x4 matrix would have four components each with the semantic name"

• Hi, thanks for the answer. I've tried to modify my code like you explained, but I'm still getting an exception. Could you take a look at my edit and see if I misunderstood? Thanks. – Nathan Ridley Nov 1 '13 at 13:01
• @NathanRidley You need to provide the correct offsets for the rows of the matrix, i.e. 0, 16, 32, 48 instead of all zeroes. Also, you're trying to put everything in slot 0, but the per-vertex data and per-instance data need to go in different slots since they're different buffers. When you do SetVertexBuffers you would pass both the vertex and instance buffers, so they'll get bound to slots 0 and 1 (for example). – Nathan Reed Nov 1 '13 at 17:59
• Thanks, yeah I've updated my code (and put the edits into my question above) to use slot #1 and the appropriate offsets, but unfortunately it's still not working. Same error. I've also fixed up the shader so it takes a matrix input, as per what someone told me in gamedev.net. Finally, I've put all of my code up on github: github.com/axefrog/game-dev-learning ... ultimately, my code still throws exactly the same exception. Struggling to think what else I could try... – Nathan Ridley Nov 1 '13 at 18:11

This may be a bit late but if anyone else would come across this topic, this answer is supposed to be a more extensive answer to the question as I believe some things are not properly pointed out.

First off, as clarified by a comment above the input layout has to use a predefined sematic name, in this case we could use:

{ "TEXCOORD", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "TEXCOORD", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "TEXCOORD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
{ "TEXCOORD", 4, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 },


Although this will only work if your instance vertex buffer is bound at slot 1. Also note that we start with the sematic name "TEXCOORD1" as most applications already have "TEXCOORD" bound to the actual texture-coordinates for the object.

Now in the vertex shader we will have to provide an appropriate input struct which should match the input layout we have defined, for example:

struct VS_IN
{
float3 Pos : POSITION;
float2 UV : TEXCOORD;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float4 InstancePos0 : TEXCOORD1;
float4 InstancePos1 : TEXCOORD2;
float4 InstancePos2 : TEXCOORD3;
float4 InstancePos3 : TEXCOORD4;
};


Then we simply have to construct a 4x4 matrix from the instanced data we have provided:

float4x4 world = float4x4(input.InstancePos0, input.InstancePos1, input.InstancePos2, input.InstancePos3);