I am investigating a E_INVALIDARG exception that is thrown when I attempt to create a second constant buffer that stores the information for my lights:
// create matrix stack early
CD3D11_BUFFER_DESC constantMatrixBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantMatrixBufferDesc,
nullptr,
&m_constantMatrixBuffer
)
);
DX::ThrowIfFailed(
m_matrixStack.Initialize(m_d3dContext, m_constantMatrixBuffer, &m_constantMatrixBufferData)
);
// also create the light buffer early, we must create it now but we will later
// update it with the light information that we parsed from the model
CD3D11_BUFFER_DESC constantLightBufferDesc(sizeof(LightConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
/* !!!!---- AN E_INVALIDARG IS THROWN BY THE FOLLOWING LINE ----!!!! */
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantLightBufferDesc,
nullptr,
&m_constantLightBuffer
)
);
At this point, it appears that the parameters being passed into the Light's CreateBuffer call are in the same state that the Matrix's are! The problem seems to have to do with the number of bytes being stored in the buffer description.
The buffer is defined as such in the module:
// a constant buffer that contains the 3 matrices needed to
// transform points so that they're rendered correctly
struct ModelViewProjectionConstantBuffer
{
DirectX::XMFLOAT4X4 model;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};
// a constant buffer that contains up to 4 directional or point lights
struct LightConstantBuffer
{
DirectX::XMFLOAT3 ambient[4];
DirectX::XMFLOAT3 diffuse[4];
DirectX::XMFLOAT3 specular[4];
// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
DirectX::XMFLOAT3 attenuation[4];
// the position and direction of the light
DirectX::XMFLOAT3 position[4];
DirectX::XMFLOAT3 direction[4];
// the type of light that we're working with, defined in lights.h
UINT type[4];
// a number from 0 to 4 that tells us how many lights there are
UINT num;
};
And as such in the vertex shader (.hlsl):
cbuffer ModelViewProjectionConstantBuffer : register (b0)
{
matrix model;
matrix view;
matrix projection;
};
cbuffer LightConstantBuffer : register (b1)
{
float3 ambient[4];
float3 diffuse[4];
float3 specular[4];
// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
float3 attenuation[4];
// the position and direction of the light
float3 position[4];
float3 direction[4];
// the type of light that we're working with, defined in lights.h
uint type[4];
// a number from 0 to 4 that tells us how many lights there are
uint num;
}
In an attempt to figure out what is causing this, I have stumbled across this line in the MSDN HLSL Shader documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/ff476898(v=vs.85).aspx):
Each element stores a 1-to-4 component constant, determined by the format of the data stored.
What does this mean and is it the reason for this exception? I have noticed that in the Visual Studio 3D Starter Kit (http://code.msdn.microsoft.com/wpapps/Visual-Studio-3D-Starter-455a15f1), the buffers have extra floats padding them:
///////////////////////////////////////////////////////////////////////////////////////////
//
// Constant buffer structures
//
// These structs use padding and different data types in places to adhere
// to the shader constant's alignment.
//
struct MaterialConstants
{
MaterialConstants()
{
Ambient = DirectX::XMFLOAT4(0.0f,0.0f,0.0f,1.0f);
Diffuse = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
Specular = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
Emissive = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
SpecularPower = 1.0f;
Padding0 = 0.0f;
Padding1 = 0.0f;
Padding2 = 0.0f;
}
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 Diffuse;
DirectX::XMFLOAT4 Specular;
DirectX::XMFLOAT4 Emissive;
float SpecularPower;
float Padding0;
float Padding1;
float Padding2;
};
struct LightConstants
{
LightConstants()
{
ZeroMemory(this, sizeof(LightConstants));
Ambient = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
}
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 LightColor[4];
DirectX::XMFLOAT4 LightAttenuation[4];
DirectX::XMFLOAT4 LightDirection[4];
DirectX::XMFLOAT4 LightSpecularIntensity[4];
UINT IsPointLight[4*4];
UINT ActiveLights;
float Padding0;
float Padding1;
float Padding2;
};
... // and there's even more where that came from
So am I just not padding these things correctly? And if so, how should I pad them? Or is it something completely different that I'm missing?
I greatly appreciate you reading this and trying to help.