glVertexAttribPointer澄清


94

只是要确保我正确理解了这一点(我会在SO Chat上询问,但它在那里死了!):

我们有一个顶点数组,通过绑定它使它成为“当前”,
然后我们有一个缓冲区,我们将其绑定到一个目标,
然后填充该目标,通过glBufferData 它实质上填充了绑定到该目标的任何东西,即我们的缓冲区
然后我们调用glVertexAttribPointer,它描述了数据的布局方式-数据绑定了什么GL_ARRAY_BUFFER ,该描述符保存到我们原来的顶点数组中

(1)我的理解正确吗?有关所有内容之间如何关联
文档很少。

(2)是否存在某种默认的顶点数组?因为我忘记/忽略了glGenVertexArraysglBindVertexArray如果没有它,我的程序可以正常工作。


编辑:我错过了一步glEnableVertexAttribArray

(3)是否同时glVertexAttribPointer调用了与顶点数组绑定的顶点属性,然后我们可以随时启用/禁用该attrib glEnableVertexAttribArray,而不管当前绑定了哪个顶点数组?

或(3b)是否glEnableVertexAttribArray同时调用glEnableVertexAttribArray了与顶点数组绑定的顶点属性,因此当绑定了不同的顶点数组时,我们可以通过在不同的时间调用将相同的顶点属性添加到多个顶点数组中?

Answers:


210

一些术语有些偏离:

  • A Vertex Array只是一个float[]包含顶点数据的数组(通常为)。它不需要绑定任何东西。不要与a Vertex Array Object或VAO 混淆,我将在稍后进行介绍
  • 当您存储顶点时Buffer Object,通常称为A ,简称Vertex Buffer ObjectVBO Buffer
  • 什么都不会保存回顶点数组,其glVertexAttribPointer工作原理完全相同glVertexPointerglTexCoordPointer起作用,只是提供一个数字来指定您自己的属性,而不仅仅是命名属性。您将此值传递为index。您的所有glVertexAttribPointer通话都会在您下次通话glDrawArrays或时排队glDrawElements。如果您绑定了VAO,则VAO将存储所有属性的设置。

这里的主要问题是您将顶点属性与VAO混淆了。顶点属性只是为绘制定义顶点,texcoords,法线等的新方法。VAO存储状态。我首先要说明绘图如何与顶点属性一起使用,然后说明如何减少VAO的方法调用次数:

  1. 必须先启用属性,然后才能在着色器中使用它。例如,如果要将顶点发送到着色器,则很有可能将其作为第一个属性0发送。因此,在渲染之前,需要使用启用它glEnableVertexAttribArray(0);
  2. 现在启用了属性,您需要定义将要使用的数据。为此,您需要绑定VBO- glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
  3. 现在我们可以定义属性- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);。按参数顺序排列:0是要定义的属性,3是每个顶点的大小,GL_FLOAT是类型,GL_FALSE表示不对每个顶点进行规范化,后两个零表示顶点上没有步幅或偏移。
  4. 用它画东西- glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 接下来绘制的内容可能不会使用属性0(实际上会使用属性0,但这只是一个示例),因此我们可以将其禁用- glDisableVertexAttribArray(0);

将其包装在glUseProgram()调用中,您将拥有一个与着色器正确配合的渲染系统。但是,假设您有5种不同的属性,即顶点,texcoords,法线,颜色和光照贴图坐标。首先,您将对glVertexAttribPointer这些属性中的每一个进行一次调用,并且必须事先启用所有属性。假设您将属性0-4定义为列出的属性。您可以像这样启用所有功能:

for (int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);

然后,您将不得不为每个属性绑定不同的VBO(除非将它们全部存储在一个VBO中并使用offsets / stride),然后需要进行5个不同的glVertexAttribPointer调用,分别是从glVertexAttribPointer(0,...);glVertexAttribPointer(4,...);顶点到光照贴图坐标。

希望该系统本身有意义。现在,我将继续介绍VAO,以解释在进行这种类型的渲染时如何使用它们来减少方法调用的次数。请注意,没有必要使用VAO。

A Vertex Array Object或VAO用于存储所有glVertexAttribPointer呼叫的状态以及进行每个glVertexAttribPointer呼叫时所针对的VBO 。

