PDA

View Full Version : VAO not binding?



arablau
07-12-2012, 02:22 PM
Hi everyone,

I have code in a function called updatebuffers() that creates VAOs for me and vbos and sets the appropriate bindings I want. This function sets my global GLuint* vaos variable and generates the VAOs into it then binds them and sets up other bindings.

However, in my draw function when I try to bind vaos[0] to draw my first object, it fails to bind! Nothing else happens to my vaos variable between the code.

What can cause a VAO to not bind? I have found difficulty separating certain OpenGL setup calls into separate functions without breaking code that previously rendered just like this problem.

Thanks for any help with this.

My updatebuffer code to set up my VAOs and VBOs for my geometries:


void UpdateBuffers()
{
std::cout << "\nInitializing buffers...\n";
// Create a VAO for each geometry
vaos = new GLuint[geometry_count];
glGenVertexArrays(geometry_count, &vaos[0]);
std::cout << "\nCreating vaos: " << geometry_count << std::endl;
ExitOnGLError("ERROR: Could not generate VAOS");


// Create 3 VBOs for each geometry
// Position, Normals, Texture Coords
vbos = new GLuint[3 * geometry_count];
glGenBuffers(3 * geometry_count, &vbos[0]);
ExitOnGLError("ERROR: Could not generate VBOS");


// Configure VBOs to hold data
GLuint attrib_location;
int index = 0;
std::cout << "Looping through geometries\n";
for(geometries_it = geometries.begin(); geometries_it != geometries.end(); geometries_it++)
{
std::cout << "configuring geometry " << index << " with vao: " << vaos[index] << std::endl;


glBindVertexArray(vaos[index]);
ExitOnGLError("ERROR: Could not bind the VAO for setup purposes");


// Set vertex position data
glBindBuffer(GL_ARRAY_BUFFER, vbos[3 * index]);
glBufferData(
GL_ARRAY_BUFFER,
(*geometries_it).second.vertices.size,
(*geometries_it).second.vertices.data,
GL_STATIC_DRAW);


attrib_location = glGetAttribLocation(current_program, "in_coords");
glVertexAttribPointer(
attrib_location,
(*geometries_it).second.vertices.stride,
(*geometries_it).second.vertices.type,
GL_FALSE,
0,
0);
glEnableVertexAttribArray(0);


// Set normal vector data
glBindBuffer(GL_ARRAY_BUFFER, vbos[3 * index + 1]);
glBufferData(
GL_ARRAY_BUFFER,
(*geometries_it).second.normals.size,
(*geometries_it).second.normals.data,
GL_STATIC_DRAW);


attrib_location = glGetAttribLocation(current_program, "in_normals");
glVertexAttribPointer(
attrib_location,
(*geometries_it).second.normals.stride,
(*geometries_it).second.normals.type,
GL_FALSE,
0,
0);
glEnableVertexAttribArray(1);


// Set texture data
}


glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}


And then my render function:


void DrawCursor()
{
std::cout << "Drawing cursor." << std::endl;


int index = 0;
/* Draw all parts of the cursor */
for(geometries_it=geometries.begin() ; geometries_it != geometries.end(); geometries_it++)
{
std::cout << "Drawing: " << (*geometries_it).second.id << std::endl;


//ModelMatrix = (*it).second.model_matrix;


ModelMatrix.identity();
/* Position and rotate the cursor */
/* Rotate cursor. */
matrix_rotate_about_local_axis(ModelMatrix, 0, ((float) cursor_angle[0]));
matrix_rotate_about_local_axis(ModelMatrix, 1, ((float) cursor_angle[1]));
matrix_rotate_about_local_axis(ModelMatrix, 2, ((float) cursor_angle[2]));


/* Position cursor. */
//matrix_set_translation(ModelMatrix, cursor_position[0], cursor_position[1], cursor_position[2]);


glBindVertexArray(vaos[index]);
ExitOnGLError("ERROR: Could not bind the VAO for drawing purposes");


glUniformMatrix4fv(ModelMatrixLoc, 1, GL_FALSE, ModelMatrix.data());
ExitOnGLError("ERROR: Could not set the shader uniforms");


int num_elements = (*geometries_it).second.vert_indices.count;
std::cout << "Number of indices for this object: " << num_elements << std::endl;

glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_INT, (GLvoid*)0);
ExitOnGLError("ERROR: Could not draw the cube");


glBindVertexArray(0);
glUseProgram(0);
index++;
}
}

