示例代码:
1. glGenBuffers(1, &VboId);
2. glBindBuffer(GL_ARRAY_BUFFER, VboId);
3. glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
4. glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
5. glEnableVertexAttribArray(0);
所以第 4 行(第一个参数)和第 5 行的“0”指的是我们选择的任意标识符/位置。在 GLSL 中,如果我们想引用这些数据,我们只需要引用同一个 ID:
layout(location=0) in vec4 in_Position;
但是,在另一个示例程序中,我看到它的做法有所不同,没有提及“布局位置”。相反,我们这样做:
1. glGenBuffers(1, &VboId);
2. glBindBuffer(GL_ARRAY_BUFFER, VboId);
3. glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
4. glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
5. glBindAttribLocation(shaderProgramHandle, 0, "in_position");
6. glEnableVertexAttribArray(0);
我们添加了一个额外的步骤 (5),我们似乎将此属性指针绑定(bind)到特定程序中的特定变量。然后在我们的 GLSL 中,我们只是这样写:
in vec3 in_position;
没有引用位置。
如果我没记错的话,这两个程序本质上做的是完全相同的事情……那为什么会有区别呢?每种方法的优缺点是什么?
(我刚开始学习 OpenGL 3.x)
最佳答案
没有将 VAO 传递给着色器这样的事情。 VAO 只是建立了如何从缓冲区对象中提取顶点属性以进行渲染。
第二个例子什么也不做,除非shaderProgramHandle
尚未链接。 glBindAttribLocation
位置仅在程序链接之前有效。链接程序后,您无法更改它从何处获取属性。
无论如何,你真正的问题是为什么有些人使用 glBindAttribLocation(..., 0)
而不是把 layout(location = X)
在他们的着色器中。原因很简单:layout(location)
语法是(相对)新的。 glBindAttribLocation
可以追溯到 GLSL 的 OpenGL 接口(interface)的第一个版本,可以追溯到 2003 年左右的 ARB_vertex_shader 扩展。 layout(location)
来自更新的 ARB_explicit_attrib_location,它只是 GL 3.3 及更高版本的核心。 3.3是2010年才出来的。所以自然更多的 Material 会讲老路。
每个人的“优点和缺点”都很明显。从纯粹实用的角度来看,layout(location)
是新的,需要更新的驱动程序(尽管它不需要 GL 3.3。NVIDIA 的 6xxx+ 硬件支持 ARB_explicit_attrib_location 尽管只有 2.1)。 glBindAttribLocation
在源代码中工作,而 layout(location)
内置于 GLSL 着色器本身。因此,如果您需要决定哪些属性在运行时使用哪些索引,使用 layout(location)
会更难做到。比没有它。但是,如果像大多数人一样,您想从着色器中控制它们,那么 layout(location)
是你需要的。
关于opengl - 为什么有多种方法可以将 VAO 传递给 GLSL 程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8691697/