glVertexAttribPointer澄清

只是想确保我正确理解这个(我会问在SO聊天,但它已经死了!):

我们有一个顶点数组,我们通过绑定来创build“当前”
然后我们有一个缓冲区,我们绑定到一个目标
那么我们通过glBufferData来填充Target,它基本上填充绑定到那个目标的东西,也就是我们的Buffer
然后我们调用glVertexAttribPointer来描述数据是如何布置的 – 数据是绑定到GL_ARRAY_BUFFER任何东西,这个描述符被保存到我们原始的顶点数组

(1)我的理解是否正确?
这个文档对于所有东西是如何相关的有点稀疏。

(2)是否有某种默认的顶点数组? 因为我忘了/省略glGenVertexArraysglBindVertexArray和我的程序工作正常,没有它。


编辑:我错过了一个步骤… glEnableVertexAttribArray

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

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

一些术语是有点closures的:

  • Vertex Array只是一个包含顶点数据的数组(通常是一个float[] )。 它不需要绑定任何东西。 不要与Vertex Array Object或VAO混淆,我将在稍后进行讨论
  • Buffer Object ,通常在存储顶点时称为Vertex Buffer Object Buffer Object ,简称为VBO,就是你所称的Buffer
  • 没有任何东西被保存回顶点数组, glVertexAttribPointer工作方式与glVertexPointerglTexCoordPointer工作方式完全相同,而不是命名属性,您可以提供一个数字来指定您自己的属性。 你把这个值作为index 。 所有的glVertexAttribPointer调用都会在下一次调用glDrawArraysglDrawElements 。 如果您有VAO绑定,VAO将存储所有属性的设置。

这里的主要问题是你把顶点属性和VAO混淆了。 顶点属性只是为绘图定义顶点,texcoords,法线等的新方法。 VAO的存储状态。 我将首先解释如何使用顶点属性进行绘图,然后解释如何减less使用VAO的方法调用次数:

  1. 在着色器中使用它之前,必须启用属性。 例如,如果要将顶点发送到着色器,则最有可能将其作为第一个属性0发送。因此,在渲染之前,需要使用glEnableVertexAttribArray(0);启用顶点glEnableVertexAttribArray(0);
  2. 现在启用了一个属性,您需要定义要使用的数据。 为了做到这一点,你需要绑定你的VBO – glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
  3. 现在我们可以定义属性 – glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 。 按照参数的顺序:0是你定义的属性,3是每个顶点的大小, GL_FLOAT是types, GL_FALSE表示不规范化每个顶点,最后2个0表示顶点没有步长或者偏移量。
  4. 画一些东西 – glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 接下来的事情可能不会使用属性0(实际上它会,但是这是一个例子),所以我们可以禁用它 – glDisableVertexAttribArray(0);

将其glUseProgram()glUseProgram()调用中,并且您有一个可以正确处理着色器的渲染系统。 但是,假设您有5个不同的属性,顶点,texcoords,法线,颜色和光照贴图坐标。 首先,您将为每个属性进行一次glVertexAttribPointer调用,您必须事先启用所有属性。 假设你定义了我列出的属性0-4。 你可以像这样启用它们:

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

然后,你将不得不为每个属性绑定不同的VBO(除非你把它们都存储在一个VBO中,并使用偏移量/步长),那么你需要从glVertexAttribPointer(0,...);做5个不同的glVertexAttribPointer调用glVertexAttribPointer(0,...);glVertexAttribPointer(4,...); 为顶点分别光照贴图坐标。

希望这个系统是有道理的。 现在我将转到VAO,解释如何在进行这种渲染时使用它们来减less方法调用次数。 请注意,使用VAO是不必要的。

Vertex Array Object或VAO用于存储每个glVertexAttribPointer调用时所有调用的glVertexAttribPointer调用和VBO的状态。

您可以通过调用glGenVertexArrays来生成一个。 为了在VAO中存储你需要的所有东西,把它和glBindVertexArray绑定,然后做一个完整的绘制调用 。 所有的绑定绑定调用都被VAO拦截并存储。 你可以用glBindVertexArray(0);解除VAO绑定glBindVertexArray(0);

现在当你想绘制对象的时候,你不需要重新调用所有的VBO绑定或者glVertexAttribPointer调用,你只需要将VAO与glBindVertexArray绑定,然后调用glDrawArrays或者glDrawElements ,你就可以画出完全相同的就好像你在做所有这些方法调用一样。 之后你可能也想解开VAO。

一旦你解除了VAO的绑定,所有的状态都会返回到绑定VAO之前的状态。 我不确定你在VAO绑定时是否做了任何修改,但是可以很容易地通过一个testing程序来计算出来。 我想你可以想到glBindVertexArray(0); 作为绑定到“默认”VAO …


更新:有人提醒我需要实际的平局。 事实certificate,在设置VAO时,实际上并不需要进行全画通话,而只需要所有的绑定。 不知道为什么我认为这是必要的,但现在是固定的。

要调用的API的术语和顺序确实相当混乱。 更令人困惑的是,缓冲区,通用顶点属性和着色器属性variables的各个方面是如何关联的。 请参阅OpenGL术语以获得相当好的解释。

此外,链接OpenGL-VBO,着色器,VAO显示了一个简单的例子,必要的API调用。 对于那些从即时模式转换到可编程stream水线的人来说特别有用。

希望能帮助到你。

编辑:从下面的评论中可以看出,人们可以做出假设并跳到结论。 实际情况是,初学者相当困惑。