6
\$\begingroup\$

I would like to present here my Question about VBOs and VAOs. Basically from what i understand you can have different VAOs each of which can contain up to several VBOs , and by binding to the VAO's ID you can draw from the VBOs stored inside.

I have Wrote a simple class that reads a obj file then creates vertices, normals and uvs vector lists and upload those in 3 VBOs (vboID 1,2 and 3)

void Model::loadToVBO()
{
glGenVertexArrays(1, &vaoID);
glBindVertexArray(this->vaoID);

glBindBuffer(GL_ARRAY_BUFFER, vertexID);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size()*sizeof(vec3), &this->vertices[0], GL_STATIC_DRAW);  


glBindBuffer(GL_ARRAY_BUFFER, normalID);
glBufferData(GL_ARRAY_BUFFER, this->normals.size()*sizeof(vec3), &this->normals[0], GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, uvcoordID);
glBufferData(GL_ARRAY_BUFFER, this->uvs.size()*sizeof(vec2), &this->uvs[0],      GL_STATIC_DRAW);

glBindVertexArray(0);
}

if I do that in the render function i try to Bind to vaoID , and draw elements , but it would not work. To make it work i have to RELOAD vbo data every frame in Render Function (that happens because i have 2 models each model's constructor calls loadVBO , and obviously the second model overrides the first vbo's 1,2 and 3 ID positions(i was assuming that the vao generated from the first object will be entirely separate from the vao generated from the second model and each vao will have its own 3 VBOs). So maybe my code doesnt setup VAOs properly. Was reading something about how glEnableVertexAttribArray and glVertexAttribPointer are used to set up current vbo state into vao , but could not understand it really well. Maybe because i use the same functions to bind to shaders variables ....

This code below is in the shader class and it loads the vbo data into shader's variables

void StaticShader::loadAttribute(GLuint bufferID, string variable, GLuint size)
{
GLuint variableID;
variableID = glGetAttribLocation(this->shaderProgramID, variable.c_str());
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glEnableVertexAttribArray(variableID);
glVertexAttribPointer(variableID, size, GL_FLOAT, GL_FALSE, 0, 0);
}

The Model Render Functions looks like that. The loadToShader function loads: all model matrices + vertices + normals + uvs This function calls the function loadAttribute for v, n and uvs ( i assume thats not where its supposed to be ... maybe)

void Model::Render()
{
glBindVertexArray(vaoID);
//loadToVBO();
loadToShader();
glDrawArrays(GL_TRIANGLES, 0, this->vertices.size());
glBindVertexArray(0);
}

My question is - Is it Bad (performance wise) to load VBO data every time render is called (i assume YES). Second part - Should i reload model data(meaning v/n/uvs) in shader every time its called to be rendered ?

\$\endgroup\$
  • \$\begingroup\$ It looks right to me -- glBindVertexArray(this->vaoID); should have its own independent VBO ID position, like you say. I think your ::Render should be able to have glBindVertexArray(id), draw, glBindVertexArray(0) just like you want. Not sure why it's not working for you that way. \$\endgroup\$ – david van brink Mar 22 '15 at 0:45
4
\$\begingroup\$

Yes, sending your mesh data to the GL every time you render it would be very wasteful. You should only be doing that if your data has changed from one frame to another (e.g. you are computing animations in the CPU). Otherwise, you shouldn't have to re-submit data if the model/mesh was not changed.

Apparently, the problem with your program is that you are not setting the vertex layout when the VAO is created. Usually, the workflow of VAOs is:

  • On initialization:

    1. Create the VAO and bind it;

    2. Create buffers, bind them and submit data with glBufferData/glMapBuffer;

    3. Set vertex layout with glEnableVertexAttribArray and glVertexAttribPointer;

    4. Optionally unbind the VAO and buffers to avoid programming errors.

  • On rendering:

    1. Bind the VAO;

    2. Issue the draw call(s);

    3. Optionally unbind the VAO to avoid programming errors.

So the fix for your problem might be achieved rearranging the calls to glVertexAttribPointer. I see that you are querying the attribute locations from the shader. You might wish to specify your own locations with glBindAttribLocation before compiling the shader, to make things simpler. Another even better option is directly specifying the locations in shader code using the layout(location) qualifier. You'll have to check if the latter is available in your version of GLSL.

\$\endgroup\$
  • \$\begingroup\$ What i ultimately did today is to set the Model Data (vertices + normals + uvs in a single VBO) , for every model i generate unique VBO and when i want to render the Model in Question i just bind to its VBO ID , Data in VBO is loaded once after i read from the model's file. Is that a good practice ? Also i was wondering: should i reload the uniform variables(matricies + sampler2Ds + some light data) in the shader every frame (as i was doing up until now , is it how its done ? I assume yes because i should load Different model matrices and texture for each model rendered) \$\endgroup\$ – user2742982 Mar 22 '15 at 11:44
  • \$\begingroup\$ @user2742982, yes, you should be able to draw without a VAO. The VAO is actually meant more as an optimization. You don't need to reset the shader uniforms that don't change. The states remain valid even after the shader is unbound, so only update the ones that have changed. \$\endgroup\$ – glampert Mar 22 '15 at 17:34
  • \$\begingroup\$ Well there is only one that does not change and its the Projection Matrix and light direction and color(maybe). the sampler , view and model matrices change for every frame so i should keep updating ? (does it cost a lot of CPU resources to upload them to the shader ?) \$\endgroup\$ – user2742982 Mar 22 '15 at 17:38
  • \$\begingroup\$ @user2742982, for the uniform variables that change every frame, you really don't have a choice but updating them. The question if it is expensive or not is relative. If you are doing only a handful of updates each frame, that wont ever become a bottleneck in your application. In the future, if you need to optimize that, then you can look into uniform buffers. \$\endgroup\$ – glampert Mar 22 '15 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.