PDA

View Full Version : need clarifications on VAO.



Sergey Nenakhov
11-04-2011, 04:02 AM
Hi,

To me it seems that after VAO is created, you can't change anything about it, like attribute offsets or vertex buffer references.
So if I have 2VBOs with similar data, I have to create 2 VAOs to render them ? Is this correct (or I did something wrong) ?

Thanks,
Sergey.

V-man
11-04-2011, 04:10 AM
I believe you can change them but why would you want to. The reason VAO was created was "create once and use many times." and avoid GL driver side work thus possibly giving a performance boost.

Sergey Nenakhov
11-04-2011, 04:22 AM
I just don't want to create another VAO just because I have a new VBO with the same type of data, managing a set of VAOs per-buffer-per-shader-layout seems like too much hassle. And currently it seems that I can't replace a reference to buffer which was used to create VAO. If you say it is possible to change it, then I need to know how, because it doesn't work for me atm. i.e. - only the buffer which used to create vao is used, doesn't matter if I try to bind another buffer afterwards (when rendering)

FordDefect
11-04-2011, 04:40 AM
I am no expert, but when you create and bind a VAO the Binding of a VBO applies to that VAO. Then you go around setting your attribute pointers for your paticular vertex format of that VBO.

SO if you bind a different VBO whilst the VAO is still bound that VBO becomes the one associated with VAO.

I do recall in the GL SuperBible (5th ed.) where it goes into detail about using VBOs that they bind one global VAO so that you can use various VBOs.

Id imagine in your case you got two VBO one with vertex structure like position and colour and another vertex format with position, colour and texture. Your data is identical for the first two vertex elements and you just want to use an ancillary 3rd but not create another VAO just for that.

What I would do is create one VBO with the biggest vertex format and then create two VAO, one pointing out the pos,colour structure (offsets and strides) and the other VAO pos, colour and textures structure. EDIT* (I should point out that you can bind multiple VBOs to a VAO so each vertex attribute could be tightly packed in its own VBO and you just attribute pointer the required buffers).

But really I probably just use one VBO and VAO and have the two vertex program just ignore which ever input i'm not interested in (you can have 16 attribute slots).

Disclaimer: I am in no way a GL expert

aqnuep
11-04-2011, 04:44 AM
The whole point of VAO is that you don't have to make several calls to glVertexAttrib*Pointer. So using VAOs should be, at least theoretically, faster than manually switching the vertex pointers. At least it is less GL calls thus lower CPU performance penalty.

I don't quite understand why it is so difficult to carry the VAO with yourself together with the VBO. It's just an additional GLuint besides the one that you already keep track of.

Sergey Nenakhov
11-04-2011, 05:04 AM
Ok, several problematic cases I can see: using multiple shaders where each shader accesses a subset of attributes will require a different VAO ? Packing data of different type in the same VBO will require managing a separate VAO per type. Streaming into the buffer will require data offset to be multiple of the vertex stride.
By 'problematic' I mean it requires a lot of extra tracking code, making simple thing look complex in the code, not that it is not doable at all.

FordDefect
11-04-2011, 06:04 AM
Ok, several problematic cases I can see: using multiple shaders where each shader accesses a subset of attributes will require a different VAO?

No, when you linked your shader you provided it with details on
what "vertex slot" it should expect to find a paticular vertex attribute.

glBindAttribLocation(program_id, vertex_slot, "in_position");

when you use

glVertexAttribPointer(vertex_slot, 3, GL_FLOAT, GL_FALSE, vertex_stride, offset_into_vertex);

you are describing where attribute information for vertex_slot should come from within currently bound buffer.

glVertexAttribPointer(vertex_slot, 3, GL_FLOAT, GL_FALSE, dif_stride, dif_offset) will still work for the bound shader as long as vertex slot remains the same.


Packing data of different type in the same VBO will require managing a separate VAO per type.

What do you mean by type? Vertex_types or different elements?
say you have two vertex types:

Vertex_A
{
vec3 pos;
vec4 colour;
} vA;

