Passing multiple Vertex Attributes in GLSL 130

(note this question is closely related to this one however I didn't fully understand the accepted answer)

To support videocards in laptops I have to rewrite my GLSL 330 shaders to GLSL 130. I'm trying to do this but somehow I don't get vertex attributes to work properly.

My 330 shaders look like this:

#version 330
layout(location = 0) in vec4 position;
layout(location = 3) in vec4 color;

smooth out vec4 theColor;
void main()
{
gl_Position = position;
theColor = color;
}


Now this explicit layout is not allowed in GLSL 130 so I referenced this page to see what the default layouts for some values would be. As you can see position should be the 0th vertex attribute and color should be the 3rd vertex attribute. Because this is a test case I had already configured my explicit layouts in the same way, which worked, so I now simply rewrote my shader to this and expected it to work:

#version 130
smooth out vec4 theColor;
void main()
{
gl_Position = gl_Vertex;
theColor = gl_Color;
}


However this doesn't work, the value of gl_Color is always (1,1,1,1). So how should I pass multiple vertex attributes to my GLSL 130 shaders?

For reference, this is how I set my vertex buffer object and attributes (I've just adapted this tutorial to JAVA+JOGL)

gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vertex_buffer_id);
gl.glEnableVertexAttribArray(0);
gl.glEnableVertexAttribArray(3);
gl.glVertexAttribPointer(0, 4 , GL3.GL_FLOAT, false, 0, 0);
gl.glVertexAttribPointer(3, 4, GL3.GL_FLOAT, false, 0, 4*4*4);

gl.glDrawArrays(GL3.GL_TRIANGLE_STRIP, 0, 4);

gl.glDisableVertexAttribArray(0);
gl.glDisableVertexAttribArray(3);


EDIT I solved the problem by querying for the layout locations of position an color using glGetAttribLocation however I still don't understand why the 'hardcoded' values like gl_Color didn't work, can't I upload data in there as normal? Shouldn't they be used?

• The preamble in () deserves an upvote on its own ;) – mlvljr Aug 9 '14 at 21:23

gl_Color is for the deprecated fixed function context. It's set up when you call the glColor* functions. If you want to set it, you have to use the fixed function pipeline, otherwise gl_Color will have the default value, which is white opaque.

You used GLSL version 330 which means you should've been using OpenGL version 3.3 which uses the core specification (glColor* functions are deprecated; GLSL version 330 doesn't have gl_Color). Your code should be set up for the programmable pipeline with pure shaders (the code you posted is that exactly), which means you can't call glColor* thus can't set gl_Color in the shader. If you want to use the programmable pipeline then you shouldn't be using gl_Color.

Post which version of OpenGL you're using for the GLSL 130 version and some code if what i said didn't satisfy the answer.

• Hey Dreta I'm using VertexBufferAttribute so indeed I'm using OpenGL3. I thought gl_Color was just mapped to the 3rd vertex attribute in the shader, but that is not the case? So in OpenGL 3 I should always check where something is stored in the shader using glGetAttribLocation? – Roy T. Nov 4 '12 at 16:27
• @RoyT. The layout location feature was introduced in OpenGL 3.3 (GLSL 330), so you should retrieve (or bind) attribute locations from your program if you're using anything older than that, this includes OpenGL 3.0 (GLSL 130). As for gl_Color being bound to attribute 3, according to the specification this isn't allowed, NVidia however has a record of using gl_Vertex for attribute 0, gl_Color for attribute 3, etc. but it's against the specification and shouldn't be relied on. – dreta Nov 4 '12 at 17:29
• @RoyT. The fact that NVidia drivers act as they do, means you shouldn't bind attribute locations explicitly with glBindAttribLocation, unless necessary. This may cause conflicts as described here stackoverflow.com/questions/6628007/… just stick to glGetAttribLocation. – dreta Nov 4 '12 at 17:32
• Ah together with those 2 comments this was exactly what I wanted to know, thanks! – Roy T. Nov 4 '12 at 17:36

