glVertexAttribPointer澄清

mpe*_*pen 92 opengl

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

我们有一个顶点数组,我们通过绑定它来制作"当前"
然后我们有一个缓冲区,我们绑定到一个目标,
然后我们填充该目标,通过glBufferData 该目标基本上填充绑定到该目标的任何东西,即我们的缓冲区
然后我们调用glVertexAttribPointer哪个描述数据是如何布局的 - 数据是绑定的任何数据GL_ARRAY_BUFFER ,这个描述符保存到我们原始的顶点数组中

(1)我的理解是否正确?关于一切如何相关
文档有点稀疏.

(2)是否存在某种默认的顶点阵列?因为我忘了/省略了glGenVertexArrays,glBindVertexArray没有它我的程序运行正常.


编辑:我错过了一步...... glEnableVertexAttribArray.

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

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

Rob*_*ani 207

有些术语有点过时了:

  • A Vertex Array只是一个float[]包含顶点数据的数组(通常是a ).它不需要绑定任何东西.不要与a Vertex Array Object或VAO 混淆,我将在稍后讨论
  • A Buffer Object,通常被称为Vertex Buffer Object存储顶点时,或简称VBO,就是你所谓的a Buffer.
  • 没有任何东西被保存回顶点数组,glVertexAttribPointer工作完全像glVertexPointerglTexCoordPointer工作,只是代替命名属性,你可以提供一个指定自己的属性的数字.您将此值传递为index.您的所有glVertexAttribPointer调用就会排队等候下次呼叫时间glDrawArraysglDrawElements.如果您有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意味着不规范化每个顶点,最后2个零意味着顶点上没有步幅或偏移.
  4. 用它画一些东西 - glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 你绘制的下一件事可能不会使用属性0(实际上它会,但这是一个例子),所以我们可以禁用它 - glDisableVertexAttribArray(0);

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

for (int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);
Run Code Online (Sandbox Code Playgroud)

然后,你就必须结合不同维也纳组织为每个属性(除非您将它们都存储在一个VBO及使用补偿/步幅),那么你需要5个不同的glVertexAttribPointer电话,从glVertexAttribPointer(0,...);glVertexAttribPointer(4,...);了顶点光照贴图坐标分别.

希望这个系统是有道理的.现在,我将继续讨论如何使用它们来减少进行此类渲染时方法调用的数量.请注意,不需要使用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时,实际上并不需要进行全部绘制调用,只需要所有绑定内容.不知道为什么我认为这是必要的,但现在已经解决了.

  • "顶点缓冲区对象,或VBO(有时简称为缓冲区对象)"它"有时"被称为"因为它实际上就是它所谓的".它只是一个缓冲区对象,与您可能用于统一块,像素传输,变换反馈或任何其他用途的任何其他缓冲区对象没有区别.OpenGL规范*从不*将任何东西称为"顶点缓冲对象"; 甚至[原始扩展规范](http://www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt)也从不称它为. (9认同)
  • 请注意,在现代OpenGL中,不再有默认的顶点数组对象,您必须自己创建一个,否则您的应用程序将无法在向前兼容的上下文中工作. (8认同)
  • 很好的答案.感谢您花时间写出来!一对夫妇可以跟进问题:(1)你说"在渲染之前,在定义属性之前,你需要用glEnableVertexAttribArray(0)启用它" - 你确定它需要在调用之前启用它吗? glVertexAttribPointer`?在我的测试中,订单似乎并不重要.(2)如果我理解正确,顶点属性是全局的,只有它们的启用/禁用状态被保存到当前绑定的VAO? (3认同)
  • 是的,VAO旨在让您通过绑定VAO来替换大部分绘制方法.每个实体都可以有一个单独的VAO,它仍然可以正常工作.你仍然需要更新制服并绑定自己的纹理.并且您必须使用相同的属性索引来将着色器的属性与属性索引绑定,无论是通过着色器中的`layout(location = x)`还是在编译着色器时使用`glBindAttributeLocation`.[实施例](http://www.opengl.org/wiki/Tutorial1:_Rendering_shapes_with_glDrawRangeElements,_VAO,_VBO,_shaders_(C%2B%2B _/_ freeGLUT)) (2认同)