OpenGL 3:​​glBindVertexArray使GL_ELEMENT_ARRAY_BUFFER无效

Com*_*sMS 7 c++ opengl nvidia opengl-3

我确信如果你绑定一个缓冲区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";
Run Code Online (Sandbox Code Playgroud)

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

 Buffer is 1
 Bound before glBindVertexArray: 1
 Bound after glBindVertexArray: 0
Run Code Online (Sandbox Code Playgroud)

另一方面,GL_ARRAY_BUFFER 不会被呼叫改变.我检查了OpenGL 3.2规范(2.10),glBindVertexArray没有发现这种意想不到的副作用.

  1. 这种行为是否符合规范?
  2. 如果是这样,可以通过电话预期会产生哪些其他副作用glBindVertexArray
  3. 这背后的理由是什么?

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

Nic*_*las 14

顶点数组对象封装了渲染顶点数据所需的所有状态*.因此,它们必须封装与属性(via glVertexAttribPointer),GL_ELEMENT_ARRAY_BUFFER(glDrawElement*调用所需)等相关联的缓冲区.

但是,我仍然感到有些困惑,因为我在文档中找不到任何关于这种副作用的事实.

规范清楚地解释了这一点,但它需要了解规范的工作原理.

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

OpenGL对象由它们封装的OpenGL状态块定义.因此,如果函数修改了对象封装的状态,那么该函数会修改对象本身.绑定对象意味着将它们封装的当前状态块替换为该对象的当前状态.

ARB_vertex_array_object规范基础上,他们封装什么状态定义VAOs.它基本上指向一个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函数设置的状态.如果未启用属性数组,这些可能会影响渲染.