Dan Bartlett
07-12-2012, 03:05 PM
I don't know whether they are just copy-paste errors, but here's a few errors:

1) "index" is always 0 in
UpdateBuffers(), so only the first VAO gets initialized
2) If you're querying attribute locations, rather than setting them explicitly, you should be using
glEnableVertexAttribArray(attrib_location) instead of glEnableVertexAttribArray({0 or 1});
3) In DrawCursor(), you call glUseProgram(0) at the end of the first loop, but don't appear to set it to a valid program anywhere else.

arablau
07-12-2012, 03:19 PM
Thank you for pointing those out!!

The index being always 0 in updatebuffers isn't a problem now since I am only trying to draw one object. There is only one geometry in my geometry map.

It seems I mixed up some things I've picked up from various tutorials,
If in my vertex shader I define inputs like this:

layout(location=0) in vec4 in_coords;
layout(location=1) in vec4 in_normals;

Does that mean that in glEnableVertexAttribArray() I can pass 0 and 1 because I have set those locations explicitly? Is that what layout(location = X) does?

If I define the vertex shader inputs without the layout(location=0) in front, do I then have to query for their locations and use that?

Upon further investigation I discovered that the error was actually coming from glVertexAttribPointer. Apparently, the index I passed it was larger than GL_MAX_VERT_ATTRIBS so it fails.
Is this a result of my confusions above and can anyone explain this to me?

Thank you all!

EDIT: Ok, I think I was being an idiot and setting in_normals as an input to my vertex shader when I want it as an input for my fragment shader. I haven't learned about lighting yet so I am not touching it yet, but glGetAttribLocation gives me a REALLY LARGE NUMBER when I call it on in_normals. It gives me 0 when I call it on in_coords which I think is correct. What could be going wrong with the in_normals input?

Dan Bartlett
07-12-2012, 06:30 PM
Thank you for pointing those out!!

The index being always 0 in updatebuffers isn't a problem now since I am only trying to draw one object. There is only one geometry in my geometry map.

It seems I mixed up some things I've picked up from various tutorials,
If in my vertex shader I define inputs like this:

layout(location=0) in vec4 in_coords;
layout(location=1) in vec4 in_normals;

Does that mean that in glEnableVertexAttribArray() I can pass 0 and 1 because I have set those locations explicitly? Is that what layout(location = X) does?

If I define the vertex shader inputs without the layout(location=0) in front, do I then have to query for their locations and use that?

Yes, although if the location isn't specified in the shader, you can still explicitly set the location for attributes using glBindAttribLocation prior to linking the shader program. See http://www.opengl.org/wiki/GLSL_Type_Qualifiers#Vertex_shader_attribute_index

