绑定着色器 - LWJGL 对象的不正确纹理
Binding shaders - incorrect texturing of LWJGL objects
未来访客请注意:如果您使用 ft运行sform() 方法,则必须将顶点数据绑定到属性 0。
我正在尝试创建一个 3D 地形,它成功地看起来像这样:
然而,当我切换到 java 8 时,游戏变成了这样:
长话短说,纹理完全乱七八糟,我完全不知道为什么。地形颜色似乎与纹理左上角像素的颜色相同。
我这样编译着色器:
private static int loadShader(String file, int type){
StringBuilder shaderSource = new StringBuilder();
try{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine())!=null){
shaderSource.append(line).append("\n");
}
reader.close();
}catch(IOException e){
e.printStackTrace();
System.exit(-1);
}
int shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS )== GL11.GL_FALSE){
System.out.println(GL20.glGetShaderInfoLog(shaderID, 500));
System.err.println("Could not compile shader!");
System.exit(-1);
}
return shaderID;
}
使用两个 java 版本时,着色器总是能成功编译。
附加着色器后,我接着绑定着色器属性:
@Override
protected void bindAttributes() {
int loc = 0;
super.bindAttribute(GL20.glGetAttribLocation(loc, "position"), "position");
super.bindAttribute(GL20.glGetAttribLocation(loc, "textureCoords"), "textureCoords");
super.bindAttribute(GL20.glGetAttribLocation(loc, "normal"), "normal");
}
protected void bindAttribute(int attribute, String variableName){
GL20.glBindAttribLocation(programID, attribute, variableName);
}
尽管出于某种原因 "attribute" 始终设置为相同的数字,但更改它似乎不会影响任何地方。
然后我只是将这些坐标转发到片段着色器:
#version 130
in vec3 position;
in vec2 textureCoords;
in vec3 normal;
out vec2 pass_textureCoords;
out vec3 surfaceNormal;
out vec3 toLightVector;
uniform mat4 transformationMatrix;
uniform vec3 lightPosition;
void main(void){
gl_Position = ftransform(); //I prefer the fixed-function pipeline. I may change some time. However, I don't believe it to be the cause of my issue.
pass_textureCoords = textureCoords;
surfaceNormal = (transformationMatrix * vec4(normal, 0.0)).xyz;
toLightVector = (vec3(500, 50000, 500)) - (transformationMatrix * vec4(position, 1.0)).xyz;
}
#version 130
in vec2 pass_textureCoords;
in vec3 surfaceNormal;
in vec3 toLightVector;
out vec4 out_Color;
uniform sampler2D textureSampler;
uniform vec3 lightColour;
void main(void){
vec3 unitNormal = normalize(surfaceNormal);
vec3 unitLightVector = normalize(toLightVector);
float nDot1 = dot(unitNormal, unitLightVector);
float brightness = max(nDot1, 0.2);
brightness = brightness + 0.5;
vec3 diffuse = brightness * vec3(1, 1, 1);
vec4 text = texture(textureSampler, pass_textureCoords);
vec4 textureColor = vec4(diffuse, 1.0) * text;
if(textureColor.a<0.01){
discard;
}
out_Color = vec4(textureColor.r, textureColor.g, textureColor.b, textureColor.a);
}
我不知道问题出在哪里。我对 GLSL 和着色器的内部结构还没有那么多经验,我什至不知道问题是什么时候开始出现的,因为我是在开始将游戏发送给其他人后才注意到这个问题的(我 运行 在 java 7).
我已经使用 Jon Skeet's method of changing versions of java 和 运行 并排使用完全相同的 JAR 文件测试了游戏,一个是 java 8,一个是 java 7。 Java 8 绝对是导致问题的决定因素。
更新:
这段代码-
System.out.println("Err1: " + GL11.glGetError());
vertexShaderID = loadShader(vertexFile,GL20.GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile,GL20.GL_FRAGMENT_SHADER);
programID = GL20.glCreateProgram();
System.out.println("Err2: " + GL11.glGetError());
GL20.glAttachShader(programID, vertexShaderID);
GL20.glAttachShader(programID, fragmentShaderID);
System.out.println("Err3: " + GL11.glGetError());
bindAttributes();
System.out.println("Err4: " + GL11.glGetError());
GL20.glLinkProgram(programID);
GL20.glValidateProgram(programID);
System.out.println("Err5: " + GL11.glGetError());
start();
System.out.println("Err6: " + GL11.glGetError());
System.out.println("Comiled shader!");
打印出如下结果:
Comiling shader!
Err1: 0
Error:
Error:
Err2: 0
Err3: 0
Err4: 1282 //This equals either GL_INVALID_VALUE or GL_INVALID_OPERATION
Err5: 0
Err6: 0
Comiled shader!
更新:
根据我收到的第一个答案,我将我的代码修改为:
@Override
protected void bindAttributes() {
super.bindAttribute(1, "position");
super.bindAttribute(2, "textureCoords");
super.bindAttribute(3, "normal");
}
现在,这段代码不会打印出任何错误:
public ShaderProgram(String vertexFile,String fragmentFile){
System.out.println("Comiling shader!");
System.out.println("Err1: " + GL11.glGetError());
vertexShaderID = loadShader(vertexFile,GL20.GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile,GL20.GL_FRAGMENT_SHADER);
programID = GL20.glCreateProgram();
System.out.println("Err2: " + GL11.glGetError());
GL20.glAttachShader(programID, vertexShaderID);
GL20.glAttachShader(programID, fragmentShaderID);
System.out.println("Err3: " + GL11.glGetError());
bindAttributes();
System.out.println("Err4: " + GL11.glGetError());
GL20.glLinkProgram(programID);
GL20.glValidateProgram(programID);
System.out.println("Err5: " + GL11.glGetError());
start();
System.out.println("Err6: " + GL11.glGetError());
System.out.println("Comiled shader!");
}
Comiling shader!
Err1: 0
Error:
Error:
Err2: 0
Err3: 0
Err4: 0
Err5: 0
Err6: 0
Comiled shader!
Made StaticShader!
Made shaders!
此外,我肯定会将 VAO 数据绑定到正确的属性:
public RawModel loadToVAO(float[] positions,float[] textureCoords,float[] normals,int[] indices, ArrayList<Vector3f> vertices){
int vaoID = createVAO();
bindIndicesBuffer(indices);
storeDataInAttributeList(1 /*attribute*/,3,positions);
storeDataInAttributeList(2/*attribute*/,2,textureCoords);
storeDataInAttributeList(3/*attribute*/,3,normals);
unbindVAO();
return new RawModel(vaoID,indices.length, vertices);
}
但是,当游戏开始尝试渲染任何内容时,它只会不断崩溃。 Here's the crash report.
这是我的渲染代码:
GL30.glBindVertexArray(downgrade.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
GL20.glEnableVertexAttribArray(3);
glBindTexture(GL_TEXTURE_2D, textureID);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
glTranslatef((float) x, 0f,(float) z);
glScalef(1, 4, 1);
glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
对于那些想知道的人,我缺少属性“0”,因为属性 0 用于固定功能管道,如果我绑定该属性,它会抛出 GL_INVALID_VALUE。
我怀疑 bindAttributes()
函数是否能在任何 Java 版本中可靠地工作。也许您很幸运,属性位置最终符合您的预期。
查看这段代码:
protected void bindAttributes() {
int loc = 0;
super.bindAttribute(GL20.glGetAttribLocation(loc, "position"), "position");
super.bindAttribute(GL20.glGetAttribLocation(loc, "textureCoords"), "textureCoords");
super.bindAttribute(GL20.glGetAttribLocation(loc, "normal"), "normal");
}
protected void bindAttribute(int attribute, String variableName){
GL20.glBindAttribLocation(programID, attribute, variableName);
}
您正在调用 glGetAttribLocation()
,第一个参数是 0
。第一个参数需要是着色器程序的 ID。所以这些调用会导致错误。
退一步说,我认为您误解了这些调用的作用:
glBindAttribLocation()
可用于 设置 属性位置 在 着色器程序链接之前。
glGetAttribLocation()
可用于获取(自动分配的)属性位置在 着色器程序链接后。
您通常使用这两者之一,而不是两者。如果要指定位置,请使用第一种方法。如果你想让着色器 compiler/linker 分配位置,并获得结果位置,你使用第二种方法。
由于您在 glLinkProgram()
之前调用了 bindAttributes()
,看起来您正在使用方法 1。因此您应该只调用 glBindAttribLocation()
。假设你想按顺序分配位置值,你可以使用类似的东西:
int loc = 0;
GL20.glBindAttribLocation(programID, loc++, "position");
GL20.glBindAttribLocation(programID, loc++, "textureCoords");
GL20.glBindAttribLocation(programID, loc++, "normal");
您指定的实际位置必须与您在代码中其他地方使用的位置相匹配,特别是作为 glEnableVertexAttribArray()
和 glVertexAttribPointer()
.
的第一个参数
未来访客请注意:如果您使用 ft运行sform() 方法,则必须将顶点数据绑定到属性 0。
我正在尝试创建一个 3D 地形,它成功地看起来像这样:
然而,当我切换到 java 8 时,游戏变成了这样:
长话短说,纹理完全乱七八糟,我完全不知道为什么。地形颜色似乎与纹理左上角像素的颜色相同。
我这样编译着色器:
private static int loadShader(String file, int type){
StringBuilder shaderSource = new StringBuilder();
try{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine())!=null){
shaderSource.append(line).append("\n");
}
reader.close();
}catch(IOException e){
e.printStackTrace();
System.exit(-1);
}
int shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS )== GL11.GL_FALSE){
System.out.println(GL20.glGetShaderInfoLog(shaderID, 500));
System.err.println("Could not compile shader!");
System.exit(-1);
}
return shaderID;
}
使用两个 java 版本时,着色器总是能成功编译。
附加着色器后,我接着绑定着色器属性:
@Override
protected void bindAttributes() {
int loc = 0;
super.bindAttribute(GL20.glGetAttribLocation(loc, "position"), "position");
super.bindAttribute(GL20.glGetAttribLocation(loc, "textureCoords"), "textureCoords");
super.bindAttribute(GL20.glGetAttribLocation(loc, "normal"), "normal");
}
protected void bindAttribute(int attribute, String variableName){
GL20.glBindAttribLocation(programID, attribute, variableName);
}
尽管出于某种原因 "attribute" 始终设置为相同的数字,但更改它似乎不会影响任何地方。
然后我只是将这些坐标转发到片段着色器:
#version 130
in vec3 position;
in vec2 textureCoords;
in vec3 normal;
out vec2 pass_textureCoords;
out vec3 surfaceNormal;
out vec3 toLightVector;
uniform mat4 transformationMatrix;
uniform vec3 lightPosition;
void main(void){
gl_Position = ftransform(); //I prefer the fixed-function pipeline. I may change some time. However, I don't believe it to be the cause of my issue.
pass_textureCoords = textureCoords;
surfaceNormal = (transformationMatrix * vec4(normal, 0.0)).xyz;
toLightVector = (vec3(500, 50000, 500)) - (transformationMatrix * vec4(position, 1.0)).xyz;
}
#version 130
in vec2 pass_textureCoords;
in vec3 surfaceNormal;
in vec3 toLightVector;
out vec4 out_Color;
uniform sampler2D textureSampler;
uniform vec3 lightColour;
void main(void){
vec3 unitNormal = normalize(surfaceNormal);
vec3 unitLightVector = normalize(toLightVector);
float nDot1 = dot(unitNormal, unitLightVector);
float brightness = max(nDot1, 0.2);
brightness = brightness + 0.5;
vec3 diffuse = brightness * vec3(1, 1, 1);
vec4 text = texture(textureSampler, pass_textureCoords);
vec4 textureColor = vec4(diffuse, 1.0) * text;
if(textureColor.a<0.01){
discard;
}
out_Color = vec4(textureColor.r, textureColor.g, textureColor.b, textureColor.a);
}
我不知道问题出在哪里。我对 GLSL 和着色器的内部结构还没有那么多经验,我什至不知道问题是什么时候开始出现的,因为我是在开始将游戏发送给其他人后才注意到这个问题的(我 运行 在 java 7).
我已经使用 Jon Skeet's method of changing versions of java 和 运行 并排使用完全相同的 JAR 文件测试了游戏,一个是 java 8,一个是 java 7。 Java 8 绝对是导致问题的决定因素。
更新: 这段代码-
System.out.println("Err1: " + GL11.glGetError());
vertexShaderID = loadShader(vertexFile,GL20.GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile,GL20.GL_FRAGMENT_SHADER);
programID = GL20.glCreateProgram();
System.out.println("Err2: " + GL11.glGetError());
GL20.glAttachShader(programID, vertexShaderID);
GL20.glAttachShader(programID, fragmentShaderID);
System.out.println("Err3: " + GL11.glGetError());
bindAttributes();
System.out.println("Err4: " + GL11.glGetError());
GL20.glLinkProgram(programID);
GL20.glValidateProgram(programID);
System.out.println("Err5: " + GL11.glGetError());
start();
System.out.println("Err6: " + GL11.glGetError());
System.out.println("Comiled shader!");
打印出如下结果:
Comiling shader!
Err1: 0
Error:
Error:
Err2: 0
Err3: 0
Err4: 1282 //This equals either GL_INVALID_VALUE or GL_INVALID_OPERATION
Err5: 0
Err6: 0
Comiled shader!
更新: 根据我收到的第一个答案,我将我的代码修改为:
@Override
protected void bindAttributes() {
super.bindAttribute(1, "position");
super.bindAttribute(2, "textureCoords");
super.bindAttribute(3, "normal");
}
现在,这段代码不会打印出任何错误:
public ShaderProgram(String vertexFile,String fragmentFile){
System.out.println("Comiling shader!");
System.out.println("Err1: " + GL11.glGetError());
vertexShaderID = loadShader(vertexFile,GL20.GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile,GL20.GL_FRAGMENT_SHADER);
programID = GL20.glCreateProgram();
System.out.println("Err2: " + GL11.glGetError());
GL20.glAttachShader(programID, vertexShaderID);
GL20.glAttachShader(programID, fragmentShaderID);
System.out.println("Err3: " + GL11.glGetError());
bindAttributes();
System.out.println("Err4: " + GL11.glGetError());
GL20.glLinkProgram(programID);
GL20.glValidateProgram(programID);
System.out.println("Err5: " + GL11.glGetError());
start();
System.out.println("Err6: " + GL11.glGetError());
System.out.println("Comiled shader!");
}
Comiling shader!
Err1: 0
Error:
Error:
Err2: 0
Err3: 0
Err4: 0
Err5: 0
Err6: 0
Comiled shader!
Made StaticShader!
Made shaders!
此外,我肯定会将 VAO 数据绑定到正确的属性:
public RawModel loadToVAO(float[] positions,float[] textureCoords,float[] normals,int[] indices, ArrayList<Vector3f> vertices){
int vaoID = createVAO();
bindIndicesBuffer(indices);
storeDataInAttributeList(1 /*attribute*/,3,positions);
storeDataInAttributeList(2/*attribute*/,2,textureCoords);
storeDataInAttributeList(3/*attribute*/,3,normals);
unbindVAO();
return new RawModel(vaoID,indices.length, vertices);
}
但是,当游戏开始尝试渲染任何内容时,它只会不断崩溃。 Here's the crash report.
这是我的渲染代码:
GL30.glBindVertexArray(downgrade.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
GL20.glEnableVertexAttribArray(3);
glBindTexture(GL_TEXTURE_2D, textureID);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
glTranslatef((float) x, 0f,(float) z);
glScalef(1, 4, 1);
glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
对于那些想知道的人,我缺少属性“0”,因为属性 0 用于固定功能管道,如果我绑定该属性,它会抛出 GL_INVALID_VALUE。
我怀疑 bindAttributes()
函数是否能在任何 Java 版本中可靠地工作。也许您很幸运,属性位置最终符合您的预期。
查看这段代码:
protected void bindAttributes() {
int loc = 0;
super.bindAttribute(GL20.glGetAttribLocation(loc, "position"), "position");
super.bindAttribute(GL20.glGetAttribLocation(loc, "textureCoords"), "textureCoords");
super.bindAttribute(GL20.glGetAttribLocation(loc, "normal"), "normal");
}
protected void bindAttribute(int attribute, String variableName){
GL20.glBindAttribLocation(programID, attribute, variableName);
}
您正在调用 glGetAttribLocation()
,第一个参数是 0
。第一个参数需要是着色器程序的 ID。所以这些调用会导致错误。
退一步说,我认为您误解了这些调用的作用:
glBindAttribLocation()
可用于 设置 属性位置 在 着色器程序链接之前。glGetAttribLocation()
可用于获取(自动分配的)属性位置在 着色器程序链接后。
您通常使用这两者之一,而不是两者。如果要指定位置,请使用第一种方法。如果你想让着色器 compiler/linker 分配位置,并获得结果位置,你使用第二种方法。
由于您在 glLinkProgram()
之前调用了 bindAttributes()
,看起来您正在使用方法 1。因此您应该只调用 glBindAttribLocation()
。假设你想按顺序分配位置值,你可以使用类似的东西:
int loc = 0;
GL20.glBindAttribLocation(programID, loc++, "position");
GL20.glBindAttribLocation(programID, loc++, "textureCoords");
GL20.glBindAttribLocation(programID, loc++, "normal");
您指定的实际位置必须与您在代码中其他地方使用的位置相匹配,特别是作为 glEnableVertexAttribArray()
和 glVertexAttribPointer()
.