只是想确保我理解正确(我会问SO聊天,但它已经死了!):
我们有一个顶点阵列,我们通过绑定它来制作“当前”
然后我们有一个缓冲区,我们绑定到目标
然后我们通过glBufferData
填充该目标
它基本上填充了与该目标绑定的任何内容,即我们的缓冲区
然后我们调用glVertexAttribPointer
来描述数据是如何布局的 - 数据是绑定到GL_ARRAY_BUFFER
的任何数据
并且此描述符将保存到我们原始的顶点数组
(1)我的理解是否正确?
关于一切如何相关,documentation有点稀疏。
(2)是否存在某种默认的顶点阵列?因为我忘了/省略glGenVertexArrays
和glBindVertexArray
,我的程序在没有它的情况下工作正常。
修改:我错过了一步... glEnableVertexAttribArray
。
(3)在调用glVertexAttribPointer
时,Vertex Attrib是否与顶点数组相关联,然后我们可以随时通过glEnableVertexAttribArray
启用/禁用该属性,无论哪个顶点数组目前有约束力?
或(3b)在调用glEnableVertexAttribArray
时,顶点属性是否与顶点数组相关联,因此我们可以通过在不同时间调用glEnableVertexAttribArray
将相同的顶点属性添加到多个顶点数组,当绑定不同的顶点数组时?
答案 0 :(得分:207)
有些术语有点过时了:
Vertex Array
只是一个包含顶点数据的数组(通常是float[]
)。它不需要绑定任何东西。不要与Vertex Array Object
或VAO混淆,我将在稍后讨论Buffer Object
,通常在存储顶点时称为Vertex Buffer Object
,或简称为VBO,就是您所谓的Buffer
。glVertexAttribPointer
的工作方式与glVertexPointer
或glTexCoordPointer
完全相同,只需要提供一个指定属性的数字而不是命名属性。您将此值传递为index
。您下次致电glVertexAttribPointer
或glDrawArrays
时,所有glDrawElements
来电都会排队等候。如果您有VAO绑定,VAO将存储您所有属性的设置。这里的主要问题是您将顶点属性与VAO混淆。顶点属性只是为绘图定义顶点,texcoords,法线等的新方法。 VAO存储状态。我首先要解释绘图如何与顶点属性一起使用,然后解释如何使用VAO减少方法调用的数量:
glEnableVertexAttribArray(0);
启用它。glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
。glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
。按参数顺序:0是你定义的属性,3是每个顶点的大小,GL_FLOAT
是类型,GL_FALSE
表示不规范化每个顶点,最后2个零意味着有顶点上没有任何步幅或偏移。glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
在glUseProgram()
次调用中包裹它,并且您有一个可以正确处理着色器的渲染系统。但是,假设您有5种不同的属性,顶点,texcoords,法线,颜色和光照贴图坐标。首先,您将为每个属性进行一次glVertexAttribPointer
调用,并且您必须事先启用所有属性。假设您定义属性0-4,因为我已将它们列出。你可以这样启用所有这些:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
然后你必须为每个属性绑定不同的VBO(除非你将它们全部存储在一个VBO中并使用偏移/步幅),然后你需要从{{1}进行5次不同的glVertexAttribPointer
调用} glVertexAttribPointer(0,...);
分别为顶点到光照贴图坐标。
希望只有这个系统才有意义。现在,我将转到VAO,解释如何使用它们来减少进行此类渲染时的方法调用次数。请注意,不需要使用VAO。
glVertexAttribPointer(4,...);
或VAO用于存储所有Vertex Array Object
次调用的状态以及每次glVertexAttribPointer
次调用时定位的VBO。
通过调用glVertexAttribPointer
生成一个。要在VAO中存储您需要的所有内容,请将其与glGenVertexArrays
绑定,然后执行完整的绘制调用。所有 draw 绑定调用都被VAO拦截并存储。您可以使用glBindVertexArray
现在,当您想要绘制对象时,您不需要重新调用所有VBO绑定或glBindVertexArray(0);
调用,只需要将VAO与glVertexAttribPointer
绑定,然后调用{ {1}}或glBindVertexArray
并且您将绘制完全相同的内容,就好像您正在进行所有这些方法调用一样。你可能也想在之后解开VAO。
一旦解除了VAO的绑定,所有状态将返回到绑定VAO之前的状态。我不确定在VAO绑定时是否进行了任何更改,但是可以通过测试程序轻松找出。我想你可以认为glDrawArrays
绑定到“默认”VAO ......
更新:有人提请我注意实际绘制电话的需要。事实证明,在设置VAO时,实际上并不需要进行全部绘制调用,只需要所有绑定内容。不知道为什么我认为这是必要的,但现在已经修好了。
答案 1 :(得分:2)
要调用的API的术语和顺序确实令人困惑。更令人困惑的是各个方面 - 缓冲区,通用顶点属性和着色器属性变量如何相关联。请参阅OpenGL-Terminology以获得相当不错的解释。
此外,链接OpenGL-VBO,shader,VAO显示了一个包含必要API调用的简单示例。对于那些从立即模式转换到可编程管道的人来说,这是特别好的。
希望它有所帮助。
编辑:从下面的评论中可以看出,人们可以做出假设并得出结论。现实情况是,这对于初学者来说非常困惑。