2017-11-13 19 views
0

「Directx 11での3Dゲームプログラミング入門」で作業しています。エフェクトフレームワークを使用しないようにサンプルを修正しています。定数バッファが部分的にDirect11で更新されるのはなぜですか?

しかし、定数バッファの1つが部分的にしか更新されないという問題がありました。

CPU側CB構造体:私は前の任意の図面にCBを更新

struct CBPerFrame 
{ 
    DirectionalLight DirLight[3]; 
    DirectX::XMFLOAT3 EyePositionW; 

    DirectX::XMFLOAT4 FogColour; 

    float    FogStart; 
    float    FogRange; 

    int    LightNumber; 
    double   Padding; 
}; 

CBPerFrame cbPerFrame { }; 

    cbPerFrame.DirLight[ 0 ] = mDirectionalLights[ 0 ]; 
    cbPerFrame.DirLight[ 1 ] = mDirectionalLights[ 1 ]; 
    cbPerFrame.DirLight[ 2 ] = mDirectionalLights[ 2 ]; 

    cbPerFrame.EyePositionW = mEyePosW; 

    cbPerFrame.FogColour  = XMFLOAT4(Colors::Black); 
    cbPerFrame.FogRange  = 1.0F; 
    cbPerFrame.FogStart  = 0.0F; 

    cbPerFrame.LightNumber = mLightCount; 

    cbPerFrame.Padding  = 0.0; 

mD3DImmediateContext->UpdateSubresource(mCBPerFrame.Get(), 0, nullptr, &cbPerFrame, 0, 0); 

ピクセルシェーダ:

cbuffer CBPerFrame : register(b0) 
{ 
    DirectionalLight gDirectionalLights[ 3 ]; 
    float3   gEyePosW; 

    float4   gFogColor; 
    float   gFogStart; 
    float   gFogRange; 

    int    gLightCount; 
    double   gPadding; 
} 

cbuffer CBPerObject : register(b1) 
{ 
    matrix gWorld; 
    matrix gWorldInverseTranspose; 
    matrix gWorldViewProjection; 
    float4x4 gTextureTransform; 
    Material gMaterial; 
} 

float4 main(VertexOut input) : SV_TARGET 
{ 
    // Interpolating normal can unnormalize it, so normalize it. 
    input.NormalW = normalize(input.NormalW); 

    // The toEye vector is used in lighting. 
    float3 toEye = normalize(gEyePosW - input.PositionW); 

    // Cache the distance to the eye from this surface point. 
    float distToEye = length(toEye); 

    // Normalize. 
    toEye /= distToEye; 

    // 
    // Lighting. 
    // 

    // Start with a sum of zero. 
    float4 ambient = float4(0.0F, 0.0F, 0.0F, 0.0F); 
    float4 diffuse = float4(0.0F, 0.0F, 0.0F, 0.0F); 
    float4 spec = float4(0.0F, 0.0F, 0.0F, 0.0F); 

    // Sum the light contribution from each light source. 
    /* [unroll]*/ 
    for (int i = 0; i < gLightCount; i++) 
    { 
     float4 A, D, S; 

     ComputeDirectionalLight(gMaterial, gDirectionalLights[ i ], input.NormalW, toEye, A, D, S); 

     ambient += A; 
     diffuse += D; 
     spec += S; 
    } 

    float4 litColour = ambient + diffuse + spec; 

    // Common to take alpha from diffuse material. 
    litColour.a = gMaterial.Diffuse.a; 

    return litColour; 
} 

はgLightCountは常にそれがアプリケーションの開始時に2に設定する必要があっても、0に設定されています。ループの条件をハードコードされた1/2/3に変更すると、シェイダーは正常に機能します。

私は、CBに余分な変数があることを認識していますが、サンプルコードにこれがあり、さらなる例で使用されていると思います。

私は、CBPerFrame構造体がどのように埋め込まれているかに問題があると思うので、GPUに正しくコピーされていません。何かご意見は?

ありがとうございました。

答えて

2

梱包に問題があるようです。 Packing Rules for Constant Variablesによれば、データは4バイト境界でパックされるべきであるが、データブロックは16バイト境界を越えないようにする必要がある。この場合、EyePositionW後に間違いなくパディングがあるだろう。最後にdouble gPadding;がある理由

struct CBPerFrame 
{ 
    DirectionalLight DirLight[3]; 
    DirectX::XMFLOAT3 EyePositionW; 
    float    padding1; 
    DirectX::XMFLOAT4 FogColour; 

はまた、私はよく分かりません。おそらく別の intであるはずです。

+0

ありがとうございましたCB構造体は16バイトの倍数でなければならないが、16バイト境界で整列する必要があることは知らなかった。 – Compton

関連する問題