john01dav
john01dav

Reputation: 1962

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). When I create and initialize my VAOs separately, any call to glDrawElements causes the program to immediately exit without any error message. When, however, I create and initialize them together, the exact same glDrawElements call succeeds.


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. 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.

Upvotes: 0

Views: 448

Answers (1)

tkausl
tkausl

Reputation: 14279

Before VAO's were invented, (almost) everything was saved in the global OpenGL state. This changed with VAO's slightly, as they have their own state.

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. 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. 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.

*: To change or delete them you obviously still need their name, hence don't "forget" them in the strict sense of the word.

Upvotes: 6

Related Questions