为OpenGL着色器程序设置属性位置时,您将面临两个选项:
在链接之前glBindAttribLocation()以明确定义属性位置。
或
链接后glGetAttribLocation()以获取自动分配的属性位置。
使用其中一个的效用是什么?
在实践中,哪一个(如果有的话)是首选的?
答案 0 :(得分:84)
我知道偏好显式位置定义的一个很好的理由。
考虑在Vertex Array Objects.中保存几何数据对于给定对象,您可以创建一个VAO,使得索引对应于,例如:
现在考虑使用两个不同着色器绘制一个对象。一个着色器需要位置和普通数据作为输入,另一个 - 位置和纹理坐标。
如果您编译这些着色器,您会注意到第一个着色器将预期属性索引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着色器语言中不存在。
答案 1 :(得分:17)
这里的另一个答案是glGetAttribLocation将数据返回给调用者,这意味着它隐式地需要管道刷新。如果在编译程序后立即调用它,那么实质上就是强制异步编译同步进行。
答案 2 :(得分:8)
第三个选项,即着色器代码中的layout(location=0) in vec4 position;
,现在可在OpenGL ES 3.0 / GLSL 300 es中使用。仅适用于顶点着色器输入变量。