我正在尝试在 Vulkan 上掌握光线追踪,主要信息来源是本教程。我想出了如何构建 BLAS 和 TLAS,创建了一个 SBT 表,最后开始跟踪场景:

我正要继续简单照明的实现,然后出现了一个问题,我在教程中找不到答案..
如何获取顶点属性?
最让我困惑的是:
- 在我最初为光栅器制作的渲染器中,场景由一组网格描述,其中每个网格都有自己的顶点和索引缓冲区。
- 在光线追踪的情况下,这些缓冲区用作 BLAS(低级加速结构)的基础,但 BLAS 仅包含位置,并且无法访问 BLAS 中的属性。
- 有一个 TLAS(顶级加速结构),它基本上设置了光线追踪的场景。有一个实例这样的概念,它已经引用了 BLAS(也就是说,场景可以由许多不同的缓冲区来描述,而不仅仅是一个,正如它已经暗示的那样)
- 有了这一切,关于单个实例的顶点属性什么都没有说,并且着色器在相交期间可以获得的最大值是重心坐标和一些
gl_PrimitiveID(据我了解,存储三角形的索引),以及作为gl_InstanceID(据我了解,TLAS 中的 instance'a 索引)
所有这些都引出了以下问题:
- 这一切是否意味着我需要将几何图形重新加载到某种 SSBO 中才能访问顶点属性。
- 如果是这样,那么如果我的场景是由不同的顶点缓冲区描述的,而不是一个大的,在这种情况下我该怎么办?事实证明,您需要创建某种将存储在 SSBO 中的二维数组,其键将是实例 ID?
- 如果是这样,并且如果制作了这样的数组,是否意味着除了顶点本身之外还需要存储变换,以便获得属性的实际值(例如,法线)?
我上面提到的教程显示了以下着色器代码:
layout(binding = 2, set = 1, scalar) buffer ScnDesc { sceneDesc i[]; } scnDesc;
layout(binding = 5, set = 1, scalar) buffer Vertices { Vertex v[]; } vertices[];
layout(binding = 6, set = 1) buffer Indices { uint i[]; } indices[];
// Object of this instance
uint objId = scnDesc.i[gl_InstanceID].objId;
// Indices of the triangle
ivec3 ind = ivec3(indices[nonuniformEXT(objId)].i[3 * gl_PrimitiveID + 0], //
indices[nonuniformEXT(objId)].i[3 * gl_PrimitiveID + 1], //
indices[nonuniformEXT(objId)].i[3 * gl_PrimitiveID + 2]); //
// Vertex of the triangle
Vertex v0 = vertices[nonuniformEXT(objId)].v[ind.x];
Vertex v1 = vertices[nonuniformEXT(objId)].v[ind.y];
Vertex v2 = vertices[nonuniformEXT(objId)].v[ind.z];
但我不太明白这里发生了什么。什么是 nonuniformEXT,为什么会这样?还有一个顶点数组和一个索引数组作为描述符......一个一维数组......好像它包含场景的所有几何形状。
总的来说,我对此完全感到困惑,如果有人能阐明这一切,我将不胜感激。
于是,一切都尘埃落定。
确实没有办法从 BLAS 中提取顶点属性,但这并不意味着不能重用几何缓冲区(用于 BLAS)来提取这些相同的属性。
在以下代码中突出显示
是这些不是一维数组。这些是描述符数组。也就是说,这样一个数组的每个元素对应一个缓冲区。
您可以将多个缓冲区绑定为 SSBO 并访问它们。gl_InstanceID 可以用作这样的描述符数组的键。
因此,例如,如果我们在舞台上显示 5 个对象,每个对象都有一个指向其自己的几何缓冲区(顶点和索引缓冲区)的链接 - 您可以简单地将 5 个描述符绑定为数组元素。
gl_PrimitiveID 是射线相交的三角形的索引,可用于获取所需的索引。并在提取的索引的帮助下,访问所需的顶点。
如何准备这个描述符数组?
确保设备扩展已连接
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME并且VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME我们确保启用了必要的物理功能。创建逻辑设备时的设备:
在创建描述符池时,我们指定描述符的类型 - eStorageBuffer 和数量,该数量应等于场景中单个对象(网格)的最大数量。
不要忘记描述符集布局
在循环中更新(绑定)描述符和特定缓冲区(我们遍历场景的所有当前元素并将它们的索引、顶点和 UBO 缓冲区与必要的描述符连接)
我们确保所有用作此类 SSBO 的缓冲区都有一个使用标志
vk::BufferUsageFlagBits::eStorageBuffer因此,着色器将可以访问所有必要的数据,并且可以使用重心坐标插入必要的顶点属性。
也有这样一个时刻,验证层可以发誓调用没有更新的描述符。这一切都是因为在创建描述符集布局时,指定了描述符的最大数量,而不是实际使用的描述符。如果您指定将在那里使用的数量,那么一切都会好起来的。其实这个层警告可以忽略(或者创建一个描述符集布局,描述符个数对应场景元素个数)
也许这对某人有用。