2017-11-13 22 views
0

"Directx 11에서 3D 게임 프로그래밍 소개"를 진행하십시오. Effects Framework을 사용하지 않도록 샘플을 다시 작성합니다. 지금까지는 모두 훌륭했습니다.Direct11에서 부분 버퍼 업데이트가 부분적으로 발생합니다

그러나 상수 버퍼 중 하나가 부분적으로 만 업데이트된다는 문제가 있습니다.

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