【发布时间】:2015-10-27 23:23:57
【问题描述】:
我正在制作一个游戏引擎,其中我有一个加载 OBJ 模型的类。该类本身运行良好,但是,我遇到的问题是,当我使用纹理渲染任何模型时,我总是会收到错误 (1282) Invalid Operation。我在代码中尝试了不同的东西,我发现正是片段着色器中的 texture() 调用导致了这个问题。我有一个自定义类,可以根据打开的单元将纹理移动到纹理单元中,这是该类:
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);
}
}
该类在调用 useTex() 时将纹理放入槽中,并返回放入的槽中。我在DetailedVAO 类中调用它,它在更新材料的制服后简单地渲染VAO(模型视图矩阵为在模型类内部处理)。它还告诉着色器纹理所在的纹理单元,据我所知,它会直接绑定纹理。详细的VAO类是这样的:
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);
}
}
顶点着色器:
#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;
}
如果我只使用 Blinn-Phong 值,片段着色器就可以工作:
#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- 你有没有移动你的glGetError?有点奇怪。关于片段着色器,我得到的唯一想法是像这样替换纹理查找:vec3 diffuseColor = texture(u_diffuseTexture, o_texcoords.xy).rgb; -
是的,请在每个 opengl调用后检查glGetError(如果需要,请将其放在#ifdef _DEBUG括号中)。
-
我启用了调试选项,所以每次调用后都会调用它。就像我在帖子中所说的那样,删除 texture() 可以解决问题。 @St0fF,我也试过了,同样的错误。感谢您的关注!
-
好吧,我不知道这个组合。对我来说,普通的 OpenGL 是 C/C++。您必须在那里拨打
glGetError电话。特别是我很困惑,您可以将错误处理到片段着色器中。所以现在我只假设glDrawArrays抛出了错误。它不会在没有纹理的情况下出现 - 您是否正确设置了所有必要的纹理参数?GL_MIN_FILTER、GL_MAG_FILTER、GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T? -
如果您使用某种调试选项,它应该真正告诉您哪个 OpenGL 调用触发了错误。否则它将毫无用处,您最好自己拨打
glGetError()。缩小错误的来源真的很容易。一旦你这样做了,就会很明显是什么原因造成的。
标签: java opengl glsl textures lwjgl