5

ライトの情報を格納する 2 番目の定数バッファーを作成しようとするとスローされる 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
        )
        );

この時点で、ライトの CreateBuffer 呼び出しに渡されるパラメーターは、マトリックスと同じ状態にあるように見えます! この問題は、バッファ記述に格納されているバイト数に関係しているようです。

バッファは、モジュールで次のように定義されています。

// 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;
};

頂点シェーダー (.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;
}

これの原因を突き止めようとして、MSDN HLSL シェーダーのドキュメント ( 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

だから私はこれらのものを正しくパディングしていないのですか?もしそうなら、どうやってパディングすればいいですか?それとも、私が見逃しているのはまったく別のものですか?

これをお読みいただき、お役に立てていただければ幸いです。

4

1 に答える 1

8

重要な情報が不足しているため問題を解決するのは難しいですが、試してみましょう。

明らかに、「E_INVALIDARG」は、無効な引数が関数に渡されたことを示しています。ここで、どのパラメータが間違っているかを突き止めなければなりません。 ID3D11Device::CreateBufferメソッドは、D3D11_BUFFER_DESC、D3D11_SUBRESOURCE_DATA、および ID3D11Buffer ** 自体の 3 つパラメーター受け入れます

そして、&constantLightBufferDescnullptr&m_constantLightBufferにフィードします。ここで、MSDN の 4 つの記事すべてを注意深く読んで、何が問題なのかを確認する必要があります。

  1. constantLightBufferこれは問題ではありません。ID3D11Buffer ポインター型であることを確認してください。
  2. nullptr問題になる可能性は低いですが、知る限りこれは C++ 標準のキーワードではないため、ここでは単純な '0' の方がよいでしょう。 実はC++11以降の標準です
  3. 残念ながらconstantLightBufferDesc、問題になる可能性のある定義を提供していません。バッファの配置ミスがある可能性があると述べたように、constantLightBufferDesc.BindFlagsフラグD3D11_BIND_CONSTANT_BUFFERconstantLightBufferDesc.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 ERROR #66: CREATEBUFFER_INVALIDDIMENSIONS]

そのため、不適切なバッファ サイズが原因で失敗した場合CreateBuffer()は、これを処理する方法がいくつかあります。

  1. 構造のサイズを変更します。パディング メンバーを追加して、合計sizeof()が 16 の倍数になるようにします。
  2. 構造体を 16 ビット アラインとして宣言します。私の知る限り、これを行うにはコンパイラ固有の方法しかありません。たとえば#pragma pack、msvc の場合です。
  3. ByteWidth実際の構造サイズではなく、次の 16 の倍数に切り上げて割り当てます:リンク

ハッピーデバッグ!=)

于 2013-06-12T13:48:17.447 に答える