【问题标题】:Binding shaders - incorrect texturing of LWJGL objects绑定着色器 - LWJGL 对象的不正确纹理
【发布时间】:2015-10-08 10:43:19
【问题描述】:

未来访问者请注意:如果您使用 ftransform() 方法,则必须将顶点数据绑定到属性 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);
}

尽管出于某种原因,“属性”总是设置为相同的数字,但更改它似乎不会影响任何地方。

然后我只是将这些坐标转发到片段着色器:

#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。

【问题讨论】:

    标签: java opengl java-8 glsl lwjgl


    【解决方案1】:

    我怀疑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。所以这些调用会导致错误。

    退后一步,我认为您误解了这些调用的作用:

    1. glBindAttribLocation() 可用于设置属性位置之前着色器程序被链接。
    2. glGetAttribLocation() 可用于获取(自动分配的)属性位置链接着色器程序之后。

    您通常使用这两者之一,而不是两者。如果要指定位置,请使用第一种方法。如果您想让着色器编译器/链接器分配位置,并获得结果位置,则使用第二种方法。

    由于您在调用glLinkProgram() 之前调用了bindAttributes(),因此您似乎要使用方法1。所以您应该只调用glBindAttribLocation()。假设你想按顺序分配位置值,你可以使用类似的东西:

    int loc = 0;
    GL20.glBindAttribLocation(programID, loc++, "position");
    GL20.glBindAttribLocation(programID, loc++, "textureCoords");
    GL20.glBindAttribLocation(programID, loc++, "normal");
    

    您指定的实际位置必须与您在代码中其他地方使用的位置相匹配,尤其是作为glEnableVertexAttribArray()glVertexAttribPointer() 的第一个参数。

    【讨论】:

    • 我认为 fTransform() 占用了属性位置 0。我对此有误吗?
    • 我在问题中添加了我的新代码。然而,游戏现在只是在调用glDrawArrays() 时崩溃。
    • @Joehot200 您正在混合使用 OpenGL 的各种方式。例如,固定函数属性和通用属性。使用矩阵堆栈并构建您自己的转换。您需要决定是要坚持使用遗留功能,还是只使用核心配置文件中的功能。你不能随意混合这些东西。但这确实远远超出了原始问题的范围。
    猜你喜欢
    • 1970-01-01
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-13
    • 2016-08-06
    • 1970-01-01
    相关资源
    最近更新 更多