这是我能想出的(最简单的)实例化着色器,它基本上只是转换了一堆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?如果是这样,我做错了什么?
答案 0 :(得分:13)
参考编译器用于为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
是从instanced drawing command中的第一个实例开始的实例。但是,当添加了基础实例化渲染(呈现任意范围的实例的能力)时,gl_InstanceID
未更新为匹配。因此,如果您从具有5个实例的2的基本实例开始,则第一个gl_InstanceID
将仍为零(后跟1,2,3和4)。因此,基本实例唯一影响的是instanced arrays。
当然,Vulkan不希望OpenGL在这方面愚蠢,因此它使用了大多数人期望的实例值:用户要求呈现的实际实例索引。但是这需要一个新的变量,这样用户就不会做你正在尝试的事情:在OpenGL和Vulkan中意外地使用相同的变量,却没有意识到它们有不同的语义。
您需要两个着色器或检查是否定义了VULKAN
,这将是那些使用GL_KHR_vulkan_glsl扩展名的人。如果是,则使用gl_InstanceIndex
;如果没有,请使用gl_InstanceID
。此外,您的#extension声明也应该作为范围,因为Vulkan GLSL-to-SPIR-V编译器将假设GLSL 4.50,并且它不一定提供扩展。
答案 1 :(得分:2)
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从基本实例计数。见
了解有关内置组件的更多信息。