OpenGL:是否可以在不指定VBO的情况下使用VAO


12

在我可以找到的有关VAO(顶点数组对象)的所有教程中,它们都展示了如何通过配置顶点属性和绑定VBO(顶点缓冲区对象)来使用它们。但是我想创建一个VAO,该VAO将与一组固定着色器一起为一组VBO配置,其中每个缓冲区使用相同的数据模式(顶点,uv,颜色等)。因此,我想为将使用一个着色器绘制的多个VBO创建一个VAO。

我在此上找不到任何演示,所以我决定尝试一下。但它不起作用,并在glDrawArray通话中崩溃。似乎VBO没有绑定。这是我正在使用的代码:

渲染:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

VAO创作:

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

其中ls一个简单的struct保存属性位置。

在“渲染”部分中,交换glBindBufferglBindVertexArrayOES周围环境也不起作用。

因此,问题是:是否有可能这样做,还是我必须为每个缓冲区创建一个VAO?如果我必须为每个VBO创建一个VAO,是否可以glBufferSubData结合使用VAO 来更新VBO的数据?

Answers:


18

VAO不包含“ glBindBuffer”状态,但GL_ELEMENT_ARRAY_BUFFER的绑定状态除外。您不了解的是什么glBindBuffer(GL_ARRAY_BUFFER) 也没做。好吧,就渲染而言,它没有任何作用。尝试一下; 在调用glDraw *之前,立即调用glBindBuffer(GL_ARRAY_BUFFER, 0); 您的渲染效果很好。

其工作方式glVertexAttribPointer是查看调用glVertexAttribPointer绑定到GL_ARRAY_BUFFER 内容。不在渲染时。不晚 就在那一刻。它获取那里的任何缓冲区对象,并将其存储在另一个OpenGL状态中,该状态封装在VAO中。

通常,您有两种选择,其中一种是新的,可能不应该在此时使用。

您的第一个选择是将所有使用相同顶点格式的对象(即:除缓冲区对象和偏移量以外的所有对象)放在同一缓冲区对象中。基本上,构建一个巨型数组,其中包含使用相同格式的所有对象的所有顶点。

当需要渲染时,可以渲染一部分顶点。glDrawArrays需要渲染一系列元素,您可以调整索引glDrawElements以执行相同的操作。另外,您也可以使用glDrawElementsBaseVertex偏置顶点,从而加入到每个索引的偏移量。此偏移量是大数组中该顶点之前的顶点数量。

另一种选择是使用GL 4.3中添加的相对较新的格式属性分离系统。它可以让您更改缓冲区而无需重新设置格式。因此,您将绑定一个VAO,然后根据需要仅替换为不同的缓冲区glBindVertexBuffer。ES 3.1中也提供了此功能。


1
NV GL4.3驱动程序现在已完全发布。
Maximus Minimus

非常感谢您解释glVertexAttribPointer的工作方式。这很有启发性,并解释了它为什么起作用以及如何起作用。
Martijn Courteaux

5

VAO存储glVertexAttribPointer状态。更改VAO不会影响当前的glBindBuffer,更改glBindBuffer也不会影响VAO。通过记录调用中使用的缓冲区,只有glVertexAttribPointer调用会影响VAO。

因此,您的问题的答案是否定的。

如果要减少对象数量,一个选择是将所有网格数据放入一个大的VBO中,并使用“ first”和“ count”参数在glDrawArrays调用中指定网格数据在VBO中的位置。


VAO上互联网上的所有文章都显示,绑定VAO会自动绑定VBO。因此,我认为VAO是同时包含glVertexAttribPointer状态和glBindBuffer状态的配置。是的,绑定VAO时绑定VBO会更改VAO。我说这是因为我已经测试了它并且有效地做到了。这些信息从何而来?
Martijn Courteaux 2013年

2
@MartijnCourteaux:“ VAO上互联网上的所有文章都表明,绑定VAO会自动绑定VBO。 ”不,他们没有。OpenGL Wiki在顶点规范上没有。确实,给我看互联网上的一篇文章,其中说,绑定VAO 之外,其他任何glBindBuffer状态 GL_ELEMENT_ARRAY_BUFFER将更改。
Nicol Bolas 2013年

另一个答案很好地解释了glVertexAttribPointer方法的工作方式。它使用当时绑定的VBO。你是对的!谢谢,我现在明白了。
Martijn Courteaux
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.