How to use multiple buffers (glGenBuffer/BindBuffer)

Hello OpenGL experts,

I am asking for some help to get multiple buffer objects working.

I have an animated scene with mutliple ellipses & spheres, and it is starting to go slow if I keep sending all the vertices to OpenGL for each frame. So I want to re-use buffer data across scene objects since I have repeats of the same data & just a different model-view transform.

The same shader is used throughout. The code works fine if I set (objectNotInCache) to always return TRUE, so the buffers get recreated each time round the loop. It also works fine if I only use one geometry & therefore keep retrieving the same one from my cache.

I can’t get this working with mutliple goemetries in the same scene. The minute I introduce a mix of geometries (i.e. use multiple buffers), I get garbage on screen - so obviously I am missing something in how to correctly set up and swap between buffers.

Thanks in advance for any assistance. Can anyone advise what I am doing wrong?


=========
Pseudocode

Loadshader ()

SetShaderUniforms(); 

for (each object in scene)
{
   SetShaderModelView(); 

   if (objectNotInCache)
   {
      glGenVertexArrays( 1, &vao );
      glBindVertexArray( vao );

      glGenBuffers (1, &bufferID)
      glBindBuffer (GL_ARRAY_BUFFER, bufferID);

      // Set up buffers for drawing facets. I know interleaved will be faster but want to get
      // a simpler buffer layout working first. 
      glBufferData( GL_ARRAY_BUFFER, 
                    vertexbuffersize + normalbuffersize,
                    NULL, GL_STATIC_DRAW );  
      glBufferSubData( GL_ARRAY_BUFFER, 
                       0, vertexBufferSize(), pVertices);
      glBufferSubData( GL_ARRAY_BUFFER, 
                       vertexbuffersize , normalbuffersize, pNormals); 

      // vPosition & vNormal are the shader variables for vertex position & normal
      // the positions are retrieved up where I load the shader. I know this is working bcs the
      // program works when I use a single buffer or use only one geometry and thus one buffer
      glEnableVertexAttribArray( vPosition );
      glEnableVertexAttribArray( vNormal );

      // set up the vertex arrays for drawing facets
      glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
                             BUFFER_OFFSET(0) );
      glVertexAttribPointer( vNormal, 3, GL_FLOAT, GL_FALSE, 0,
                             BUFFER_OFFSET(vertexbuffersize) ); 

      cacheVaoAndBuffer (vao, bufferID);
   }
   else
   {
      getVaoAndBufferfromCache (&vao, &bufferID);

      glBindVertexArray( vao );
      glBindBuffer (GL_ARRAY_BUFFER, bufferID);

      // I supect I don't need the following 4 calls but ended up putting them in
      // a vain attempt to get some output. 
      glEnableVertexAttribArray( vPosition );
      glEnableVertexAttribArray( vNormal );

      glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
                             BUFFER_OFFSET(0) );
      glVertexAttribPointer( vNormal, 3, GL_FLOAT, GL_FALSE, 0,
                             BUFFER_OFFSET(vertexbuffersize) );

   }
       

   glDrawArrays( GL_TRIANGLES, 0, vertexCount);

}

When you use VAO, you don’t need to call bind the VBO, you don’t need to enable the arrays and call glVertexAttribPointer. A VAO stores all those states.
Also, are you using shaders?

[QUOTE=V-man;1239365]When you use VAO, you don’t need to call bind the VBO, you don’t need to enable the arrays and call glVertexAttribPointer. A VAO stores all those states.
Also, are you using shaders?[/QUOTE]

Yes, I am using shaders. I have removed the calls to Bind, enable arrays etc for the case where they should already be set up & associated with the VAO. Code works fine when I have only 1 VAO & 1 VBO, but as soon as I have more than one then I get what looks like random or arbiritrary output.

My code inside the loop through objects in the scene looks like:


if (object not yet cached)
{
         glGenVertexArrays( 1, &uVAO );
         glBindVertexArray( uVAO );

         glGenBuffers( 1, &uBuffer );
         glBindBuffer( GL_ARRAY_BUFFER, uBuffer );

         // Set up buffers for drawing facets
         glBufferData( );  
         glBufferSubData(// Vertices);
         glBufferSubData(// Normals); 

         SaveVaoInCache(uVao); 

         vPosition= glGetAttribLocation( shaderId, "vPosition" );
         glEnableVertexAttribArray( vPosition );
         vNormal = glGetAttribLocation( shaderId, "vNormal" ); 
         glEnableVertexAttribArray( vNormal );
         glVertexAttribPointer(vPosition etc );
         glVertexAttribPointer(vNormal etc ); 
}
else
{
   uVAO = lookUpObjectInCache();
   glBindVertexArray( uVAO );
}

glDrawArrays( GL_TRIANGLES, 0, uVertices);

For posterity I am going to answer my own question here …

I never got multiple VAOs or buffers to work.

There are other threads here that discuss performance … so I decided to switch to one large buffer, use glBufferSubData() to hold the vertices of the various objects in the scene, and switch the offsets in glVertexAttribPointer () to match when drawing the objects. Pointers & memory layout seems easier to understand than the GL API. I still don’t understand how multiple buffers/VAOs work …

So try to debug it. Inspect the values you get in each uVAO. Inspect the value you get for each VBO.
What you are doing should work (all the vertices come first, then all the normals) but perhaps try to interleave them (x y z nx ny nz | x y z nx ny nz | x y …).
If that doesn’t work. Try it without VAO (Write a GL 3.0 program).

1 large VBO is fine if you are writing a small program. Try to keep it under 4 MB.

[QUOTE=V-man;1239511]So try to debug it. Inspect the values you get in each uVAO. Inspect the value you get for each VBO.
What you are doing should work (all the vertices come first, then all the normals) but perhaps try to interleave them (x y z nx ny nz | x y z nx ny nz | x y …).
If that doesn’t work. Try it without VAO (Write a GL 3.0 program).

1 large VBO is fine if you are writing a small program. Try to keep it under 4 MB.[/QUOTE]

Yes, I was doing that … it all seemed to work (I got progressive integers for the VAO & VBO ids … just no output on the screen.

A single buffer holding multiple objects is working fine, so I have parked this.

Thanks anyway for your advice. I will keep an eye on the buffer size & return to this area if it goes > 4MB. I will also set the data up interleaved … am currently adding texture coords so I will get that working with in my current order before interleaving it all (x y z nx ny nz tx ty | x y z nx ny nz tx ty | …