glVertexAttribPointer澄清
只是想确保我正确理解这个(我会问在SO聊天,但它已经死了!):
我们有一个顶点数组,我们通过绑定来创build“当前”
然后我们有一个缓冲区,我们绑定到一个目标
那么我们通过glBufferData
来填充Target,它基本上填充绑定到那个目标的东西,也就是我们的Buffer
然后我们调用glVertexAttribPointer
来描述数据是如何布置的 – 数据是绑定到GL_ARRAY_BUFFER
任何东西,这个描述符被保存到我们原始的顶点数组
(1)我的理解是否正确?
这个文档对于所有东西是如何相关的有点稀疏。
(2)是否有某种默认的顶点数组? 因为我忘了/省略glGenVertexArrays
和glBindVertexArray
和我的程序工作正常,没有它。
编辑:我错过了一个步骤… 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
工作方式与glVertexPointer
或glTexCoordPointer
工作方式完全相同,而不是命名属性,您可以提供一个数字来指定您自己的属性。 你把这个值作为index
。 所有的glVertexAttribPointer
调用都会在下一次调用glDrawArrays
或glDrawElements
。 如果您有VAO绑定,VAO将存储所有属性的设置。
这里的主要问题是你把顶点属性和VAO混淆了。 顶点属性只是为绘图定义顶点,texcoords,法线等的新方法。 VAO的存储状态。 我将首先解释如何使用顶点属性进行绘图,然后解释如何减less使用VAO的方法调用次数:
- 在着色器中使用它之前,必须启用属性。 例如,如果要将顶点发送到着色器,则最有可能将其作为第一个属性0发送。因此,在渲染之前,需要使用
glEnableVertexAttribArray(0);
启用顶点glEnableVertexAttribArray(0);
。 - 现在启用了一个属性,您需要定义要使用的数据。 为了做到这一点,你需要绑定你的VBO –
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
。 - 现在我们可以定义属性 –
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
。 按照参数的顺序:0是你定义的属性,3是每个顶点的大小,GL_FLOAT
是types,GL_FALSE
表示不规范化每个顶点,最后2个0表示顶点没有步长或者偏移量。 - 画一些东西 –
glDrawArrays(GL_TRIANGLES, 0, 6);
- 接下来的事情可能不会使用属性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水线的人来说特别有用。
希望能帮助到你。
编辑:从下面的评论中可以看出,人们可以做出假设并跳到结论。 实际情况是,初学者相当困惑。