Djindjidj
Djindjidj

Reputation: 133

Render to FBO, sampling fails

I am trying to render to FBO and then to screen in OpenGL / LWJGL and I get weird results.

My scene if rendered directly to the framebuffer works just fine and looks like this:

1

But when I render to the FBO and then to that one to a quad on the default framebuffer, I get this:

2

Looks like all the colors in the image got averaged in a single color and as if the screen was cleared with that one.

My guess is, that there's something wrong with the sampling of the texture on the quad but I cannot figure it out.

The quad obviously IS there as I see the edges with glPolymode - GL_LINE. Also, the single color on the quad changes when I move the ingame camera and somehow also reflects the most prominent color on screen. So maybe you can point me to the probably obvious solution? I will put some code that i think is relevant at the end of this post.


This is how I set up my squad's vertices and uv coordinates. I use the same method and parent classes for the cubes, so i know this works:

    vertices[0] = new Vertex(-1.0f,-1.0f,0.0f);
    vertices[0].setTexCoords(0.0f,0.0f);

    vertices[1] = new Vertex(-1.0f,1.0f,0.0f);
    vertices[1].setTexCoords(0.0f,1.0f);

    vertices[2] = new Vertex(1.0f,1.0f,0.0f);
    vertices[2].setTexCoords(1.0f,1.0f);

    vertices[3] = new Vertex(1.0f,-1.0f,0.0f);
    vertices[3].setTexCoords(1.0f,0.0f);

This is how i bind those to the vbos:

    vaoID = GL30.glGenVertexArrays();
    GL30.glBindVertexArray(vaoID);
        //POSITION - LOCATION 0
        int vboID = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);

        FloatBuffer buffer = BufferUtils.createFloatBuffer(vertices.length*3);
        buffer.put(getPositions());
        buffer.flip();

        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(0,  3,  GL11.GL_FLOAT, false, 0,0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

        buffer.clear();

       //... some code for color and normal, going into VBO location 1 and 2


        //TEX COORDS - LOCATION 3
        vboID = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);

        buffer = BufferUtils.createFloatBuffer(vertices.length*2);
        buffer.put(getTexCoords());
        buffer.flip();

        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(3, 2,  GL11.GL_FLOAT, false, 0,0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

        buffer.clear();

This is how i bind the attribute locations in the shader for the quad:

    protected void bindAttributes(){
       GL20.glBindAttribLocation(id, 0, "vertex_position");
       GL20.glBindAttribLocation(id, 3, "vertex_texCoord");
    }

This is how i render the screen quad:

GL20.glUseProgram(presentShader.getProgramID());
    GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
    GL20.glEnableVertexAttribArray(0);
    GL20.glEnableVertexAttribArray(3);

    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    //GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
    GL11.glDrawElements(GL11.GL_TRIANGLES, screenQuad.getMesh(0).getIndexCount(), GL11.GL_UNSIGNED_INT, 0);

    GL20.glDisableVertexAttribArray(3);
    GL20.glDisableVertexAttribArray(0);
    GL30.glBindVertexArray(0);
GL20.glUseProgram(0);

This is my vertex and fragment shader: Vertex:

#version 400 core

in vec2 vertex_position;
in vec2 vertex_texCoords;

out vec2 pass_texCoords;

void main(){

    gl_Position =  vec4(vertex_position.x, vertex_position.y, 0.0f, 1.0f);
    pass_texCoords = vertex_texCoords;
}

Fragment:

#version 400 core

in vec2 pass_texCoords;

out vec4 fragment_color;

uniform sampler2D screenTexture;

void main(){
    fragment_color = texture(screenTexture, pass_texCoords);
    //fragment_color  = vec4(0.3,0.3,0.3,1.0);

}

Finally, this is my rendering procedure: prepare(); drawScene(); present();

With those functions:

public void prepare(){
        //FBO aktivieren, alles danach wird auf FBO-Textur gerendert
        GL11.glClearColor(0.0f,0.0f,0.0f, 1.0f); 
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL11.GL_STENCIL_TEST);
        GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE); 
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT |  GL11.GL_STENCIL_BUFFER_BIT);
    }

    public void present(){
        //Standard Framebuffer aktivieren
        GL11.glClearColor(1.0f,1.0f,1.0f, 1.0f);
        GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glDisable(GL11.GL_STENCIL_TEST);
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);


        GL20.glUseProgram(presentShader.getProgramID());
        GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
        GL20.glEnableVertexAttribArray(0);
        GL20.glEnableVertexAttribArray(3);

        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);
        GL11.glDrawElements(GL11.GL_TRIANGLES, screenQuad.getMesh(0).getIndexCount(), GL11.GL_UNSIGNED_INT, 0);

        GL20.glDisableVertexAttribArray(3);
        GL20.glDisableVertexAttribArray(0);
        GL30.glBindVertexArray(0);

        GL20.glUseProgram(0);
    }

