Kelvin Bongers
Kelvin Bongers

Reputation: 197

GLSL Setting Texture Unit Uniform Problems

Edit: I changed GLTextureUnitID from a uint to an int, and it caused the error to stop appearing, but instead of the texture, a black square renders. When I comment out the call to SetTexture it still renders fine even though I never set that uniform before that line.

Edit2: It appears GLTextureUnitID has a value of 1, while the texture that is being set has an ID of 0.

Edit3: Changing the SetTexture function to have the following seems to have solved the problem, but it feels like a bit of a dirty solution.

GL.BindTexture(TextureTarget.Texture2D, (int)texture.GLTextureUnitID);
GL.Uniform1(GLTextureUnitLocation, 0);

Original Question: I started adding support for texture files to my project but whenever I call GL.Uniform1 for my textured shader program, I get an "InvalidOperation" error. Ever stranger, when I comment out the call to the function that causes the error, the texture still gets rendered.

The RenderGUI function in which the quad with a texture is being rendered is:

    public override void RenderGUI()
    {
        // Translate Matrix to Position of GUI Element
        Matrices.Translate(SetMatrixParam.ModelViewMatrix, Position.X, Position.Y, 0);

        // Bind Shaders and Send Matrices
        Shader.Bind();
        Shader.SendMatrices();

        // Set Texture Information
        Shader.SetTexture(Texture); // <- This causes the error, it's just a call to Uniform1 using a property from the texture object, if commented out the error doesn't appear.
        Shader.SetTextureColor(Color4.White);

        GL.Begin(BeginMode.Triangles);

        // Render Quad
        Vector3 topLeft = new Vector3(0, 0, 0);
        Vector3 bottomLeft = new Vector3(0, Size.Y, 0);
        Vector3 topRight = new Vector3(Size.X, 0, 0);
        Vector3 bottomRight = new Vector3(Size.X, Size.Y, 0);

        Shader.SetTextureCoord(0, 0); GL.Vertex3(topLeft); // Top Left
        Shader.SetTextureCoord(0, 1); GL.Vertex3(bottomLeft); // Bottom Left
        Shader.SetTextureCoord(1, 1); GL.Vertex3(bottomRight); // Bottom Right

        Shader.SetTextureCoord(0, 0); GL.Vertex3(topLeft); // Top Left
        Shader.SetTextureCoord(1, 1); GL.Vertex3(bottomRight); // Bottom Right
        Shader.SetTextureCoord(1, 0); GL.Vertex3(topRight); // Top Right

        GL.End();
    }

And the function that's being called that's causing an error to appear:

    public void SetTexture(Texture2D texture)
    {
        if (texture.GLTextureUnitID == null)
            throw new ArgumentException();

        GL.Uniform1(GLTextureUnitLocation, (uint)texture.GLTextureUnitID);
    }

This can also be found at the github for this project. along with the Texture2D class and the vertex and fragment shader being used and the class handling the shader program that uses those shaders.

Upvotes: 3

Views: 1942

Answers (2)

Ming
Ming

Reputation: 69

In order to bind a texture to a program's uniform slot, you will need:

  1. the gl-name of the texture which is returned from glGenTextures
  2. the uniform location returned from glGetUniformLocation
  3. a texture unit to bind the texture (it should be decided by your system; usually depending on how many textures are needed to bind to the shader)

In your texture class, I think you have mixed up the texture-unit and the gl-name.

And the followings is the pseudo code for texture binding

Int32 texunit = 0; // assume your shader only have 1 texture-type uniform
Shader.Bind();
GL.Uniform1( Shader.GetUniformLocation( "uniformName" ), texunit );
GL.ActiveTexture( texunit );
GL.BindTexture( TextureTarget.Texture2D, (int)tex.GLTextureUnitID ); // I recommend renaming tex.GLTextureUnitID to tex.GLName

Hope this helps

Upvotes: 1

Roger Allen
Roger Allen

Reputation: 2312

Where is the code with the error?

From http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml there is a list of many reasons why glUniform1 would return an GL_INVALID_OPERATION. I'd suggest just going through each one and confirming for yourself that it either applies or does not apply.

Here's the list:

Errors

GL_INVALID_OPERATION is generated if there is no current program object.

GL_INVALID_OPERATION is generated if the size of the uniform variable declared in the shader does not match the size indicated by the glUniform command.

GL_INVALID_OPERATION is generated if one of the signed or unsigned integer variants of this function is used to load a uniform variable of type float, vec2, vec3, vec4, or an array of these, or if one of the floating-point variants of this function is used to load a uniform variable of type int, ivec2, ivec3, ivec4, unsigned int, uvec2, uvec3, uvec4, or an array of these.

GL_INVALID_OPERATION is generated if one of the signed integer variants of this function is used to load a uniform variable of type unsigned int, uvec2, uvec3, uvec4, or an array of these.

GL_INVALID_OPERATION is generated if one of the unsigned integer variants of this function is used to load a uniform variable of type int, ivec2, ivec3, ivec4, or an array of these.

GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.

GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable.

GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than glUniform1i and glUniform1iv.

Upvotes: 2

Related Questions