OpenGL着色器的显式与自动属性位置绑定

Jin*_*ing 77 shader opengl-es opengl-es-2.0

为OpenGL着色器程序设置属性位置时,您将面临两个选项:

链接之前的glBindAttribLocation()以显式定义属性位置.

要么

链接后的glGetAttribLocation()以获取自动分配的属性位置.

使用一个而不是另一个有什么用?

在实践中哪一个(如果有的话)更受欢迎?

Kos*_*Kos 90

我知道选择明确的位置定义的一个很好的理由.

考虑在顶点数组对象中保存几何数据.对于给定对象,您可以以索引对应的方式创建VAO,例如:

  • 指数0:头寸,
  • 指数1:法线,
  • 指数2:texcoords

现在考虑要使用两个不同的着色器绘制一个对象.一个着色器需要位置和正常数据作为输入,另一个 - 位置和纹理坐标.

如果编译这些着色器,您会注意到第一个着色器将预期属性索引0处的位置和法线处的位置1.另一个将期望位置为0但纹理坐标为1.

引用https://www.opengl.org/wiki/Vertex_Shader:

自动分配

如果前两个方法都没有为属性索引分配输入,则在链接程序时由OpenGL自动分配索引.分配的索引是完全任意的,对于链接的不同程序可能不同,即使它们使用完全相同的顶点着色器代码.

这意味着您将无法在两个着色器中使用VAO.而不是每个对象都有一个VAO,在最坏的情况下,每个着色器每个对象需要一个单独的VAO.

强制着色器使用您自己的属性编号约定glBindAttribLocation可以轻松解决此问题 - 您需要做的就是保持属性与其建立的ID之间的一致关系,并强制着色器在链接时使用该约定.

(如果你不使用单独的VAO,这不是一个大问题,但仍然可能使你的代码更清晰.)


BTW:

为OpenGL着色器程序设置属性位置时,您将面临两个选项

OpenGL/GLSL 3.3中有第三个选项:直接在着色器代码中指定位置.它看起来像这样:

layout(location=0) in vec4 position;
Run Code Online (Sandbox Code Playgroud)

但这在GLSL ES着色器语言中不存在.

  • *"VAO非常轻巧,你通常会为每一帧重新创建它们.在你的情况下,你只需要在调用每个着色器之前创建不同的VAO,不是吗?"* - 不,你通常不会这样做因为这最终完全使VAO的目的无效.那么为什么要使用VAO呢? (34认同)
  • 第三个选项实际上在GLES2.0中可用,但格式略有不同:layout(location = 0)属性vec4位置; 请注意,您还需要在GLSL文件的顶部:#extension GL_EXT_separate_shader_objects:enable (4认同)
  • 请注意。您不会将几何数据保存在VAO中。那将在VBO中。VAO没有数据存储。 (2认同)

Lit*_*rum 18

这里的另一个答案是glGetAttribLocation将数据返回给调用者,这意味着它隐式地需要管道刷新.如果在编译程序后立即调用它,则实质上是强制异步编译同步进行.


lan*_*ane 9

第三个选项,即layout(location=0) in vec4 position;着色器代码,现在可在OpenGL ES 3.0/GLSL 300 es中使用.仅适用于顶点着色器输入变量.

  • 正如他们所暗示的那样,英特尔卡可能不支持这种情况(完全不超过3.0+,因为我得到它),这是令人厌恶的:) (7认同)