8

这是我能想到的(最简单的)实例化着色器,它基本上只是转换了一堆 2D 基元:

#version 400
#extension GL_ARB_draw_instanced : enable
#extension GL_ARB_shading_language_420pack : enable
layout(std140, binding = 0) uniform VConstants {
    vec4 vfuniforms[48];
};
in vec4 pos;
void main() {

    gl_Position = vec4(0.0,0,0.0,1);
    gl_Position.x = dot(pos, vfuniforms[int(float(gl_InstanceID) * 2.0)]);
    gl_Position.y = dot(pos, vfuniforms[int(float(gl_InstanceID) * 2.0 + 1.0)]);

}

如果我尝试使用 Vulkan SDK 附带的 glslangValidator 将其编译为 SPIR-V,我会得到:

WARNING: 0:2: '#extension' : extension not supported: GL_ARB_draw_instanced
ERROR: 0:14: 'gl_InstanceID' : undeclared identifier
ERROR: 1 compilation errors.  No code generated.

如果我删除该#extension GL_ARB_draw_instanced行,我仍然会收到gl_InstanceID错误消息。是否可以编写实例化 GLSL 并将它们编译为 SPIR-V?如果是这样,我做错了什么?

4

2 回答 2

22

参考编译器用于为 Vulkan 生成 SPIR-V 的 GLSL 形式不使用普通的 OpenGL 扩展。它遵循 GLSL 4.50 的规则,但它通过隐式伪扩展GL_KHR_vulkan_glsl的指示修改/覆盖它们。请注意,您不使用#extension 来启动它;假定它处于活动状态,因为您使用的是 Vulkan GLSL-to-SPIR-V 编译器。

特别是,此扩展删除 gl_InstanceID了(and gl_VertexID)。相反,它会创建自己的变量gl_InstanceIndex. 这样做的原因是因为 OpenGL 是……愚蠢的。

看,是从实例化绘图命令gl_InstanceID中的第一个实例开始的实例。但是,当添加了基本实例渲染(渲染任意范围的实例的能力)时,并没有更新以匹配。因此,如果您从 2 和 5 个实例的基本实例开始,第一个仍将为零(随后是 1、2、3 和 4)。因此,基本实例影响的唯一事物是实例化数组gl_InstanceIDgl_InstanceID

自然,Vulkan 不希望 OpenGL 在这方面愚蠢,因此它使用大多数人期望的实例值:用户要求渲染的实际实例索引。但这需要一个新变量,这样用户就不会做你正在尝试的事情:意外地在 OpenGL 和 Vulkan 中使用相同的变量,而没有意识到它们具有不同的语义。

您将需要两个着色器或检查是否VULKAN已定义,这将适用于使用 GL_KHR_vulkan_glsl 扩展的用户。如果是,您使用gl_InstanceIndex; 如果没有,你使用gl_InstanceID. 此外,您的#extension 声明也应该限定范围,因为 Vulkan GLSL-to-SPIR-V 编译器将假定 GLSL 4.50,它不一定提供扩展。

于 2016-02-25T23:12:21.063 回答
3

GL_ARB_draw_instanced 扩展不是必需的,它由核心 GLSL 1.40 和 vulkan 支持。glslang 似乎并没有使用扩展:https://github.com/KhronosGroup/glslang/blob/master/glslang/MachineIndependent/Initialize.cpp#L1707

我认为必须使用 gl_InstanceIndex 而不是 gl_InstanceID。不同之处在于 gl_InstanceID 从 0 开始计数,其中 gl_InstanceIndex 从基本实例开始计数。看

https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#interfaces-builtin-variables

有关内置函数的更多信息。

于 2016-02-25T22:59:51.423 回答