Nic*_*ico 5 c++ directx graphics hlsl windows-phone-8
我正在研究当我尝试创建存储灯光信息的第二个常量缓冲区时引发的E_INVALIDARG异常:
// 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
)
);
Run Code Online (Sandbox Code Playgroud)
此时,传递给Light的CreateBuffer调用的参数似乎与Matrix的状态相同!问题似乎与缓冲区描述中存储的字节数有关.
缓冲区在模块中定义如下:
// 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;
};
Run Code Online (Sandbox Code Playgroud)
就像在顶点着色器(.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;
}
Run Code Online (Sandbox Code Playgroud)
为了弄清楚导致这种情况的原因,我在MSDN HLSL Shader文档中偶然发现了这一行(http://msdn.microsoft.com/en-us/library/windows/desktop/ff476898(v=vs. 85).aspx):
每个元素存储1到4的组件常量,由存储的数据格式决定.
这是什么意思,是这个例外的原因吗?我注意到在Visual Studio 3D入门套件(http://code.msdn.microsoft.com/wpapps/Visual-Studio-3D-Starter-455a15f1)中,缓冲区有额外的浮点数填充它们:
///////////////////////////////////////////////////////////////////////////////////////////
//
// 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
Run Code Online (Sandbox Code Playgroud)
所以我只是没有正确填充这些东西?如果是这样,我应该如何填充它们?还是我错过了一些完全不同的东西?
我非常感谢您阅读本文并尝试提供帮助.
由于缺乏重要信息,很难解决您的问题,但让我们试一试.
显然,'E_INVALIDARG'表示无效参数传递给函数.现在我们必须弄清楚哪个参数是错误的. ID3D11Device :: CreateBuffer方法接受3个参数:D3D11_BUFFER_DESC ,D3D11_SUBRESOURCE_DATA和ID3D11Buffer**本身.
你可以喂到它与constantLightBufferDesc,nullptr,与m_constantLightBuffer.现在你必须仔细阅读所有4篇MSDN文章,找出问题所在.
constantLightBuffer 这不是问题,只需检查它是否具有ID3D11Buffer指针类型.nullptr它不太可能是一个问题,constantLightBufferDesc定义,这是一个问题的候选者:正如你所说的,可能存在缓冲区对齐错误:如果你constantLightBufferDesc.BindFlags有D3D11_BIND_CONSTANT_BUFFER标志并且constantLightBufferDesc.ByteWidth 不是16的倍数,则缓冲区创建失败.但这只是猜测.你可以在这里遇到任何其他的不匹配,所以,你可以在网上猜测.幸运的是,还有另一种诊断方法:如果使用D3D11_CREATE_DEVICE_DEBUG标志创建ID3D11Device,则在Visual Studio输出窗口中,您将看到根据D3D11的所有警告和错误.例如,如果未对齐,您将看到:
D3D11错误:ID3D11Device :: CreateBuffer:维度无效.对于使用D3D11_BIND_CONSTANT_BUFFER BindFlag标记的ConstantBuffers,ByteWidth(值= 10)必须是16的倍数.当前驱动程序上的ByteWidth也必须小于或等于65536.[STATE_CREATION错误#66:CREATEBUFFER_INVALIDDIMENSIONS]
因此,如果CreateBuffer()由于错误的缓冲区大小而失败,有几种方法可以处理:
sizeof()达到16的倍数.#pragma pack对于msvc.ByteWidth不是真正的结构大小,但向上舍入到16的下一个倍数:链接快乐的调试!=)