通过"使用Directx 11"进行3D游戏编程简介。我正在重新处理样本以便不使用效果框架,到目前为止一切都很好。
但是,我提出了一个问题,其中一个常量缓冲区仅部分更新。
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 );
Pixel Shader:
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。有什么想法吗?
感谢您的帮助。
答案 0 :(得分:2)
这似乎是包装的问题。根据{{3}},数据应以4字节边界打包,但数据块也不能跨越16字节边界。在这种情况下,EyePositionW
之后肯定会有填充:
struct CBPerFrame
{
DirectionalLight DirLight[3];
DirectX::XMFLOAT3 EyePositionW;
float padding1;
DirectX::XMFLOAT4 FogColour;
此外,我不确定为什么最后有double gPadding;
。它可能应该是另一个int
。