GLSL-使用统一缓冲区对象的顶点着色器和批处理

时间:2019-04-29 18:04:01

标签: opengl glsl

我有以下顶点着色器:

#version 450 core
...
layout (binding=2, std140) uniform MATRIX_BLOCK
{
   mat4 projection;
   mat4 view;
   mat4 model[128];
   mat4 mvp[128];
};

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 3) in uint object_idx;

out vec2 TexCoord;
flat out uint instance_idx;

void main()
{  
  gl_Position = mvp[object_idx] * vec4(aPos.x, aPos.y, aPos.z, 1.0);  
  TexCoord = aTexCoord;
  instance_idx = object_idx;
}

我正在使用统一缓冲区传递128个模型和模型-视图-投影矩阵,这些矩阵由对象ID索引。使用顶点属性object_idx将对象ID传递给着色器。基本上,每个顶点除了具有x,y,z坐标和u,v纹理坐标外,还具有与之关联的对象ID。这样的想法是能够将多个对象的数据存储在同一缓冲区中,但仍为每个单独的对象使用特定的转换矩阵。这是我的(可能是愚蠢的)尝试,使用glDrawElements渲染三角形,将多个对象批处理在一起以通过一次绘制调用将其绘制,而不必重新绑定任何对象。

但是,它不起作用。当我这样做

gl_Position = mvp[object_idx] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

然后将object_idx为0的三角形在预期位置处渲染得很好,但是object_idx值为0以外的顶点的三角形不会出现在任何位置。我以为我可能弄错了转换矩阵,所以为了进行调试,我将可能的对象减少到了2个(0和1),并使用

反转了索引。
gl_Position = mvp[1-object_idx] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

这将导致在object_idx = 1的所有三角形处渲染mvp [1]的预期位置,但是同样,在任何位置都不会出现object_idx = 1的三​​角形。所以至少我知道变换矩阵是正确的。然后我尝试了

gl_Position = mvp[0] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

,并渲染所有三角形(使用对象0的转换矩阵)和

gl_Position = mvp[1] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

使用对象1的转换矩阵提供全部

因此,显然我不了解关于顶点着色器或glDrawElement如何工作的真正基础。

所以,我的问题:

为什么当我使用object_idx对mvp转换矩阵进行“动态”查找时,为什么我的所有三角形都无法渲染,而尽我所能检查所有数据就如同将其传递到顶点着色器中一样应该是?

1 个答案:

答案 0 :(得分:2)

我在这里进行有根据的猜测:

layout (location = 3) in uint object_idx;

使用uint属性输入需要使用函数glVertexAttribIPointer()设置属性指针(请注意其中的附加 I )。

使用标准的glVertexAttribPointer函数将始终设置float属性(使用类型GL_INT将从整数转换为float)。从技术上讲,当您在着色器中读取诸如uint之类的float属性时,它将是未定义的,但是很有可能0保持0,因为该float和integer表示为通常相同,但这只是偶然而已。

除此问题外,每个顶点存储对象索引的效率也很低。为了有效地批处理绘图调用,您应该查看multi draw callsgl_DrawID(最初来自GL_ARB_shader_draw_parameters)功能。您可能还会发现approaching zero driver overhead (AZDO) techniques有用。