Vulkan中的实例化GLSL着色器?

Mue*_*ito 5 glsl vulkan spir-v

这是我能想出的(最简单的)实例化着色器,它基本上只是转换了一堆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)]);

}
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用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.
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*las 15

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

特别是,此扩展删除 gl_InstanceID(和gl_VertexID).相反,它创建自己的变量,gl_InstanceIndex.原因是因为OpenGL是......愚蠢的.

请参阅实例绘制命令中gl_InstanceID从第一个实例开始的实例.但是,添加基础实例化渲染(呈现任意范围的实例的能力)时,gl_InstanceID未更新以匹配.因此,如果你从2与5的实例的基本实例启动时,第一gl_InstanceID意愿值仍然是零(随后用1,2,3和4).因此,基本实例唯一影响的是实例化数组.

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

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

  • @MuertoExcobito:也许它被你的“#version 400”声明混淆了。他们确实应该有自己的版本号:“#version 100 vulkan”,就像 GLSL ES 具有“#version 300 es”一样。 (2认同)