If you do specify the location in the shader, you can use 0 and 1 for glVertexAttribPointer / glEnableVertexAttribArray and no need to call ​glBindAttribLocation (http://www.opengl.org/wiki/GLAPI/glBindAttribLocation) / glGetAttribLocation at all, unless you're checking if an attribute has been optimised away, in which case the location query would return -1. If you don't specify the location of the attribute in the shader or with glBindAttribLocation, you can just query with glGetAttribLocation to see whatever index OpenGL assigned you.



Upon further investigation I discovered that the error was actually coming from glVertexAttribPointer. Apparently, the index I passed it was larger than GL_MAX_VERT_ATTRIBS so it fails.
Is this a result of my confusions above and can anyone explain this to me?

Thank you all!

EDIT: Ok, I think I was being an idiot and setting in_normals as an input to my vertex shader when I want it as an input for my fragment shader. I haven't learned about lighting yet so I am not touching it yet, but glGetAttribLocation gives me a REALLY LARGE NUMBER when I call it on in_normals. It gives me 0 when I call it on in_coords which I think is correct. What could be going wrong with the in_normals input?


glGetAttribLocation returns a GLint not a GLuint, so if you were to declare attrib_location as a GLint, you'd probably find that large number is -1, which usually means the attribute has been optimised away, or was misspelt/doesn't exist. If you do get -1 for an attribute location, then you shouldn't plug this straight into the GLuint index argument of glVertexAttribPointer, or it will get interpreted as a value > GL_MAX_VERTEX_ATTRIBS.

arablau
07-12-2012, 06:40 PM
You are amazing. Thank you so much.
I have those problems worked out now and there are no more errors but instead of getting my object to render I get a white screen now.

Which is strange because my clearscreen color is black, and in my fragment shader I set the output color to always be red just so I can clearly see if I can render this object.
I'll have to take a look and see what could be happening.
Thank you so much for your help!

drmz0counting
07-16-2012, 01:44 PM
Can you post your vertex and fragment shader code?

arablau
07-16-2012, 07:22 PM
I actually have it all figured out!
I can load COLLADA files and display them nicely. Plus I have a camera that can revolve around the model I loaded!
YAY for learning OpenGL!

I do have some more questions though.

I have a surgical tool I've modeled. It is made up of different pieces.
I exported it to .dae and the load it up in my program and display it.
In the .dae file, each piece is in its own "geometry" node.
To make things easy as a beginner, I made a VAO for each piece and VBOs to store the vertices and indices that I read in. Then I read in the model matrix to transform the piece correctly and now I can draw them all and they are in the right place relative to each other.
However, they are all separate pieces, each with its own vao, vbo, vertex data, indices, model matrix, etc.

What would be a good approach to organizing the pieces of one complete model so that I can move them all together as one and still be able to apply matrices to individual pieces for animation, etc?

I am thinking of letting each model be a map from the string id of the piece to the piece geometry data that I store in my own data structure.
Then all of the big geometries in my scene will be maps from strings to the piece.
I could then apply a transformation across a whole map to each piece to move a whole object together. I could have access to each piece of an object. At the same time, I could control different objects.
Does this sound reasonable or would it be too slow / memory wasteful?
What are some approaches I can take?

Thanks again

blm768
07-16-2012, 08:05 PM
What would be a good approach to organizing the pieces of one complete model so that I can move them all together as one and still be able to apply matrices to individual pieces for animation, etc?
Thanks again

I'm not much of an expert, but the method I plan to use in my own code is to store members of groups as items in a linked list, but that's not always the most convenient method because I can't pull out items by name.

I assume you're looking for something like:


scene.objects["scalpel"].objects["blade"].rotateBy(someRotationMatrix);


Hash tables would do that quite nicely, but they're not as fast as some other methods. They'll probably work for smaller scenes, but you'll want a linked list or array for larger ones.

Another option would be to store a group's children in both a linked list and a hash table. That way, you could still pull out elements by name, but looping over the elements would be faster than if you were using just a hash table. Of course, this will slow down insertion and deletion a bit, but it's unlikely that you will be doing that as much as iterating over the objects.

Another thing you could try is to just hard-code references to the objects where needed:



Mesh blade;
Mesh handle;
Group scalpel;
scalpel.add(blade);
scalpel.add(handle);
blade.rotateBy(someRotationMatrix);


You could also create hash tables for just the elements you really need to reference by strings and stash them in a variable somewhere.

Ultimately, you'll just have to try out various combinations and see what balances ease-of-use with speed for your particular needs. The third and fourth suggestions will probably be the fastest.