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;
}
INVALID_OPERATION
- have you moved around your glGetError? It's weird. The only Idea I would get about the fragment shader would be to replace the texture lookup like this:vec3 diffuseColor = texture(u_diffuseTexture, o_texcoords.xy).rgb;
– St0fFglGetError
calls. Especially I am confused that you can mangle the error that far into the fragment shader. So for now I'll just assumeglDrawArrays
threw the error. It doesn't appear without texturing - have you correctly set all necessary texture parameters?GL_MIN_FILTER
,GL_MAG_FILTER
,GL_TEXTURE_WRAP_S
, andGL_TEXTURE_WRAP_T
? – St0fFglGetError()
calls yourself. It's really easy to narrow down where the error comes from. And once you do, it tends to be very obvious what's causing it. – Reto Koradi