纹理被渲染为黑色四边形

Texture being rendered as black quad

我一直在尝试遵循 code as specified in this tutorial on OpenGL3+ textures,但我的结果最终是黑色而不是纹理。

我正在使用 stbimage 将纹理使用的图像加载到直接的 ByteBuffer 中,并且可以保证缓冲区中的 RGB 数据至少是不统一的 - 所以不可能是那样。

我通常不喜欢转储代码,但目前我看不出还有什么可以做的。这是我的 java 代码和着色器:

GL是指向LWJGL31.

中所有GL##功能的接口

ShaderProgram 将所有特定于着色器的内容包装到一个漂亮的黑盒中,该黑盒在第一次调用 use(GL) 时从附加的着色器生成一个着色器程序,然后重用该程序。这适用于渲染彩色三角形,所以我排除了其中的任何错误。

Util.checkError(GL, boolean); 会检查自上次执行以来累积的任何 OpenGL 错误,如果未设置布尔值则抛出 运行time 异常(如果设置则静默写入日志) .

渲染代码,update(GL, long)是运行每帧一次

private static final ResourceAPI res = API.get(ResourceAPI.class);

Image lwjgl32;

ShaderProgram prog = new ShaderProgram();
int vbo, vao, ebo;
int texture;

@Override
public void init(GL gl) {

    try {
        prog.attach(res.get("shaders/texDemo.vert", ShaderSource.class));
        prog.attach(res.get("shaders/texDemo.frag", ShaderSource.class));
        lwjgl32 = res.get("textures/lwjgl32.png", Image.class);
    } catch(ResourceException e) {
        throw new RuntimeException(e);
    }

    float[] vertices = {
        // positions          // colors           // texture coords
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
         0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left 
    };

    int[] indices = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };

    vao = gl.glGenVertexArrays();
    vbo = gl.glGenBuffers();
    ebo = gl.glGenBuffers();

    gl.glBindVertexArray(vao);

    gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo);
    gl.glBufferData(GL.GL_ARRAY_BUFFER, vertices, GL.GL_STATIC_DRAW);

    gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, ebo);
    gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indices, GL.GL_STATIC_DRAW);

    gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 0);
    gl.glEnableVertexAttribArray(0);

    gl.glVertexAttribPointer(1, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 3 * Float.BYTES);
    gl.glEnableVertexAttribArray(0);

    gl.glVertexAttribPointer(2, 2, GL.GL_FLOAT, false, 8 * Float.BYTES, 6 * Float.BYTES);
    gl.glEnableVertexAttribArray(0);

    texture = gl.glGenTextures();
    gl.glBindTexture(GL.GL_TEXTURE_2D, texture);

    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);

    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);

    gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, lwjgl32.getWidth(), lwjgl32.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, lwjgl32.getImageData());
    gl.glGenerateMipmap(GL.GL_TEXTURE_2D);

    prog.use(gl);
    gl.glUniform1i(gl.glGetUniformLocation(prog.getId(gl), "texture"), 0);

    Util.checkError(gl, false);
}

@Override
protected void update(GL gl, long deltaFrame) {
    gl.glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    gl.glClear(GL.GL_COLOR_BUFFER_BIT);

    gl.glActiveTexture(GL.GL_TEXTURE0);
    gl.glBindTexture(GL.GL_TEXTURE_2D, texture);

    prog.use(gl);
    gl.glBindVertexArray(vao);
    gl.glDrawElements(GL.GL_TRIANGLES, 6, GL.GL_UNSIGNED_INT, 0);
}

@Override
public void clean(GL gl) {
    gl.glDeleteVertexArrays(vao);
    gl.glDeleteBuffers(vbo);
    gl.glDeleteBuffers(ebo);

    ShaderProgram.clearUse(gl);
    prog.dispose(gl);
}

顶点着色器

#version 330 core

layout (location = 0) in vec3 in_position;
layout (location = 1) in vec3 in_color;
layout (location = 2) in vec2 in_texCoord;

out vec3 color;
out vec2 texCoord;

void main() {
    gl_Position = vec4(in_position, 1.0);

    color = in_color;
    texCoord = vec2(in_texCoord.x, in_texCoord.y);
}

片段着色器

#version 330 core

out vec4 frag_colour;

in vec3 color;
in vec2 texCoord;

uniform sampler2D texture;

void main() {
    frag_colour = texture(texture, texCoord) * vec4(color, 1.0);
}

1我将 LWJGL3 的 GL## static 类 包装到单个接口和实现中,这样我就可以拥有一堆有状态的方法例如识别正在呈现的上下文等。我也尽力从界面中删除非核心功能,所以我什至不想使用已弃用的东西

仅看代码很难判断,但黑色四边形表示片段着色器中的这一行:

frag_colour = texture(texture, texCoord) * vec4(color, 1.0);

评估为 0。这意味着纹理不正确 read/bound,您的纹理坐标关闭或颜色为零向量。确保您的纹理图像已正确加载(文件存在,具有宽度和高度等)并且具有正确的格式。我通常调试着色器的做法是将每个参数设置为颜色,以在其具有正确的值时给出提示:

frag_colour = vec4(color, 1.0); //Makes sure the color is right

frag_colour = texture(texture, texCoord); //Makes sure the texture is loaded and bound

如果这还不能提供足够的信息,请提供更多详细信息:

frag_colour = vec4(color.x, color.x, color.x, 1.0);

frag_colour = vec4(texCoord.x, texCoord.x, texCoord.x, 1.0);

你只启用索引为0的顶点属性,但是这3次。

像这样调整您的代码:

gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 0);
gl.glEnableVertexAttribArray(0);

gl.glVertexAttribPointer(1, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 3 * Float.BYTES);
gl.glEnableVertexAttribArray(1); // <-------

gl.glVertexAttribPointer(2, 2, GL.GL_FLOAT, false, 8 * Float.BYTES, 6 * Float.BYTES);
gl.glEnableVertexAttribArray(2); // <------