This:

layout(location = 0) in vec4 position;
layout(location = 3) in vec4 color;


is simply the nice form of this:

//GLSL
in vec4 position;
in vec4 color;

GLuint prog = glCreateProgram();
glBindAttribLocation(prog, 0, "position");
glBindAttribLocation(prog, 3, "color");
...


So rather than mucking about with built-in vertex attributes like gl_Position and such, just do that. Indeed, you can build up an entire naming convention scheme using glBindAttribLocation. The best part is that you can bind any name to any location, even if that name never appears in your shader. It will simply be ignored by OpenGL.

So you can have a standard set of naming-to-attribute location mappings somewhere that you use for every program. Just apply this mapping as part of your program setup before linking, and you get the behavior you want.

And even better, you can keep doing this even when you work in GLSL 3.30 and layout(location) syntax. See, layout(location) has precedence, so it overrides any glBindAttribLocation calls. So they'll just be ignored.

Most importantly, DO NOT USE glGetAttribLocation. Always directly specify your attribute indices, either with layout(location) or with glBindAttribLocation.

I would have thought the reason for this was obvious (since it's the same reason to use layout(location) to begin with). But since some asked...

By specifying attribute locations, you create a convention for your attributes. Positions are always attribute 0. Colors are always attribute 1. Or whatever. You establish a convention and you maintain it.

This now means that when it comes time to load, setup, and render your models, your glVertexAttribPointer calls can use the convention without having to know which program they use. glVertexAttribPointer is known for many things; speed is not one of them. So you want to make as few calls to it as possible.

This means packing multiple objects in the same buffer(s) and using glDrawArrays and/or glDrawElements[BaseVertex] to draw different segments of the buffer(s). Each draw call represents an object. But they don't have to use the same program.

If you switch programs without an established attribute convention, now you need to use glGetAttribLocation (a function who's performance is unknown) and glVertexAttribPointer for each attribute for each object in the buffer. Rather than just doing it once for all of the objects and rendering each one in turn.

Plus, it makes everything cleaner. Your mesh objects can make the necessary glVertexAttribPointer calls they need without having to know what program they use. There's no reason why a mesh should need to know what program it will be rendered with.

The NVIDIA Problem

This somewhat overblown. Indeed, I advise you to ignore pretty much all of the documentation on the "OpenGL SDK" page on OpenGL.org, except for the actual man pages (and even some of those are wrong).

You cannot rely on gl_Position to have a particular attribute index. Indeed, the OpenGL specification is quite clear that gl_Position does not have an attribute index. NVIDIA's implementation is in violation of the specification by giving it an attribute index that can conflict with user-defined indices. Non-NVIDIA implementations (aka: those that actually follow the specification) don't do this.

But this is an easily avoidable problem. Never use any of the built-in attributes. Then you won't have a problem.

• is there anything wrong with GetAttribLocation or is it just that it fails as a method when working with VAOs (for example when you ommit an attribute in a shader) – dreta Nov 4 '12 at 20:19
• Yes the emphasis on not using glGetAttribLocation is missing an explanation. I would very much like to know what is wrong with it. Although binding might be even nicer. But since location has precedence will binding give me problems on nVidia hardware? For example if a bind color to 3. Will it stick on nVidia hardware even though it clashes with their gl_Color? – Roy T. Nov 4 '12 at 20:41
• @RoyT.: As I said, "Never use any of the built-in attributes." Then nothing will clash with anything, even on NVIDIA's "implementation". – Nicol Bolas Nov 4 '12 at 20:47
• @dreta: I thought it was pretty self-explanatory, but since you asked, I added one. – Nicol Bolas Nov 4 '12 at 21:00
• Thanks for expanding your answer which now makes it hard to choose between two great answers! Thanks for clearing up the glGetAttriblocation stuff, I hadn't thought of the case where I use multiple shaders which will certainly happen so I'll get rid of it. – Roy T. Nov 4 '12 at 21:48