我的交叉点着色器总是只从我拥有的SSBO中读取零. 我try 使用debugPrintEXT,但无法从交叉点着色器中打印出来.然而,当我试图通过光线有效载荷输出任何值作为命中 colored颜色 时,我得到的总是黑色.最初,我认为我复制数据的方式有问题,但事实并非如此,它与示例代码一样好,它可以工作(来自NVIDIA).然后,验证层不抛出警告/错误/不抛出任何内容.然后我判断了NVIDIA NSight显卡的缓冲区,其中有我复制到其中的数据,完全符合我想要的布局.然后我判断了SPIRV指令,它们都正确地引用了缓冲区的偏移量!我现在完全迷路了:即使是NVIDIA 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 的 struct 布局:

#[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],
}

The total byte size of the struct is 44 bytes. Aligning to a multiple of 16 results in 48 bytes copy when moving the data from the temporary CPU buffer to the GPU buffer. Here is the screenshot of NVIDIA NSight, which proves the shader must have the data: NSight screenshot Here in the screenshot of NSight, the values are exactly the ones I have in Rust. And here is the shader's 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);
  }

在这里,这两个分支部分都没有走进go !"有效载荷"没有完全设定,所以我看到的 colored颜色 是一片漆黑.但是,如果我不try 访问"Material"缓冲区并从中读取值,或者只是在这些if-else之后为"有效负载"赋值,则我分配的 colored颜色 是可见的:

  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);

除此之外,如果我首先设置 colored颜色 ,在分支之前, colored颜色 又是黑色的,就好像没有设置有效载荷一样!

  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?

Another screenshot from the NSight showing that the buffer is correctly laid out, bound to the hit shader correctly as well: enter image description here

我目前的猜测是,着色器绑定表没有为命中着色器正确设置.但我不明白为什么当时甚至会援引它.

致决定投票支持结案的人: 每个知道Vulkan、Rust和GLSL的人都必须清楚复制步骤:使用所需类型的GPU缓冲区.NSight证明它是正确的,所以MCVE的这一点是不必要的.唯一不能正常工作的是着色器,它的代码用作MCVE.所需的行为是显而易见的-数据应该按其在缓冲区中的原样被读取,而不是始终为零.如果你有任何问题--问,除非你清楚,否则不要投票支持结案.即使你很确定,也要通知作者,而不是默默投票.如果被要求,人们可以提供任何类型的信息,但我已经提供了所有必要的信息.

推荐答案

我解决了这个问题.实际上有两个问题.一个是对齐问题-正如@Nicol Bolas指出的那样, colored颜色 向量实际上应该位于距离块开始32个字节的偏移量处.然而,这是一个相当小的问题.一个更大的问题是着色器绑定表.正如你在问题中的最后一个屏幕截图上看到的,没有命中着色器分配给着色器绑定表.这是一个巨大的调试问题,因为所有数据都被正确复制到我的代码中,问题不是如何将数据复制到SBT缓冲区,而是如何创建着色器组.在《光线跟踪Ruby II》一书中说,我们为其创建着色器组的着色器的顺序并不重要.好吧,在我的机器上,这是错误的.首先,正如NVIDIA Night所示,我没有附加命中着色器.其次,我的未命中着色器在组"2"中的索引为"1",与索引和组的顺序始终相同的其他应用程序相比,这肯定是奇怪的:

  • 光线生成明暗器组.
  • 未命中明暗器组.
  • 点击明暗器组.

在书中读到顺序并不重要后,我更改了我创建的着色器组的顺序:第二个是命中着色器组,而不是像其他任何地方一样的未命中着色器组.

作为一名Vulkan光线跟踪学习者,我应该指出,《光线跟踪Ruby II》(第251页)中的这句话可能会被误解:

...首先,对于SBT中的着色器类型没有顺序要求;光线生成、命中和未命中组可以以任何顺序出现.

我解释了它,所以我们也不关心如何创建着色器组.着色器组的着色器记录似乎总是按光线生成、未命中和命中组的顺序排列,当我们为光线跟踪管道创建组本身时,顺序很重要.

对于在使用光线跟踪管道和着色器绑定表时具有相同着色器奇怪行为的人,有一条建议:如果着色器行为奇怪(产生奇怪行为),即使它被调用,或者当您try 访问除在着色器阶段之间传递的数据之外的任何数据时,很可能是着色器绑定表存在问题.在同一本书(光线追踪Ruby II)中,有人指出,创建/使用SBT及其数据经常是错误的,是问题的常见原因.

Rust相关问答推荐

如何访问Rust存储值的内存地址

使用pyo3::Types::PyIterator的无限内存使用量

使用Py03从Rust调用Python函数时的最佳返回类型

正则表达式中的重叠匹配?(铁 rust 正则式发动机)

我可以在不收集或克隆的情况下,将一个带有Item=(key,val)的迭代器拆分成单独的key iter和val iter吗?

如何使用Actix Web for Rust高效地为大文件服务

为什么HashMap::get和HashMap::entry使用不同类型的密钥?

如何获取光标下的像素 colored颜色 ?

如何轮询 Pin>?

为什么我需要 to_string 函数的参考?

我应该如何表达具有生命周期参数的类型的总排序,同时允许与不同生命周期进行比较?

信号量释放后 Rust 输出挂起线程

Rust 中多个 & 符号的内存表示

Rust 如何将链表推到前面?

Rust并发读写引起的死锁问题

如何在 Rust 中显式声明 std::str::Matches<'a, P> ?

为什么 `tokio::join!` 宏不需要 Rust 中的 `await` 关键字?

为什么传递 option.as_ref 的行为不同于使用匹配块并将内部映射到 ref 自己?

我如何将 google_gmail1::Gmail> 传递给线程生成?

有什么办法可以用 Rust 访问 Windows 最近的文件夹吗?