为什么我不能单独创建和初始化 OpenGl VAO?

joh*_*dav 0 c++ opengl debugging

我目前正在开发一个使用 VAO(每个网格一个)的 OpenGL 3.3 应用程序。当我分别创建和初始化我的 VAO 时,任何对 的调用glDrawElements都会导致程序立即退出而没有任何错误消息。但是,当我一起创建和初始化它们时,完全相同的glDrawElements调用会成功。


单独的初始化代码:

Chunk::Chunk(){
  glGenVertexArrays(1, &m_vaoId);
  glBindVertexArray(m_vaoId);

  glGenBuffers(1, &m_vboId);
  glGenBuffers(1, &m_eboId);

  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (GLvoid*)(0));
  glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (GLvoid*)(1*sizeof(GLfloat)));
  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);
}
Run Code Online (Sandbox Code Playgroud)


void Chunk::refreshMesh(){
  /*build data into vector<GLfloat> verticies and vector<GLuint> indices...*/

  //send data to GPU
  glBindVertexArray(m_vaoId);

  glBindBuffer(GL_ARRAY_BUFFER, m_vboId);
  glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW);

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_eboId);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(GLfloat), indices.data(), GL_STATIC_DRAW);
}
Run Code Online (Sandbox Code Playgroud)

编译的初始化代码:

void Chunk::refreshMesh(){
  /*build data into vector<GLfloat> verticies and vector<GLuint> indices...*/

  //send data to GPU
  glGenVertexArrays(1, &m_vaoId);
  glBindVertexArray(m_vaoId);

  glGenBuffers(1, &m_vboId);
  glBindBuffer(GL_ARRAY_BUFFER, m_vboId);
  glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW);

  glGenBuffers(1, &m_eboId);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_eboId);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(GLfloat), indices.data(), GL_STATIC_DRAW);

  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (GLvoid*)(0));
  glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (GLvoid*)(1*sizeof(GLfloat)));
  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);
}
Run Code Online (Sandbox Code Playgroud)

注意:我使用 Ubuntu 16.04 LTS 与 g++ 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.2)、glew 1.13 和 SDL2 2.0.0 进行编译。我想进行单独的初始化,以便在不创建新的 VAO 等的情况下定期更新网格数据,因为我认为可以在任何真实的 GPU 上处理有限数量的这些数据。

tka*_*usl 5

在发明 VAO 之前,(几乎)所有内容都保存在全局 OpenGL 状态中。VAO 的情况略有改变,因为它们有自己的状态。

您正在使用glVertexAttribPointer设置指向缓冲区中属性的指针,但是,VAO 状态不仅包含您传递给函数的值,还包含它们指向的缓冲区,即GL_ARRAY_BUFFER调用时绑定到的缓冲区功能。这允许这样的事情(伪代码):

glBindBuffer(GL_ARRAY_BUFFER, a);
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, b);
glVertexAttribPointer(...);
Run Code Online (Sandbox Code Playgroud)

有了这个,您将使用来自两个不同缓冲区的属性。然后您可以取消绑定缓冲区并忘记*它们,您不需要绑定它们进行绘图。

TLDR:要解决您的问题,您需要GL_ARRAY_BUFFER在调用之前绑定您打算使用的缓冲区glVertexAttribPointer。您不需要每次都绑定缓冲区进行绘图,因为 VAO使用当前绑定的缓冲区数组缓冲区进行绘图,而是使用在设置属性指针时绑定的缓冲区。

*:要更改或删除它们,您显然仍然需要它们的名字,因此不要在严格意义上“忘记”它们。

  • 即使在创建 VAO 之后,也隐含着全局顶点状态。区分这种区别的是核心配置文件,在其他所有支持 VAO 的地方,您可以想象一下,最初有一个默认的 VAO(名称 = **0**)绑定,就像纹理一样;) (3认同)