DirectX 12根常量问题:为何仅scale设置生效?
以下是几个最可能导致该问题的原因及对应排查方法:
1. HLSL与CPU端根常量布局/顺序不匹配
HLSL的根常量cbuffer和C++端的结构体必须严格保持内存布局一致,变量顺序完全对应。比如HLSL中定义:
cbuffer RootConstants : register(b0) { float scale; // 4字节 float2 offset; // 8字节 float4 color; // 16字节 };
C++端结构体必须对齐到相同内存布局,不能随意调整变量顺序:
struct RootConstants { float scale; XMFLOAT2 offset; XMFLOAT4 color; };
若CPU端结构体顺序与HLSL不一致(比如把color放在offset前),GPU读取到的offset和color会是错误的垃圾值,color为0时就会显示黑色。
2. 根签名中声明的根常量数量不足
创建根签名时,D3D12_ROOT_PARAMETER的Constants.Num32BitValues必须等于HLSL根常量的总32位值数量。以上面的例子来说,scale是1个32位值,offset是2个,color是4个,总共7个,所以根参数的常量数量必须设为7:
D3D12_ROOT_PARAMETER rootParam = {}; rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX | D3D12_SHADER_VISIBILITY_PIXEL; rootParam.Constants.ShaderRegister = 0; rootParam.Constants.RegisterSpace = 0; rootParam.Constants.Num32BitValues = 7; // 必须等于总32位常量数
如果这里设为1,GPU只会读取第一个常量(scale),后续的offset和color超出声明范围,无法获取有效值。
3. 设置根常量时的参数错误
调用SetGraphicsRoot32BitConstants时,必须指定正确的常量数量。要传递全部7个常量,代码应为:
cmdList->SetGraphicsRoot32BitConstants( 0, // 根参数索引(对应根签名中该常量的位置) 7, // 要设置的32位常量总数 &rootConstants, // CPU端数据地址 0 // 起始常量索引(从0开始) );
如果第三个参数传1,只会更新scale,offset和color仍为未初始化的默认值(通常是0),导致网格显示黑色。
4. HLSL寄存器绑定与根签名不匹配
确保HLSL中根常量的register(bX)和根签名中Constants.ShaderRegister的值一致。比如HLSL写register(b0),根签名里的ShaderRegister必须设为0,否则GPU无法正确映射到该根常量缓冲区。
5. 颜色变量的赋值范围错误
HLSL中颜色值通常使用01的float范围,如果CPU端赋值时用了0255的整数(比如直接把255赋值给color.x),会导致颜色值远超有效范围,被GPU clamp后可能变成0(黑色)。正确赋值示例:
rootConstants.color = XMFLOAT4(1.0f, 0.5f, 0.0f, 1.0f); // 红橙色,alpha=1
内容的提问来源于stack exchange,提问作者SRahmani

