Search code examples
javaopenglglsltextureslwjgl

OpenGL- GLSL texture() call: 1282 Invalid Operation


I am making a game engine, and in there I have a class which loads OBJ models. The class itself works perfectly, however, the issue I am getting is that when I render any model with textures I will always get the error (1282) Invalid Operation. I have tried different things in the code, and i have found out that it is specifically the texture() call in the fragment shader that causes this issue. I have a custom class to move textures into texture units based on which units are open, here is that class:

public class GLTextureHandler{
    private static ConcurrentHashMap<Integer,Integer> texRef=new ConcurrentHashMap<Integer,Integer>();
    public static final int texUnits=GL11.glGetInteger(GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
    private static Integer[] inUse=new Integer[texUnits];
    static{
        for(int i=0;i<inUse.length;i++){
            inUse[i]=0;
        }
        inUse[0]=1;
    }
    public static void registerTex(int tex){
        texRef.put(tex,-1);
    }
    public static int useTex(int tex){
        if(!texRef.containsKey(tex))
            registerTex(tex);
        int slot=texRef.get(tex);
        if(slot!=-1)
            return slot;
        int cnt=0;
        for(int u:inUse){
            System.out.println("Checking CNT ("+cnt+"), u is "+u);
            if(u==0){
                glActiveTexture(GL_TEXTURE0+cnt);
                glBindTexture(GL_TEXTURE_2D,tex);
                inUse[u]=1;
                texRef.put(tex,cnt);
                System.out.println("putting in slot "+cnt);
                return cnt;
            }
            cnt++;
        }
        glActiveTexture(GL_TEXTURE0+texUnits-1);
        glBindTexture(GL_TEXTURE_2D,tex);
        inUse[texUnits-1]=1;
        texRef.put(tex,texUnits-1);
        return texUnits-1;
    }
    public static void openSlot(int tex){
        if(!texRef.containsKey(tex))
            return;
        int slot=texRef.get(tex);
        if(slot!=-1)
            inUse[slot]=0;
    }
    public static boolean hasTex(int tex){
        return texRef.containsKey(tex);
    }
}

The class puts textures into a slot when useTex() is called, and returns which slot it was put in. I call this inside my DetailedVAO class, which simply renders the VAO after updating the uniforms for the materials (modelview matrix is handled inside the model class). It also tells the shader which texture unit the texture is in, and as far as I know it rcarrectly binds the texture. The The detailedVAO class is this:

class DetailedVAO{
    private Material mtl;
    private int vao,ksloc,kaloc,kdloc,texLoc,shinyLoc;
    private int texRef;

    public DetailedVAO(int vao,Material mtl,int ksloc,int kaloc,int kdloc,int texLoc,int shinyLoc){
        this.vao=vao;
        this.mtl=mtl;
        this.kaloc=kaloc;
        this.kdloc=kdloc;
        this.ksloc=ksloc;
        this.texLoc=texLoc;this.shinyLoc=shinyLoc;
        texRef=(mtl.tex()==null?-1:mtl.tex().getTextureID());
        GLTextureHandler.registerTex(texRef);
    }
    public void render(){
        Vec3 Ks=(mtl.getKs()==null?new Vec3(1):mtl.getKs());
        Vec3 Ka=(mtl.getKa()==null?new Vec3(.5f):mtl.getKa());
        Vec3 Kd=(mtl.getKd()==null?new Vec3(1):mtl.getKd());

        GL20.glUniform3f(ksloc,Ks.x,Ks.y,Ks.z);
        GL20.glUniform3f(kaloc,Ka.x,Ka.y,Ka.z);
        GL20.glUniform3f(kdloc,Kd.x,Kd.y,Kd.z);
        GL20.glUniform1f(shinyLoc,mtl.getShiny());

        int aSlot=GLTextureHandler.useTex(texRef);
        GL20.glUniform1f(texLoc,aSlot);

        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, Model.fvaoSize/4);
    }
}

The Vertex Shader:

#version 330

in vec4 position;
in vec3 normals;
in vec2 texCoords;

