简体   繁体   English

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

[英]Why can't I create and initialize an OpenGl VAO separately?

I am currently working on an OpenGl 3.3 application that makes use of VAOs (one per mesh). 我目前正在研究使用VAO(每个网格一个)的OpenGl 3.3应用程序。 When I create and initialize my VAOs separately, any call to glDrawElements causes the program to immediately exit without any error message. 当我分别创建和初始化我的VAO时,对glDrawElements任何调用glDrawElements导致程序立即退出,而不会出现任何错误消息。 When, however, I create and initialize them together, the exact same glDrawElements call succeeds. 但是,当我一起创建和初始化它们时,完全相同的glDrawElements调用成功。


Separate Initialization Code: 单独的初始化代码:

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);
}


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);
}

Compiled Initialization Code: 编译后的初始化代码:

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);
}

NOTE: I am using Ubuntu 16.04 LTS to compile with g++ 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.2), glew 1.13, and SDL2 2.0.0. 注意:我正在使用Ubuntu 16.04 LTS与g ++ 5.4.0 20160609(Ubuntu 5.4.0-6ubuntu1〜16.04.2)一起编译,运行1.13和SDL2 2.0.0。 I want to do separate initialization to allow for the mesh data to be updated periodically without creating a new VAO, etc. since I imagine a finite number of those can be handled on any real GPU. 我想进行单独的初始化,以允许在不创建新VAO的情况下定期更新网格数据,因为我想可以在任何实际GPU上处理有限数量的网格数据。

Before VAO's were invented, (almost) everything was saved in the global OpenGL state. 在发明VAO之前,(几乎)所有内容都保存在全局OpenGL状态下。 This changed with VAO's slightly, as they have their own state. 这与VAO略有不同,因为它们具有自己的状态。

You are using glVertexAttribPointer to set up the pointers to attributes in buffers, however, the VAO state does not only contain the values you pass to the function but also the buffer which they point to, which is the buffer which was bound to GL_ARRAY_BUFFER when you called the function. 您正在使用glVertexAttribPointer在缓冲区中设置指向属性的指针,但是,VAO状态不仅包含您传递给函数的值,还包含它们指向的缓冲区, GL_ARRAY_BUFFER当您绑定到GL_ARRAY_BUFFER的缓冲区时称为功能。 This allows for something like this (pseudocode): 这允许这样的事情(伪代码):

glBindBuffer(GL_ARRAY_BUFFER, a);
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, b);
glVertexAttribPointer(...);

with this, you'd use attributes from two different buffers. 这样,您将使用来自两个不同缓冲区的属性。 You could then unbind the buffers and forget* about them, you don't need to bind them for drawing. 然后,您可以取消绑定缓冲区而忘记*它们,而无需为绘制而绑定它们。

TLDR: To fix your problem, you need to bind the buffer you intend to use to GL_ARRAY_BUFFER before you call glVertexAttribPointer . TLDR:要解决您的问题,您需要在调用glVertexAttribPointer之前将要使用的缓冲区绑定到GL_ARRAY_BUFFER You don't need to bind the buffer every time for drawing, as the VAO does not use the currently bound buffer array buffer for drawing but the one which was bound when the attribute-pointer was set. 您不需要每次都绑定缓冲区以进行绘制,因为VAO 不会使用当前绑定的缓冲区数组缓冲区进行绘制,而是使用设置了属性指针时绑定的缓冲区。

*: To change or delete them you obviously still need their name, hence don't "forget" them in the strict sense of the word. *:要更改或删除它们,您显然仍然需要它们的名称,因此不要严格意义上的“忘记”它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM