user9833551
user9833551

Reputation:

OpenGL will only update the last vertex array object

I am writing some code that generates some VAO and then when the physics have been updated a call is made to update the vertices inside the VAOs and then a call is made to redraw these objects.

The problem with my code is that only the last VAO is being updated by UpdateScene. The following two functions create the buffers.

void BuildBuffers(std::vector<demolish::Object>& objects)
{
    VAO = new UINT[objects.size()];
    glGenVertexArrays(objects.size(),VAO);
    int counter = 0;
    for(auto& o:objects)
    {
        if(o.getIsSphere())
        {
            BuildSphereBuffer(o.getRad(),o.getLocation(),counter);
            counter++;
        }
        else
        {
        }
    }
}

void BuildSphereBuffer(float radius,std::array<iREAL,3> position,int counter)
{

    GeometryGenerator::MeshData meshObj;
    geoGenObjects.push_back(meshObj);
    geoGen.CreateSphere(radius,30,30,meshObj,position);

    VAOIndexCounts.push_back(meshObj.Indices.size());
    glGenBuffers(2,BUFFERS);
    glBindVertexArray(VAO[counter]);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);


    glBindBuffer(GL_ARRAY_BUFFER,BUFFERS[0]);
    glBufferData(GL_ARRAY_BUFFER,
                                  meshObj.Vertices.size()*sizeof(GLfloat)*11,
                                  &meshObj.Vertices.front(), GL_STATIC_DRAW);


    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BUFFERS[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                                   meshObj.Indices.size() * sizeof(UINT),
                                   &meshObj.Indices.front(), GL_STATIC_DRAW);

    glVertexPointer(3, GL_FLOAT,sizeof(GLfloat)*11, 0);
    glNormalPointer(GL_FLOAT,sizeof(GLfloat)*11,(GLvoid*)(3*sizeof(GLfloat)));
}

Then the following function updates the buffers when it is called.

void UpdateScene(float dt, std::vector<demolish::Object>& objects)
{
    float x = radius*sinf(phi)*cosf(theta);
    float z = radius*sinf(phi)*sinf(theta);
    float y = radius*cosf(phi);


    AV4FLOAT position(x,y,z,1.0);

    AV4FLOAT target(0.0,0.0,0.0,0.0);
    AV4FLOAT up(0.0,1.0,0.0,0.0);

    viewModelMatrix = formViewModelMatrix(position,target,up);

    for(int i=0;i<objects.size();i++)
    {
        geoGen.CreateSphere(objects[i].getRad(),
                            30,
                            30,
                            geoGenObjects[i],
                            objects[i].getLocation());

        VAOIndexCounts[i] = geoGenObjects[i].Indices.size();

        glBindVertexArray(VAO[i]);
        glBufferSubData(GL_ARRAY_BUFFER,
                                0,
                                geoGenObjects[i].Vertices.size()*sizeof(GLfloat)*11,
                                &geoGenObjects[i].Vertices.front());
    }

    RedrawTheWindow();

}

The problem with this code is that it is not updating all of the buffers, only the "last" one. For instance if objects has size 3 then even if the locations of all three objects change only the last buffer is being updated with the new vertices.

I have narrowed it down to OpenGL but I am not sure what I am doing wrong.

Upvotes: 1

Views: 199

Answers (1)

Rabbid76
Rabbid76

Reputation: 211230

Binding the Vertex Array Object doesn't bind any array buffer object.
If you want to change the content of an array buffer, then you have to bind the array buffer:

GLuint VBO = .....; // VBO which corresponds to VAO[i]

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(
    GL_ARRAY_BUFFER, 0,
    geoGenObjects[i].Vertices.size()*sizeof(GLfloat)*11,
    &geoGenObjects[i].Vertices.front());

Note, a vertex array object may refer to a different array buffer object, for each attribute. So which one should be bound?

Since OpenGL 4.5 you can do this by the direct state access version too.
See glNamedBufferSubData:

glNamedBufferSubData (
    VBO, 0,
    geoGenObjects[i].Vertices.size()*sizeof(GLfloat)*11,
    &geoGenObjects[i].Vertices.front());

If the vertex array object is bound, then a named array buffer object which is bound to a binding point can be queried by glGetVertexAttribIuiv using the parameter GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:

e.g.:

glBindVertexArray(VAO[i]);
GLuint VBO;
glGetVertexAttribIuiv(0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &VBO);

Upvotes: 2

Related Questions