Vertex Attributes, VAOs and Shaders

Started by
2 comments, last by larspensjo 11 years, 10 months ago
I'm trying to come up with a clever abstraction for shaders for my project and I'm stumbling on this issue concerning VAOs. So, when you've got a shader bound and you want to bind a VBO for rendering you ask the shader for the location of each attribute your VBO contains data for. This way it's just a step when you're binding a VBO / Shader, correct? If I've got this part right, then where do VAOs fit in with their ability to essentially cache the operations necessary to bind a VBO? To clarify, say I've got ShaderA bound, and I set up a VAO that records what is necessary to bind a VBO. I find out from the shader that "position" is at location 1, "color" is at location 2 and "normal" is at location 3. When I call glEnableVertexAttribute and similar operations, the VAO is recording simply the integer value going into these functions (1, 2, or 3 in this example) not the fact that I've queried the current shader to find out where they actually are. So now if I swap ShaderA for ShaderB and bind that same VAO for drawing, but ShaderB happens to have "position", "color" and "normal" at 2, 3, and 1 respectively, the VAO is going to bind the data in the wrong order and mess everything up.

All I can think of is to statically enforce the location of vertex attributes in the shader code, but this seems like the wrong thing to do. Is this my only option?
Advertisement
You are correct. If you have two different shaders with differently bound input attribute positions, you can't use the same VAO to render with both shaders.

What I do is I make all my shader programs to use a compatible layout that are intended to be used with the same VAO. A compatible layout can have extra stuff, i.e program with { index0: pos, index1: normal, index2: uv} and a program with { index0: pos, index1: normal} are compatible, since the common portion of them is identical. I have a function AreCompatible(ShaderProgram, VAO) that checks the objects that the VAO and shader program agree with the stored state. This check is enabled at debug time and it yells red text in the console if not. That way I can manually author my shader programs and VAOs to use a common structure wherever necessary, and in release mode, the checks don't exist and there is no overhead.

So, essentially, in my case, I am able to get around the potential problems by rules of convention.

So, essentially, in my case, I am able to get around the potential problems by rules of convention.


Heh, I was just coming back here to update and say that I spent the last hour or so implementing a static system just to see how it worked out, and I think I like it.

Like I said before, it was clever to be able to do it dynamically with hash maps of attribute names and locations but not being able to use VAOs was a huge strike against it. The new code is also simpler. I'm glad to see someone else taking this approach as well as it gives me confidence that this is viable (not that I saw many other options like I said).

I'm still interested in any other opinions / techniques people have got though!
There are a couple of ways to achieve this.

One way is to use the "layout" specifier, and use a convention to make sure it is always the same. Another way is to have the layout declaration in a common string, that is included into the shaders before they are compiled. That way, you only have one common source.

Another way, which is compatible with OpenGL 3.0, is to tell OpenGL the locations in the compilation process of the shader (glBindAttribLocation I think it was). You have to do this before the linkage phase. I use this method, using a common base class with a callback function.
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

This topic is closed to new replies.

Advertisement