In HLSL, you declare a constant buffer and define the layout of data within that constant buffer. So if you were to have this in your shader:
cbuffer MyConstants
{
float4x4 ViewTransform;
float3 ObjectPosition;
}
Your shader would then expect a constant buffer to be bound that has the same layout. This means it would expect the buffer to start with 16 floats for the matrix, followed immediately by 3 floats for object position.
The idea here is that you specify your data layout in HLSL, and then in your application you would make sure to fill up your constant buffer resource with data using the same layout. There are many ways to do this, but probably the simplest is to do what Eric recommended in his post: make a matching C# struct with the same data layout, fill it with appropriate values, and then use either MapSubresource or UpdateResource to fill the buffer resource with the contents of your struct. For the simple constant buffer in my example, making a matching C# struct should be pretty simple:
[StructLayout(LayoutKind.Sequential)]
public struct MyConstants
{
public Matrix ViewTransform;
public Vector3 ObjectPosition;
}
The one thing you really need to watch out for is that the packing rules for constant buffers can be a little weird. Most notably, if a vector type crosses a 16-byte boundary, then it will move the vector so that it sits on the next 16-byte alignment. As an example, let's add another float3 to our constant buffer layout:
cbuffer MyConstants
{
float4x4 ViewTransform;
float3 ObjectPosition;
float3 LightPosition;
}
So the float4x4 is 64 bytes in size, and a float3 is 12 bytes. So you might think that "LightPosition" would be located at an offset of (64+12) = 76 bytes. However, this is not the case due to the alignment rule that I just mentioned. Since "LightPosition" would straddle a 16-byte boundary, it will give moved up 4 bytes so that it's located at an offset of 80 bytes. To make sure that our C# struct has the same data layout, LayoutKind.Explicit can be used:
[StructLayout(LayoutKind.Explicit)]
public struct MyConstants
{
[FieldOffset(0)]
public Matrix ViewTransform;
[FieldOffset(64)]
public Vector3 ObjectPosition;
[FieldOffset(80)]
public Vector3 LightPosition;
}
As an alternative, you can also just insert padding variables into your struct:
[StructLayout(LayoutKind.Sequential)]
public struct MyConstants
{
public Matrix ViewTransform;
public Vector3 ObjectPosition;
public Uint32 Padding;
public Vector3 LightPosition;
}