Direct3D11 and SharpDX - How to pass a model instance's world matrix as an input to a vertex shader
- by Nathan Ridley
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.
The shader looks like this:
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 VShader(VIn input)
{
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("INSTANCE0", 0, Format.R32G32B32A32_Float, 0, 0, InputClassification.PerInstanceData, 1),
new InputElement("INSTANCE1", 1, Format.R32G32B32A32_Float, 0, 0, InputClassification.PerInstanceData, 1),
new InputElement("INSTANCE2", 2, Format.R32G32B32A32_Float, 0, 0, InputClassification.PerInstanceData, 1),
new InputElement("INSTANCE3", 3, Format.R32G32B32A32_Float, 0, 0, InputClassification.PerInstanceData, 1),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0)
};
and in the shader:
struct VIn
{
float4 position: POSITION;
float4 instance0: INSTANCE0;
float4 instance1: INSTANCE1;
float4 instance2: INSTANCE2;
float4 instance3: INSTANCE3;
float4 color: COLOR;
};
VOut VShader(VIn input)
{
VOut output;
matrix world = { input.instance0, input.instance1, input.instance2, input.instance3 };
output.position = mul(input.position, world);
output.position = mul(output.position, View);
output.position = mul(output.position, Projection);
output.color = input.color;
return output;
}
However I still get an exception.