1

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); 
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
Djindjidj
  • 133
  • 8
  • At least one mistake was made with #version 400 core in vec2 vertex_position; being actually a vec3. Changing that thought did nothing to better the result. – Djindjidj Sep 06 '16 at 12:05

2 Answers2

1

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

Antoine Morrier
  • 3,930
  • 16
  • 37
  • Thank you for taking the time. I figured out the problem. Still you have mentioned some things that i'd like to ask about: What exactly do you mean by "enableVertexAttribArray should be in the function which initialize the VAO, and not during the rendering" ? I thought that you have to bind the vao and then enable that vao's vbos during rendering? If I have different vaos with a distinct number of vbos, how would i handle that then? – Djindjidj Sep 06 '16 at 12:13
  • I did not really yet go into custom texture initialization in opengl. I actually copy-pasted that part from a tutorial. Until now, i used the slick TextureLoader. I planned on diving into custom texture handling after solving that problem and i will definitely check back what you mentioned about GL_RGB and GL_RGB8 then. – Djindjidj Sep 06 '16 at 12:15
  • Aaand i deleted those pixelBuffer lines already. I used them to initialize the texture2d object as i could not do that with "null" until i found out i have to cast to a specific buffer type. – Djindjidj Sep 06 '16 at 12:16
  • I mean that glEnableVertexAttribArray should be with this part of code 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); – Antoine Morrier Sep 07 '16 at 00:12
1

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.

elect
  • 6,765
  • 10
  • 53
  • 119
Djindjidj
  • 133
  • 8
  • 1
    Just a small tip to reduce the possibility to get this error, if you have [explicit locations](https://www.opengl.org/registry/specs/ARB/explicit_attrib_location.txt), just declare `layout (location = TEX_COORD) in vec2 vertex_texCoords;`. Write on top `#define TEX_COORD 3` and in your java code use `final int TEX_COORD 2` to refer to that – elect Sep 09 '16 at 07:46