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

光线追踪相交着色器读取SSBO始终为零的问题排查

问题:光线追踪命中着色器无法正确读取SSBO数据

我的相交着色器从SSBO中读取的值始终为0。尝试使用debugPrintEXT,但无法在相交着色器内输出内容。通过ray payload输出命中颜色时,得到的始终是纯黑色。起初以为是数据复制方式有问题,但对比NVIDIA示例代码,实现并无问题。验证层也没有抛出任何警告或错误。用NVIDIA NSight Graphics查看缓冲区,里面的数据和复制的完全一致,布局符合预期。检查SPIRV指令,所有指令都正确指向缓冲区的偏移量——NSight能看到正确的值,但着色器就是读不到!

着色器代码

// Hitting a triangle.
#version 460 core
#extension GL_EXT_ray_tracing : enable

layout(location = 0) rayPayloadInEXT vec4 payload;
hitAttributeEXT vec2 attributes;
layout(push_constant) uniform rayParams {
  vec3 rayOrigin;
  vec3 rayDir;
  mat4 transformMatrix;
  float maxDistance;
};
struct PhongMaterial {
  float ambient;
  float diffuse;
  float specular;
  float shininess;
  float reflective;
  float transparency;
  float refraction;
  vec4 color;
  float reserved_1;
  vec4 reserved_2;
};

layout(set = 0, binding = 2) readonly buffer Materials {
  PhongMaterial m[];
}
materials;

void main() {
  PhongMaterial material = materials.m[0];
  payload = material.color;
}

Rust结构体布局

#[repr(C)]
pub struct PhongMaterial {
    pub ambient: f32,
    pub diffuse: f32,
    pub specular: f32,
    pub shininess: f32,
    pub reflective: f32,
    pub transparency: f32,
    pub refraction: f32,
    pub color: ColorRGBA,
    reserved: [u8; 20],
}

该结构体总字节大小为44字节,从临时CPU缓冲区复制到GPU缓冲区时会对齐到16的倍数,即复制48字节的数据。

NSight截图显示缓冲区数据与Rust中设置的完全一致,布局符合预期。

SPIRV代码片段

OpName %58 "PhongMaterial"
OpMemberDecorate %58 0 Offset 0
OpMemberDecorate %58 1 Offset 4
OpMemberDecorate %58 2 Offset 8
OpMemberDecorate %58 3 Offset 12
OpMemberDecorate %58 4 Offset 16
OpMemberDecorate %58 5 Offset 20
OpMemberDecorate %58 6 Offset 24
OpMemberDecorate %58 7 Offset 32
OpMemberDecorate %58 8 Offset 48
OpMemberDecorate %58 9 Offset 64

尝试调整填充、内存对齐都没有效果,即便存在对齐问题,至少前几个值的布局是正确的,着色器应该能读取到才对。


更新:最近命中着色器读取缓冲区完全异常

测试代码:

void main() {
  PhongMaterial material = materials.m[0];
  if (material.ambient <= 0.1) {
    payload = vec4(1.0, 0.0, 0.0, 1.0);
  } else if (material.ambient <= 0.5) {
    payload = vec4(0.0, 1.0, 0.0, 1.0);
  } else {
    payload = vec4(0.0, 0.0, 1.0, 1.0);
  }
}

所有分支都没有执行,payload完全未被设置,因此显示纯黑色。但如果不尝试访问material缓冲区,或者在if-else之后强行赋值payload,设置的颜色就能正常显示:

if (material.ambient <= 0.1) {
    payload = vec4(1.0, 0.0, 0.0, 1.0);
  } else if (material.ambient <= 0.5) {
    payload = vec4(0.0, 1.0, 0.0, 1.0);
  } else {
    payload = vec4(0.0, 0.0, 1.0, 1.0);
  }
  payload = vec4(1.0, 1.0, 0.0, 1.0);

除此之外,如果在分支前先设置颜色,颜色又会变成黑色,仿佛payload没有被设置:

payload = vec4(1.0, 1.0, 0.0, 1.0);
  if (material.ambient <= 0.1) {
    payload = vec4(1.0, 0.0, 0.0, 1.0);
  } else if (material.ambient <= 0.5) {
    payload = vec4(0.0, 1.0, 0.0, 1.0);
  } else {
    payload = vec4(0.0, 0.0, 1.0, 1.0);
  }

如果只保留一个if语句并检查任意数值,它总是被判定为true。这是不是未定义行为(UB)?

另一张NSight截图显示缓冲区布局正确,且已正确绑定到命中着色器。

现在猜测是命中着色器的着色器绑定表(Shader Binding Table)设置不正确,但无法理解为什么着色器还能被调用。


致投票关闭此问题的人:
对于任何了解Vulkan、Rust和GLSL的人来说,复现步骤都很明确:使用所需类型的GPU缓冲区即可。NSight已证明这部分操作正确,因此无需提供最小可复现示例(MCVE)。唯一无法正常工作的是着色器,其代码已作为MCVE。预期行为很明显——着色器应读取缓冲区中的实际数据而非始终为0。如有疑问,请提问,除非你确定问题不符合要求,否则不要投票关闭。即便你确定,也请告知作者,不要默默投票。只要提问,我会提供任何所需信息,而且我已经提供了所有必要的信息。

内容的提问来源于stack exchange,提问作者VP.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:11:31