user813022
user813022

Reputation:

Fishy glGetAttribLocation returns -1

I'm trying to use a shader program that consists of two shaders.

Ortho.vert:

uniform vec2 ViewOrigin;
uniform vec2 ViewSize;

in vec2 Coord;

void main ()
{
  gl_Position = vec4((Coord.x - ViewOrigin.x) / ViewSize.x,
                     1.0f - (Coord.y - ViewOrigin.y) / ViewSize.y,
                     0.0f, 1.0f);
}

Tiles.frag:

uniform sampler2D Texture;
uniform sampler2D LightMap;

in vec2 TextureCoord;
in vec2 LightMapCoord;

void main ()
{
  vec4 textureColor  = texture2D(Texture, TextureCoord);
  vec4 lightMapColor = texture2D(LightMap, LightMapCoord);

  gl_FragColor = vec4(textureColor.rgb * lightMapColor.rgb, 1.0f);
}

glGetAttribLocation is returning -1 for TextureCoord and LightMapCoord. I've read about instances where the compiler optimizes away attributes that aren't used, but in this example you can see that they are clearly used. Is there something about the OpenGL state (glEnable, etc.) that is required in order to enable samplers? I'm not sure what else could be wrong here. Any help is appreciated.

Upvotes: 0

Views: 108

Answers (1)

Reto Koradi
Reto Koradi

Reputation: 54642

Attributes cannot go directly into the fragment shader. Their full name is vertex attributes, which means that they provide values per vertex, and are inputs to the vertex shader.

Fragment shaders can have in variables, but they do not correspond to vertex attributes. They need to match up with out variables of the vertex shader.

So what you need to do to get this working is to define the attributes as inputs to the vertex shader, and then pass the values from the vertex shader to the fragment shader. In the vertex shader, this could look like this:

uniform vec2 ViewOrigin;
uniform vec2 ViewSize;

in vec2 Coord;
in vec2 TextureCoord;
in vec2 LightMapCoord;

out FragTextureCoord;
out FragLightMapCoord;

void main ()
{
    gl_Position = vec4((Coord.x - ViewOrigin.x) / ViewSize.x,
                       1.0f - (Coord.y - ViewOrigin.y) / ViewSize.y,
                       0.0f, 1.0f);
    FragTextureCoord = TextureCoord;
    FragLightMapCoord = LightMapCoord;
}

Then in the fragment shader, you declare in variables that match the out variables of the fragment shader. These variables will receive the per-fragment interpolated values of the what you wrote to the corresponding out variables in the vertex shader:

uniform sampler2D Texture;
uniform sampler2D LightMap;

in vec2 FragTextureCoord;
in vec2 FragLightMapCoord;

void main ()
{
    vec4 textureColor  = texture2D(Texture, FragTextureCoord);
    vec4 lightMapColor = texture2D(LightMap, FragLightMapCoord);

    gl_FragColor = vec4(textureColor.rgb * lightMapColor.rgb, 1.0f);
}

Having to receive the attribute values in the vertex shader, and explicitly passing the exact same values through to the fragment shader, may look cumbersome. The important thing to realize is that this is just a special case of a much more generic mechanism. Instead of simply passing the attribute value directly to the out variable in the vertex shader, you can obviously apply any kind of computation to calculate the values of the out values, which is often necessary in more complex shaders.

Upvotes: 1

Related Questions