Linking with OpenGL 3.x VBO

I am trying to update my engine that used OpenGL 2.x vertex arrays to work with OpenGL 3.x, which means updating for VAO / VBOs. I think that I am not getting attached to VBO properly. Read below for more information or skip the code and find what I am doing wrong.

A brief overview of my grid classes looks something like this:

Grid

  • root meshNode

MeshNode

  • convert
  • VAO Index
  • VBO index
  • array of child MeshNodes
  • an array of MeshObjects objects

Meshhobject

  • all vertex and index data loaded from a file for a separate part of the general grid
  • top of the vbo index

If I draw a MeshNode with only one MeshObject, it seems to be drawn perfectly. When I draw a MeshNode with several MeshObjects, I get that the general shape of the model that I am trying to draw is distorted.

I checked the vertex data in the Visual Studio debugger and the VBO data through gDEbugger and everything looks great, so I'm sure loading from a file and loading in VBOs works.

I used gDEbugger to make it draw points for all the vertices instead of triangles, and it has the shape of a single MeshObject, which makes me think that I just don't attach to different VBOs properly. As if he is trying to draw with different indices, but the same vertices every time.

VertexData is as follows:

struct VertexData { enum { NUM_TEXCOORDS = 1, }; vector3 vertex; vector3 normal; vector2 texCoord[NUM_TEXCOORDS]; }; 

Relevant MeshNode Code:

 void MeshNode::initVAO(void) { closeVAO(); unsigned int scan; //init index data if (m_meshObjects.size() > 0) { glGenVertexArrays(1, &m_meshVAO); glBindVertexArray(m_meshVAO); { //add up the total index count for all the mesh objects in this node unsigned int indexCount = 0; for (scan = 0; scan < m_meshObjects.size(); ++scan) { indexCount = indexCount + m_meshObjects[scan].getIndices()->size(); } //make the actual index buffer glGenBuffers(1, &m_indexVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexVBO); { glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(unsigned short), NULL, GL_STATIC_DRAW); //set up VBOs and fill the index buffer with the index data from each mesh object unsigned int offset = 0; for (scan = 0; scan < m_meshObjects.size(); ++scan) { m_meshObjects[scan].initVBOs(offset); } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } glBindVertexArray(0); } for (scan = 0; scan < m_childMeshNodes.size(); ++scan) { m_childMeshNodes[scan]->initVAO(); } } void MeshNode::closeVAO(void) { if (m_meshVAO != 0) { glBindVertexArray(m_meshVAO); { glDeleteBuffers(1, &m_indexVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } glBindVertexArray(0); glDeleteVertexArrays(1, &m_meshVAO); m_meshVAO = 0; m_indexVBO = 0; } } void MeshNode::render(const matrix4 &_parentTransform) { matrix4 transform = _parentTransform * m_transform; if (m_meshObjects.size() > 0) { glBindVertexArray(m_meshVAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexVBO); { for (unsigned int objectScan = 0; objectScan < m_meshObjects.size(); ++objectScan) { m_meshObjects[objectScan].render(transform); } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(0); } for (unsigned int childScan = 0; childScan < m_childMeshNodes.size(); ++childScan) { m_childMeshNodes[childScan]->render(transform); } } 

Corresponding MeshObject code:

 void MeshObject::initVBOs(unsigned int& _indexOffset) { //sub in this section of the index data m_indexOffset = _indexOffset; _indexOffset = _indexOffset + m_indices.size(); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, m_indexOffset * sizeof(unsigned short), m_indices.size() * sizeof(unsigned short), &(m_indices[0])); //init vertex data glGenBuffers(1, &m_vertexVBO); glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO); { glBufferData(GL_ARRAY_BUFFER, m_data.size() * sizeof(VertexData), &(m_data[0]), GL_STATIC_DRAW); glVertexAttribPointer(Shader::POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)0); glEnableVertexAttribArray(Shader::POSITION); glVertexAttribPointer(Shader::NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)12); glEnableVertexAttribArray(Shader::NORMAL); glVertexAttribPointer(Shader::TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)24); glEnableVertexAttribArray(Shader::TEXCOORD0); } glBindBuffer(GL_ARRAY_BUFFER, 0); } void MeshObject::closeVBOs(void) { glDeleteBuffers(1, &m_vertexVBO); m_vertexVBO = 0; } void MeshObject::render(const matrix4& _transform) { m_material->bind(_transform); glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO); { glEnableVertexAttribArray(Shader::POSITION); glEnableVertexAttribArray(Shader::NORMAL); glEnableVertexAttribArray(Shader::TEXCOORD0); glDrawRangeElements(GL_TRIANGLES, m_indexOffset, m_indexOffset + m_indices.size(), m_indices.size(), GL_UNSIGNED_SHORT, (char*)0); glDisableVertexAttribArray(Shader::POSITION); glDisableVertexAttribArray(Shader::NORMAL); glDisableVertexAttribArray(Shader::TEXCOORD0); } glBindBuffer(GL_ARRAY_BUFFER, 0); } 
+8
c ++ 3d opengl opengl-3 vbo
source share
2 answers

A brief overview of my grid classes looks something like this:

I think your scene graph hierarchy is a bit confusing. All Node in the scene graph needs transformations, a Node children list, and a list of cells to draw in Node . It should not have an element buffer or VAO; they are conceptually part of the grid data.

In fact, your problem stems from this last point. Vertex Array objects contain the state set by the glVertexAttrib(I)Pointer calls. This means that every time you call MeshObject::initVBOs within the same MeshNode, you overwrite the data set with the previous call.

Each grid requires its own VAO, not node. Cells can exchange index data, which you seem to be doing (although they should also use the same buffer object for their vertex data if you are worried about having too many buffers). But VAOs must be different. Multiple VAOs can reference the same element buffer.

+5
source share

I think you are using glDrawRangeElements . The start and end parameters are the minimum and maximum index of the vertices that can occur in the index array, but you provide m_indexOffest and m_indexOffset+m_indices.size() , which is the range of index data that you render, and not necessarily the range of vertex indices inside these index arrays.

And as a note, VAO encapsulates every array / vertex buffer state, all buffer bindings, pointers and flags, so you make a lot of unnecessary calls. Just bind the index buffer in the initVAO method, and then it always binds when you bind the VAO in the MeshNode::render method (of course, omit all glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) calls glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) in this case). You also need to include attribute arrays in the initVAO method (assuming all MeshObject have the same attributes), and they are automatically activated when you bind VAO. VAO is not required in your current configuration, and you are not abandoning it.

+1
source share

All Articles