84

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

glBindAttribLocation()在链接之前明确定义一个属性位置。

或者

glGetAttribLocation()链接后获取一个自动分配的属性位置。

使用其中一个的实用程序是什么?

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

4

3 回答 3

94

我知道一个很好的理由更喜欢明确的位置定义。

考虑将几何数据保存在Vertex Array Objects 中。对于给定的对象,您以索引对应的方式创建 VAO,例如:

  • 索引 0:位置,
  • 索引 1:法线,
  • 索引 2:texcoords

现在考虑您想用两个不同的着色器绘制一个对象。一个着色器需要位置和法线数据作为输入,另一个需要位置和纹理坐标

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

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

自动分配

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

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

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

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


顺便提一句:

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

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

layout(location=0) in vec4 position;

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

于 2011-01-09T11:34:21.577 回答
21

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

于 2013-02-19T21:04:44.437 回答
9

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

于 2014-06-30T07:40:42.497 回答