Vertex_B
{
vec3 pos;
vec3 normal;
vec2 texture;
} vB;

You could feasibly fill a VBO with both types of data though you have to ensure that they where not inter mixed. Say we have 10 of each in the buffer first 10 Vertex_A second 10 Vertex_B and as we are using VBO we have at least go a single VAO set globally. (and so can ignore it for this example)

Two shaders one to render flat shaded, and another to diffuse light textured geometry.


to render the first 10, set flat program it expects position in slot 0 and colour in slot 1. So set the attribute pointers

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vA_stride, offset_pos_in_A);
glEnableVertexAttribArray(0);

then the colour

glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, vA_Stride, offset_colour_in_A);
glEnableVertexAttribArray(0);

Then we can draw

glDrawArrays(GL_TRIANGLES, start, 10);

To draw the remaining 10 using the other shader we have to call glVertexAttribPointer again for each attribute but using vB_Stride and offset in vB and start at 10 instead of 0 for glDrawArray().

Its much easier to do this setting in a vao once for each case and just switch between them.

glBindVertexArray();

Infact I have one VAO that sets for just Vertex_A and one that sets for just Vertex_B and have two separate VBO for each vertex type. Both will still work for flat shader as long as they both put pos into attribute slot 0, however the textured shader will look a mess as it wont have access to normal or textured coordinates if it uses data from buffer containing Vertex_A.


Streaming into the buffer will require data offset to be multiple of the vertex stride.
By 'problematic' I mean it requires a lot of extra tracking code, making simple thing look complex in the code, not that it is not doable at all.


I don't know if I have been any real help but I certainly empathise, the inter relationship between shaders, VBO and VAO
still has me unsure on building a flexible way to render various geometries using various effects.

I have taken to having a few core vertex formats, that all place common attributes in the same slot so if a vertex format has an attribute as shader that needs it can find it in that slot. If the VBO doesn't have all the data at very least the shading effect can work with what is available and use the default value GL provides on missing attribute slot.

Sergey Nenakhov
11-04-2011, 06:13 AM
Ok, I got your point, you basically build super VAO, and then rely on the driver to not fetch attributes which are not needed by a shader.

Thanks for the answers.

FordDefect
11-04-2011, 06:37 AM
Yeah pretty much, I originally saw all this as a bewildering collection of permutations every I thought I want to do some kind of effect in my engine it have to add it to all the permutations.

But then I got thinking about what I want to happen in my game engine.

what If I wanted to render my table model? Close up I like it to have lot of detail, Colour map, normal map etc.. but far away I may only want simplistic lighting and no normal mapping.

in both case lot of the model data is identical, only for the closer case I want tangential information in my vertex type and far away its not required (as I wont perform normal mapping).

So I went away and though about having the data client side and building the correct vertex stream depending on the situation. My shading class would expect a particular format and then when the model data came it would process it to the correct format bung it into a vertex cache and use it. Worked well, just every time I wanted a slightly different effect that worked on a different vertex permutation. I have to write a new shader, customise the vertex processing and cache the result server side in a VBO.

So for my table example I have one instance of the data client side containing all vertex information (for all effects) and then if two identical tables in same room one far enough not to require tangential vertex data. I would have that table server side twice.

Once with vbo for pos, texture, normal
Once with vbo for pos, texture, normal, tangential

I have to have sent this data 75% of the data over bus twice at least once. If the data was dynamic I have to do it every time it was changed.

My point is I made so much effort to save a measly 25% vertex space and an overly complicated and unwieldy method that wasn't friendly to dynamic vertex structures. If I just uploaded the full information once and kept my attribute binds consistent I have actually achieved the same and on average probably saved more space.

So know I have a few fixed vertex format that can be used by any shader, though you might not get the expected result if you mix them incorrectly.

but the table example above is one VBO and a bool on shader bDoNormal and I branch that code out. If I wanted to I could just have an ambient and diffuse shader run for the table and then additive blend just a normal mapping for the front table. But in both case I don't need to change VBO or even the VAO.