dot_Sp0T
dot_Sp0T

Reputation: 399

Texture being rendered as black quad

I have been trying to follow the code as specified in this tutorial on OpenGL3+ textures, but my result ends up black instead of the texture.

enter image description here

I am using stbimage to load the image the texture uses into a direct ByteBuffer and can guarantee the RGB data in the buffer is, at least, not uniform - so it can't be that.

I usually do not like to dump code, but I don't see much else I can do at this point. Here's my java code and shaders:

GL is an interface pointing to all the GL## functionality in LWJGL31.

ShaderProgram wraps all the shader specific stuff into a nice blackbox that generates a shaderprogram from the attached shaders on the first call of use(GL) and subsequently reuses that program. This works just fine for rendering a coloured triangle, so I rule out any errors in there.

Util.checkError(GL, boolean); does check for any OpenGL errors that have accumulated since its last execution and throws a runtime exception if the boolean is not set (silently writes to the log instead, if set).

The rendering code, update(GL, long) is run once every frame

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);
}

Vertex shader

#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);
}

Fragment shader

#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);
}

1I wrapped LWJGL3's GL## static classes into a single interface and implementation so I can have a bunch of stateful methods that do things such as identifying the context that is being rendered to, etc. I also did my best to remove non-core functionality from the interface so I don't even get tempted to use deprecated stuff

Upvotes: 1

Views: 330

Answers (2)

Rabbid76
Rabbid76

Reputation: 211230

You only enable the vertex attribute with index 0, but this 3 times.

Adapt your code like this:

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); // <------

Upvotes: 2

Johan
Johan

Reputation: 1515

It's hard to tell from just looking at the code but a black quad means that this row in your fragment shader:

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

evaluates to 0. Which means either the texture is'nt read/bound properly, your texture coordinates are off or color is a zero vector. Make sure your texture image is properly loaded (file exists, has a width and height etc) and has the correct format. What I usually do to debug the shader is to set each parameter as a color to give a hint if it has the correct value:

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

or

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

And if that doesn't give enough information, even more detail:

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

or

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

Upvotes: 0

Related Questions