uniform mat4 view;
uniform mat4 projection;
uniform mat4 model;
uniform mat4 normal;

uniform vec3 u_lightPosition;
uniform vec3 u_cameraPosition;

uniform vec3 Ks;
uniform vec3 Ka;
uniform vec3 Kd;

out vec3 o_normal;
out vec3 o_toLight;
out vec3 o_toCamera;
out vec2 o_texcoords;

void main()
{
    vec4 worldPosition=model*position;

    o_normal = normalize(mat3(normal) * normals);

   // direction to light
   o_toLight = normalize(u_lightPosition - worldPosition.xyz);

   // direction to camera
   o_toCamera = normalize(u_cameraPosition - worldPosition.xyz);

   // texture coordinates to fragment shader
   o_texcoords = texCoords;

    gl_Position=projection*view*worldPosition;
}

The Fragment Shader works if i just use the Blinn-Phong values:

#version 330
out vec4 outputColor;

uniform vec4 color;

uniform mat4 view;
uniform mat4 projection;
uniform mat4 model;

uniform vec3 u_lightAmbientIntensitys; // = vec3(0.6, 0.3, 0);
uniform vec3 u_lightDiffuseIntensitys; // = vec3(1, 0.5, 0);
uniform vec3 u_lightSpecularIntensitys; // = vec3(0, 1, 0);

// parameters of the material and possible values
uniform vec3 u_matAmbientReflectances; // = vec3(1, 1, 1);
uniform vec3 u_matDiffuseReflectances; // = vec3(1, 1, 1);
uniform vec3 u_matSpecularReflectances; // = vec3(1, 1, 1);
uniform float u_matShininess;

uniform sampler2D u_diffuseTexture;

uniform vec3 Ks;
uniform vec3 Ka;
uniform vec3 Kd;

in vec3 o_normal;
in vec3 o_toLight;
in vec3 o_toCamera;
in vec2 o_texcoords;

vec3 ambientLighting()
{
   return Ka * u_lightAmbientIntensitys;
}

// returns intensity of diffuse reflection
vec3 diffuseLighting(in vec3 N, in vec3 L)
{
   // calculation as for Lambertian reflection
   float diffuseTerm = clamp(dot(N, L), 0, 1) ;
   return Kd * u_lightDiffuseIntensitys * diffuseTerm;
}

// returns intensity of specular reflection
vec3 specularLighting(in vec3 N, in vec3 L, in vec3 V)
{
   float specularTerm = 0;

   // calculate specular reflection only if
   // the surface is oriented to the light source
   if(dot(N, L) > 0)
   {
      // half vector
      vec3 H = normalize(L + V);
      specularTerm = pow(dot(N, H), u_matShininess);
   }
   return Ks * u_lightSpecularIntensitys * specularTerm;
}

void main(void)
{
   // normalize vectors after interpolation
   vec3 L = normalize(o_toLight);
  vec3 V = normalize(o_toCamera);
  vec3 N = normalize(o_normal);

   // get Blinn-Phong reflectance components
   vec3 Iamb = ambientLighting();
   vec3 Idif = diffuseLighting(N, L);
   vec3 Ispe = specularLighting(N, L, V);

   // diffuse color of the object from texture
   vec3 diffuseColor = vec3(texture(u_diffuseTexture, o_texcoords.xy));
   // combination of all components and diffuse color of the object
   outputColor.xyz = diffuseColor*(Iamb+Ispe+Idif);
   outputColor.a = 1;
}

Solution

    • This may be the source of your problems:

      GL20.glUniform1f(texLoc,aSlot);
      

      It should be

      GL20.glUniform1i(texLoc,aSlot); // i not f
      
    • EDIT: I did not read the code closely enough regarding setting glActiveTexture. The comment I made was false.

    • You're not unbinding your VAO:

      glBindVertexArray(vao);
      glDrawArrays(GL_TRIANGLES, 0, Model.fvaoSize/4);
      glBindVertexArray( 0 ); // <- Probably want this