c++ - 为什么常量缓冲区在 Directx 11 中部分更新

标签 c++ winapi directx directx-11

学习“使用 Directx 11 进行 3D 游戏编程简介”。我正在修改示例,以便不使用 Effects Framework,到目前为止一切正常。

但是,我遇到了一个问题,其中一个常量缓冲区仅部分更新。

CPU 端 CB 结构:

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

    DirectX::XMFLOAT4 FogColour;

    float             FogStart;
    float             FogRange;

    int               LightNumber;
    double            Padding;
};

我在绘制任何图纸之前更新 CB。

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 始终设置为 0,即使在应用程序开始时应将其设置为 2。如果我将循环条件更改为硬编码的 1/2/3,着色器将正常工作。

我意识到 CB 中有额外的变量,但示例代码有这个,我相信它会在更多示例中使用。

我认为问题与 CBPerFrame 结构的填充方式有关,因此它没有被正确复制到 GPU。有什么想法吗?

感谢您的帮助。

最佳答案

看来是包装的问题。根据Packing Rules for Constant Variables数据应按 4 字节边界打包,但数据 block 也不会跨越 16 字节边界。在这种情况下,EyePositionW 之后肯定会有一个填充:

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

我也不确定为什么 double gPadding; 最后。它可能应该是另一个 int

关于c++ - 为什么常量缓冲区在 Directx 11 中部分更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47273633/

相关文章:

c++ - 我是在为操作系统或处理器编码吗?

c++ - 为什么 CreateSemaphore 工作时 OpenSemaphore 在 64 位 Windows 7 中总是返回零?

delphi - Delphi应用程序将来会变得更小吗

c# - WindowsFormsHost 中的 WPF、GridSplitter 和 DirectX

c++ - 如何从一个文件中读取数据并将其导入到另一个文件中?

c++ - iPhone : Wrong values when creating struct 的 OpenCV/SURF 跟踪

c++ - 来自 mouse_event 的消息

c++ - 如何确定 DirectInput 中的键盘断开连接

c++ - DirectX 11 CreateSwapChain() 失败并出现错误 DXGI_ERROR_INVALID_CALL

c++ - 在 MFC Direct3D 应用程序中使用 DXUTSetWindow