Edit: Maybe i should add how i set up the FBO:

private void linitializeFrameBuffer(int viewportWidth, int viewportHeight){
    //COLOR TEXTURE
    frameBufferID = GL30.glGenFramebuffers();
    GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID); // GL_READ_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER

    frameBufferTextureID = GL11.glGenTextures();
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, frameBufferTextureID);   //GL_TEXTURE_1D, GL_TEXTURE2D, GL_TEXTURE3D
    FloatBuffer pixelBuffer;
    pixelBuffer = BufferUtils.createFloatBuffer(viewportWidth*viewportHeight*3);
    pixelBuffer.clear();
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, viewportWidth, viewportHeight, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);     
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR );
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR );
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

    //Attach the new Texture to the framebuffer
    GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, frameBufferTextureID, 0);

    //DEPTH BUFFER
    depthBufferID = GL30.glGenRenderbuffers();
    GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBufferID);
    GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, viewportWidth, viewportHeight);
    GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0);

    //Attach the new renderbuffer to the framebuffer
    GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBufferID);


    if(GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER) != GL30.GL_FRAMEBUFFER_COMPLETE){
        System.out.println("ERROR::FRAMEBUFFER:: Framebuffer is not complete!");
    }
    GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0); 
}

Upvotes: 1

Views: 420

Answers (2)

Djindjidj
Djindjidj

Reputation: 133

Got the solution. The texture coordinates in the shader are called in vec2 vertex_texCoords;

I referenced them as GL20.glBindAttribLocation(id, 3, "vertex_texCoord");

Changing that to GL20.glBindAttribLocation(id, 3, "vertex_texCoords"); did the job.

Upvotes: 1

Antoine Morrier
Antoine Morrier

Reputation: 4078

First,

GL30.glBindVertexArray(screenQuad.getMesh(0).getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(3);

enableVertexAttribArray should be in the function which initialize the VAO, and not during the rendering loop ;). Going that way, disableVertexAttribArray is "useless".

Secondly, I am not really convenient with "binding to work" since direct state access is a part of OpenGL core. But, I can see 2 eventuals caveat (even if I am not pretty sure about it)

You are giving the "internal format" GL_RGB to glTexImage2D, if I were you I would use GL_RGB8. (I know GL_RGB is not correct using glTexStorage, but maybe it is possible to use it with GLTexImage2D, enable arb debug output to know if there is an error or not).

You unbind the texture before sending it to frameBuffer (after reading the doc, it should be ok).

You are creating "pixelBuffer" which is never used.

Finally, I had a lot of issues using Depth and Stencil buffer, especially when I was using renderBuffer. I advice you to switch to texture instead of renderBuffer and begin to "debug" your program using only a depthTexture without stencil.

EDIT : As Djindjidj wrote, you did not respect vec2 / vec3 in your shader

Upvotes: 1

Related Questions