You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将数组作为常量缓冲区传递给着色器时数据全为0,如何正确操作?

数组传递到HLSL常量缓冲区的规范与问题排查

必须遵守的核心规范

  • 内存对齐要求:HLSL常量缓冲区所有数据按照16字节(4个float)边界对齐。数组单个元素的大小、整个常量缓冲区的总大小都必须是16字节的整数倍。如果传递自定义结构体,C++侧需要添加__declspec(align(16))修饰结构体,保证内存布局和HLSL侧完全一致。
  • 大小匹配要求:C++侧创建常量缓冲区时指定的字节大小,必须和HLSL中cbuffer定义的总字节大小一致。你示例中96个float4x4的总大小是96 * 64 = 6144字节,符合16字节对齐要求。
  • 插槽匹配要求:C++侧*SSetConstantBuffers的第一个参数(插槽索引)必须和HLSL中cbuffer绑定的register(bN)的N值完全匹配,且要绑定到对应着色器阶段:顶点着色器用VSSetConstantBuffers,像素着色器用PSSetConstantBuffers,不可混用。
  • 数据更新要求:如果需要CPU侧动态更新常量缓冲区,创建时必须指定Usage = D3D11_USAGE_DYNAMIC、CPUAccessFlags = D3D11_CPU_ACCESS_WRITE,否则Map操作会失败,数据无法写入缓冲区。

针对你代码的排查步骤

  1. 确认BoneTransformBuffer创建时的大小是否等于96 * sizeof(XMFLOAT4X4),如果创建时大小不足,填充数据会被截断,未填充区域默认为0。
  2. 检查Animator->GetTransforms(_timeDelta)返回的vector<XMFLOAT4X4>的长度是否等于96,如果返回元素数小于96,仅拷贝现有元素的情况下,数组剩余部分会保留初始0值。
  3. 验证SetData实现逻辑:是否正确调用ID3D11DeviceContext::Map且返回成功,拷贝数据的长度是否为finalTransforms.size() * sizeof(XMFLOAT4X4),是否将整个vector的内存完整拷贝到了映射后的缓冲区内存中。
  4. 确认你没有在后续代码中调用VSSetConstantBuffers(1, 1, &其他缓冲区)覆盖了b1插槽的绑定。
  5. 使用RenderDoc等渲染调试工具抓帧,直接查看绑定到顶点着色器b1插槽的常量缓冲区实际内容:如果缓冲区内部本身全为0,问题出在C++侧的数据填充逻辑;如果缓冲区数据正确,说明是着色器侧访问越界(比如骨骼索引超过95,HLSL越界访问默认返回0)。

补充说明:XMFLOAT4X4是行优先存储,HLSL默认使用列优先矩阵,若后续出现矩阵计算结果错误而非全0的问题,需要在C++侧转置矩阵后再传递,或者在HLSL中声明矩阵时添加row_major修饰。

内容的提问来源于stack exchange,提问作者문형준

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 14:36:00