【问题标题】:OpenGL 3: glBindVertexArray invalidates GL_ELEMENT_ARRAY_BUFFEROpenGL 3:​​glBindVertexArray 使 GL_ELEMENT_ARRAY_BUFFER 无效
【发布时间】:2012-04-17 13:12:45
【问题描述】:

我确信如果您通过glBindBuffer() 绑定缓冲区,您可以放心地假设它保持绑定状态,直到通过另一个调用glBindBuffer() 重新绑定目标。因此,当我发现调用 glBindVertexArray() 会将绑定到 GL_ELEMENT_ARRAY 目标的缓冲区设置为 0 时,我感到非常惊讶。

这是最小的 C++ 示例代码:

GLuint buff;
glGenBuffers(1, &buff);
std::cout << "Buffer is " << buff << "\n";
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buff);
GLuint vao;
glGenVertexArrays(1, &vao);

GLint bound_buff;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &bound_buff);
std::cout << "Bound before glBindVertexArray: " << bound_buff << "\n";

glBindVertexArray(vao);    
  // ^- an implicit glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); ?

glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &bound_buff);
std::cout << "Bound after glBindVertexArray: " << bound_buff << "\n";

我在初始化 OpenGL 3.2 设备上下文后立即运行此代码并获得以下输出:

 Buffer is 1
 Bound before glBindVertexArray: 1
 Bound after glBindVertexArray: 0

另一方面,GL_ARRAY_BUFFER 没有被调用改变。我检查了 OpenGL 3.2 规范 (2.10) 中的 glBindVertexArray 并没有发现意外的副作用。

  1. 此行为是否符合规范?
  2. 如果是这样,调用 glBindVertexArray 会产生哪些其他副作用?
  3. 这背后的原因是什么?

我在带有 296.10 WHQL 驱动程序的 Win XPx64 机器上的 nvidia 卡上对此进行了测试。 使用 nvidia GT330M 在 OS X Lion 上进行的快速测试给出了相同的结果。

【问题讨论】:

  • 我认为绑定 VAO 是隐式绑定元素和顶点数组缓冲区。这就是 VAO 的用途。如果你绑定一个 VAO,然后绑定一个索引和顶点缓冲区,那么每当你以后绑定 VAO 时,这些缓冲区就会被隐式绑定。因此,绑定上面的 VAO 可能隐式地将元素和顶点数组设置为零,因为您没有将它们包含在 VAO 对象中。这有意义吗? :-)
  • 但是为什么它只改变 GL_ELEMENT_ARRAY_BUFFER 而不是 GL_ARRAY_BUFFER?
  • 因为数组缓冲区是顶点缓冲区(至少各种 glEnableVertexAttribArray 和 glVertexAttribPointer 都用它调用你的 make),并且它包含一个元素缓冲区作为该状态的一部分。
  • 这是有道理的。但是,我仍然对在文档中找不到任何关于这种副作用的提及这一事实感到有些困惑。我真的很想看到一些官方文件确认这实际上是理想的行为。
  • @ComicSansMS:仅供参考:如果您询问有关 OpenGL 的问题,您应该使用 OpenGL 标签。即使是 OpenGL 3 的问题;使用 both 标签。

标签: c++ opengl nvidia opengl-3


【解决方案1】:

Vertex Array Objects 封装了渲染顶点数据所需的所有状态*。因此,它们必须封装与属性关联的缓冲区(通过glVertexAttribPointer)、GL_ELEMENT_ARRAY_BUFFER(glDrawElement* 调用需要)等等。

但是,我仍然感到有点困惑,因为我在文档中找不到任何关于这种副作用的提及。

规范清楚地解释了这一点,尽管它需要了解规范的工作原理才能看到。

OpenGL 是一个状态的集合,这意味着所有的 OpenGL 函数(除了那些实际渲染的东西)都会修改 OpenGL 的状态。当你调用glVertexAttribPointer 时,这个函数在概念上会修改一些内部 OpenGL 状态。

OpenGL objects 由它们封装的 OpenGL 状态片段定义。因此,如果一个函数修改了对象封装的状态,那么该函数修改了对象本身。绑定一个对象意味着用该对象的当前状态替换它们封装的当前状态。

ARB_vertex_array_object 规范根据 VAO 封装的状态定义它们。它基本上指向 OpenGL 状态表之一并说:“VAO 就是所有这些。”此功能的核心 3.x 版本实际上修改了状态表以使其更加清晰(行为相同,解释略有不同):

OpenGL 3.3 规范,第 2.10 节:

生成的顶点数组对象是一个新的状态向量,包含表 6.4 和 6.5 中列出的所有状态值。

我不打算重印表 6.4 和 6.5;你可以自己查一下。但它们显然包括GL_ELEMENT_ARRAY_BUFFER_BINDING 和各种GL_VERTEX_ATTRIB_ARRAY_BUFFER_BIDNING(它们是缓冲区对象)。

* 注意:VAO 不包含由glVertexAttrib 函数设置的状态。如果未启用属性数组,这些可能会影响渲染。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多