-1

I'm writing a 2D game in OpenTK, using OpenGL 4.4. Using colour and texture UV coordinates and a matrix I can succesfully draw textures between vertices with vertex shader:

public const string vertexShaderDefaultSrc = @" #version 330

        uniform mat4 MVPMatrix;

        layout (location = 0) in vec2 Position;
        layout (location = 1) in vec2 Texture;
        layout (location = 2) in vec4 Colour;

        out vec2 InTexture;
        out vec4 OutColour;

        void main()
        {
            gl_Position = MVPMatrix * vec4(Position, 0, 1);
            InTexture = Texture;
            OutColour = Colour;
        }";

and fragment shader:

public const string fragmentShaderDefaultSrc =
    @"
    #version 330

    uniform sampler2D Sampler;

    in vec2 InTexture;
    in vec4 OutColour;

    out vec4 OutFragColor;

    void main()
    {
        OutFragColor = texture(Sampler, InTexture) * OutColour;

        //Alpha test
        if(OutFragColor.a <= 0) 
            discard;
    }
    ";

BUT if I want to draw just a solid colour rather than a texture, I use this shader (with the same vertices, passing UV coords that won't be used):

 public const string fragmentShaderSolidColourSrc =
    @"
    #version 330

    uniform sampler2D Sampler;

    in vec2 InTexture;
    in vec4 OutColour;

    out vec4 OutFragColor;

    void main()
    {
        OutFragColor = OutColour;

        //Alpha test
        if(OutFragColor.a <= 0) 
            discard;
    }
    ";

Now this works beautifully, but OpenGL reports an error - GL_INVALID_VALUE. It draws fine and everything seems to work, but ideally I would like OpenGL to be error free in that situation, so I can catch real errors. I would appreciate any help, and can share more detail of how the shader is compiled or used if that is helpful - what I don't understand is how the default shader can work but the solid colour doesn't.

I have tracked down the exact source of the errors in my render call (shader builds with no problems)

GL.EnableVertexAttribArray(shader.LocationPosition);
        GL.VertexAttribPointer(shader.LocationPosition, 2, VertexAttribPointerType.Float, false, Stride, 0);
        //-----everything up to here is fine

        //this line throws an error
        GL.EnableVertexAttribArray(shader.LocationTexture);
        //as does this line
        GL.VertexAttribPointer(shader.LocationTexture, 2, VertexAttribPointerType.Float, false, Stride, 8);


        //this is all ok
        GL.EnableVertexAttribArray(shader.LocationColour);
        GL.VertexAttribPointer(shader.LocationColour, 4, VertexAttribPointerType.UnsignedByte, true, Stride, 16);

        //ok
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);
        GL.DrawArrays(DrawType, 0, Vertices.Length);

        //ok
        GL.DisableVertexAttribArray(shader.LocationPosition);

        //this line throws error
        GL.DisableVertexAttribArray(shader.LocationTexture);

        //this is ok
        GL.DisableVertexAttribArray(shader.LocationColour);
Mr Pie
  • 327
  • 2
  • 11
  • When does OpenGL report the error ? Shader compilation ? Shader linking ? Binding ? Drawing ? Can you provide the code surrounding the error ? – Guillaume Gris Jun 27 '15 at 16:57
  • Edited to show exact source of error (in rendering). – Mr Pie Jun 27 '15 at 19:57
  • This would suggest that shader.LocationTexture has an invalid value. You should check the line where you initialize it. Otherwise, if you don't need texture, you don't need texture coordinates either. – Guillaume Gris Jun 27 '15 at 20:35
  • 1
    Some (all?) OpenGL implementations don't like unused uniforms and you don't reference `Sampler` in your second shader variant. – n0rd Jun 29 '15 at 23:29

1 Answers1

0

It appears to me after some tests (would be nice to have this verified) that if a variable such as the texture coordinates are not used by the shader the compiler gets rid of it, so a call to get it's location returns -1. Simply checking if locationTexture was -1 here and then not binding locationTexture etc if so resolved my issues.

Mr Pie
  • 327
  • 2
  • 11
  • 1
    Yes, that is exactly the case. Only _active_ attributes (same for uniforms) do have a location. The shader compilers/linkers are typically very aggressive in optimizing out everything which does not influence the final outputs. Note that for uniforms, setting a uniform with location -1 is explicitely defined as not an error (it is just silently ignored), but for attributes, this is different. The location you can query is a signed int and might be -1, but the index for the vertex attrib functions is unsigned, and using indices outside the [0, max_attrib-1] range is always an error. – derhass Jun 29 '15 at 23:40