Rendering to texture using FBO and shaders OpenGL

3.9k views Asked by At

I want to load two textures in my FBO, one texture contains a HDR image, and my first target is to "copy" the image from first texture to second (which is empty), and called 'DownSamplingTex'.

So I create FBO, load the texture I want to write in COLOR_ATTACHMENT_0, and bind it; then init my shader program and render a quad, with texture I want to read bound in GL_TEXTURE_0.

Then I unbind the FBO and bind 'DownSamplingTex', and draw a quad.

I don't know if the process is correct, the output I have is a black screen.

Here's the render code:

glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
FBOtex->bind();  // Set read texture bound in GL_TEXTURE_0
glDrawBuffer(GL_COLOR_ATTACHMENT0);  // draw to write texture (DownSamplingTex)
fboShad->bind();    // use program of FBO shader
  fboShad->setUniformValue4f("MVP", glm::value_ptr(MVP));  // Shader attribute
  drawQuad();   // Draw
  fboShad->unbind();
 FBOtex->unbind();
// Main FB rendering
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
fboShad->bind();
  fboShad->setUniformValue4f("MVP", glm::value_ptr(MVP)); 
  DownSamplingTex->bind();
  drawQuad(); 
  DownSamplingTex->unbind();
fboShad->unbind();

Vertex shader:

#version 420

in vec4 vUV;
in vec4 vVertex;
smooth out vec2 vTexCoord;

uniform mat4 MVP;

void main()
{
   vTexCoord = vUV;
   gl_Position = MVP*vVertex;
}

Fragment shader:

#version 420
smooth in vec2 vTexCoord;
layout(location = 0) out vec4 color;
layout(binding=0) uniform sampler2D texHDR;

void main(void)
{
   color = texture(texHDR,vTexCoord);
}

Inside 'drawQuad()' I set vVertex value with glGetAttribLocation() and glVertexAttribPointer().

std::vector<GLfloat> quadVerts = {
    -1, -1, 0, 0, 1,
    -1, 1, 0, 0, 0,
    1, 1, 0, 1, 0,
    -1, -1, 0, 0, 1,
    1, 1, 0, 2, 0,
    1, -1, 0, 1, 1 };

GLuint quadVbo;
glGenBuffers(1, &quadVbo);
glBindBuffer(GL_ARRAY_BUFFER, quadVbo);
glBufferData(GL_ARRAY_BUFFER, 6*3*4, &quadVerts[0], GL_STATIC_DRAW);
GLuint vVertex = fboShad->getLocation("vVertex");
GLuint vUV = fboShad->getLocation("vUV");
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), NULL);

glEnableVertexAttribArray(vVertex);
glVertexAttribPointer(vVertex, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0);
glEnableVertexAttribArray(vUV);
glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(3 * sizeof(GLfloat)));
glDrawArrays(GL_TRIANGLES, 0, 6);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(vVertex);
glDisableVertexAttribArray(vUV);

I don't know if the mistake is in the process, or maybe is not correct the use of attributes in fragment shader ( I suppose that 'layout(binding=1)', if you use shader with FBO bound, tooks GL_COLOR_ATTACHMENT_1 texture); or the use of 'vTexCoords' as the .xy values of vertex.

1

There are 1 answers

4
Andon M. Coleman On

I think you are confusing sampler bindings with fragment data output locations. While the two things can both be assigned using a layout (...) qualifier, they are very different.

layout (location = X) out vec3 color assigns the output color to GL_COLOR_ATTACHMENT0 + X

layout (binding = Y) sampler2D texHDR tells GLSL to use texture image unit GL_TEXTURE0 + Y

Your fragment shader only writes to a single output, so there is no actual reason to have multiple color attachments in this situation. You attach images to FBOs in order to write to them from a fragment shader, not to read from them as a texture. In fact, it is undefined behavior to read from a texture at the same time as it is attached to an FBO for writing without using special extensions (e.g. GL_NV_texture_barrier).


What you actually want to do in this situation is the following:

Modified Fragment Shader:

#version 420
smooth in vec2 vTexCoord;
//out vec4 vFragColor;

layout(location=0) out     vec3      color;  // Fragment Data Output Location
layout(binding=0)  uniform sampler2D texHDR; // Texture Image Unit Binding

void main(void)
{
//vFragColor = texture(textureMap, vTexCoord);
//color = vec4(1.0,0.5,0.5,0.5);
   color = texture(texHDR,vTexCoord);
}

Now, the texture you want to read should be bound to GL_TEXTURE0 (this is the default unless you manually call glActiveTexture (...) somehwere) and the texture you want to output to should be attached to your Framebuffer Object at GL_COLOR_ATTACHMENT0.

The most important thing to keep in mind here is that the binding and location qualifiers are completely separate: Color Attachment 0 does not correspond to Texture Image Unit 0.