您通过调用生成一个glGenVertexArrays。要将所需的一切存储在VAO中,请与之绑定glBindVertexArray,然后进行完整的绘图调用。所有的抽签绑定调用都会被VAO拦截并存储。您可以将VAO与glBindVertexArray(0);

现在,当你想拉拢的对象,你并不需要全部重新调用VBO结合或glVertexAttribPointer电话,你只需要到VAO绑定glBindVertexArray然后打电话glDrawArrays或者glDrawElements,你会被绘制同样的事情,就像你正在进行所有这些方法调用。您可能以后也想取消绑定VAO。

解除绑定VAO后,所有状态将恢复为绑定VAO之前的状态。我不确定在绑定VAO时是否保留您所做的任何更改,但是可以通过测试程序轻松找出。我想您可以将glBindVertexArray(0);其绑定为“默认” VAO ...


更新:有人提醒我需要进行实际抽奖。事实证明,设置VAO时实际上不需要进行FULL绘制调用,只需绑定所有东西即可。不知道为什么我以前认为有必要,但现在已解决。


10
“顶点缓冲对象或VBO(有时称为缓冲对象)”之所以被称为“有时”是因为它实际上就是所谓的。它只是一个缓冲区对象,与用于统一块,像素传输,变换反馈或任何其他用途的任何其他缓冲区对象没有什么不同。OpenGL规范从不将任何东西称为“顶点缓冲区对象”;即使是原始的扩展规范也从未如此称呼它。
Nicol Bolas'1

3
极好的答案。感谢您抽出宝贵的时间写出来!但是,有几个后续问题:(1)您说过“在渲染之前,以及在定义属性之前,您需要使用glEnableVertexAttribArray(0)启用它” –您确定需要在调用之前启用它glVertexAttribPointer吗?在我的测试中,顺序似乎无关紧要。(2)如果我理解正确,那么顶点属性是全局的,并且仅将它们的启用/禁用状态保存到当前绑定的VAO?
mpen 2012年

1
(1)只要您在glDrawArrays或之前启用了订单,我认为该订单无关紧要glDrawElements。我将更新该帖子以反映(2)是的,但是存储的不仅是启用/禁用状态,还包括与这些调用相关的所有内容-当时绑定到GL_ARRAY_BUFFER的内容,类型,跨度和偏移量。本质上,它的存储量足以将所有“顶点属性”更改回使用VAO进行设置的方式。
罗伯特·鲁哈尼

2
是的,VAO旨在让您用绑定VAO代替大多数绘制方法。每个实体可以有一个单独的VAO,并且仍然可以正常使用。但是,您仍然必须更新制服并绑定自己的纹理。而且,无论是layout(location = x)在着色器中通过着色器还是glBindAttributeLocation在编译着色器时,都必须使用与将着色器的属性与属性索引绑定在一起时相同的属性索引。示例
罗伯特·鲁哈尼

8
请注意,在现代OpenGL中,不再有默认的顶点数组对象,您必须自己创建一个对象,否则您的应用程序将无法在前向兼容的上下文中工作。
2012年

3

实际上,要调用的API的术语和顺序非常令人困惑。更令人困惑的是各个方面(缓冲区,通用顶点属性和着色器属性变量)如何关联。有关详细说明,请参见OpenGL术语

此外,链接OpenGL-VBO,shader,VAO显示了带有必要API调用的简单示例。从立即模式过渡到可编程管道的用户特别有用。

希望能帮助到你。

编辑:从下面的评论中可以看到,人们可以做出假设并得出结论。现实情况是,对于初学者来说这很令人困惑。


有关详细说明,请参见OpenGL术语。 ”在不到1分钟的时间里,我已经发现了一个错误信息:“这些被替换为具有与着色器变量(例如坐标,颜色等)来处理属性。” 它们不被称为“索引”。它们是“位置”。这是一个非常重要的区别,因为顶点属性具有“索引”,这与位置有很大不同。那是一个非常糟糕的网站。
Nicol Bolas

2
这是一个公平的评论,但并不完全准确。如果你看一下OpenGL的API定义一个通用属性glVertexAttribPointervoid glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer),标识符被称为index。程序上下文中的相同标识符在locationAPI glGetAttribLocation中调用
2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.