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

Posted

技术标签:

【中文标题】OpenGL着色器的显式与自动属性位置绑定【英文标题】:Explicit vs Automatic attribute location binding for OpenGL shaders 【发布时间】:2011-06-05 20:59:24 【问题描述】:

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

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

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

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

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

【问题讨论】:

我没有费心在我的图形引擎中使用glBindAttribLocation,它在 linux 上运行良好。当我移植到 Windows 时,它使用我的法线作为顶点 - 我必须通过 glBindAttribLocation 明确告诉它我的着色器中变量的顺序才能让它工作...... 【参考方案1】:

我知道一个选择显式位置定义的好理由。

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

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

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

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

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

自动分配

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

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

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

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


顺便说一句:

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

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

layout(location=0) in vec4 position;

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

【讨论】:

我不明白这一点。 VAO 非常轻量级,您通常会为每一帧重新创建它们。在您的情况下,您只需在调用每个着色器之前创建不同的 VAO,不是吗? 是的,您当然可以这样做。它也可以,我们在这里只讨论约定。 :) 第三个选项其实在GLES2.0中也有,只是格式稍有不同:layout(location = 0) attribute vec4 position;请注意,您还需要在 GLSL 文件的顶部使用它:#extension GL_EXT_separate_shader_objects : enable “VAO 非常轻量级,您通常会为每一帧重新创建它们。在您的情况下,您只需在调用每个着色器之前创建不同的 VAO,不是吗?” - 不,您通常不会这样做,因为这最终完全使 VAO 的整个目的无效。那为什么还要使用 VAO? 只是一个注释。您不会将几何数据保存在 VAO 中。那将在VBO中。 VAO 没有数据存储。【参考方案2】:

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

【讨论】:

更多详情:src.chromium.org/svn/trunk/src/gpu/GLES2/extensions/CHROMIUM/… 谢谢,这是一个非常重要的考虑因素。 据我了解,在大多数情况下,无论如何您都必须致电glGetUniformLocation;这个特殊的考虑仍然相关吗? @MikeWeir 自 GL 4.3 起,您可以设置 explicit uniform location。 @Ruslan 他们正在使用 OpenGL ES。【参考方案3】:

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

【讨论】:

正如他们所暗示的那样,英特尔卡可能不支持这一点(虽然完全符合 3.0+ 标准,但据我所知),这很恶心 :)

以上是关于OpenGL着色器的显式与自动属性位置绑定的主要内容,如果未能解决你的问题,请参考以下文章

跨多个着色器的 OpenGL 统一

将属性传递给 OpenGL 顶点着色器的行为很奇怪

顶点着色器的绘制操作

OpenGL ES(一.概念)

OpenGL学习随笔-- 顶点着色器(VertexShader)

openGL:带着色器的线条