OpenGL 3:​​glBindVertexArray使GL_ELEMENT_ARRAY_BUFFER无效 [英] OpenGL 3: glBindVertexArray invalidates GL_ELEMENT_ARRAY_BUFFER

查看:328
本文介绍了OpenGL 3:​​glBindVertexArray使GL_ELEMENT_ARRAY_BUFFER无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  
glGenBuffers(1,& buff);
std :: cout<< 缓冲区是< buff< \\\
;
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< \\\
;

glBindVertexArray(vao);
// ^ - 一个隐式glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); ?

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

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



缓冲区是1
在glBindVertexArray之前绑定:1
在glBindVertexArray之后绑定:0

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


  1. 这个行为是否符合规范?

  2. 如果是这样,从 glBindVertexArray

  3. 这是什么原因?

nvidia卡在Win XPx64机器上使用296.10 WHQL驱动程序。
使用nvidia GT330M对OS X Lion进行快速测试得到相同的结果。

解决方案

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


但是,我仍然感到有点困惑的事实,我找不到任何提到这个side-


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



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



OpenGL对象由它们封装的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 功能。如果未启用属性数组,这些可能会影响呈现。


I was certain that if you bind a buffer via glBindBuffer(), you can safely assume that it stays bound, until the target is rebound through another call to glBindBuffer(). I was therefore quite surprised when I discovered that calling glBindVertexArray() sets the buffer bound to the GL_ELEMENT_ARRAY target to 0.

Here's the minimal C++ sample code:

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";

I run this code immediately after initializing an OpenGL 3.2 device context and get the following output:

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

The GL_ARRAY_BUFFER on the other hand is not changed by the call. I checked the OpenGL 3.2 spec (2.10) for glBindVertexArray and found no mention of that unexpected side effect.

  1. Is this behavior compliant with the Spec?
  2. If so, what other side effects can be expected from a call to glBindVertexArray?
  3. What is the rationale behind this?

I tested this on an nvidia card on a Win XPx64 machine with the 296.10 WHQL driver. A quick test on OS X Lion with an nvidia GT330M gave the same results.

解决方案

Vertex Array Objects encapsulate all of the state* necessary to render vertex data. Therefore, they must encapsulate what buffers you associated with attributes (via glVertexAttribPointer), GL_ELEMENT_ARRAY_BUFFER (needed for glDrawElement* calls), and so forth.

However, I still feel a little puzzled by the fact that I couldn't find any mention of this side-effect in the docs.

The specification clearly explains this, though it requires understanding how the spec works to see how.

OpenGL is a collection of state, which means that all OpenGL functions (except those that actually render something) modify OpenGL state. When you call glVertexAttribPointer, this function conceptually modifies some piece of internal OpenGL state.

OpenGL objects are defined by which pieces of OpenGL state they encapsulate. Thus, if a function modifies the state encapsulated by an object, then that function modifies the object itself. Binding an object means replacing the current pieces of state that they encapsulate with the current state of that object.

The ARB_vertex_array_object specification defines VAOs based on what state they encapsulate. It basically points at one of the OpenGL state tables and says, "VAOs are all of that." The core 3.x version of this functionality actually modifies the state tables to make it a bit more clear (same behavior, slightly different explanation thereof):

OpenGL 3.3 specification, section 2.10:

The resulting vertex array object is a new state vector, comprising all the state values listed in tables 6.4 and 6.5.

I'm not going to reprint tables 6.4 and 6.5; you can look them up yourself. But they clearly include GL_ELEMENT_ARRAY_BUFFER_BINDING and the various GL_VERTEX_ATTRIB_ARRAY_BUFFER_BIDNING (which are buffer objects).

* Note: VAOs do not contain the state set by the glVertexAttrib functions. These can affect the rendering if an attribute array is not enabled.

这篇关于OpenGL 3:​​glBindVertexArray使GL_ELEMENT_ARRAY_BUFFER无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