🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

OpenGL 4 FBO

Started by
19 comments, last by taby 1 year, 8 months ago

From what I've gathered, the only way to retrieve the contents of the default framebuffer is to use glReadPixels. This reads the pixels data to a CPU texture. It is not the fastest method.

Can anyone help clarify how I would use a framebuffer object to render to a texture? Sorry if the question seems vague. My knowledge of framebuffer objects is still primitive.

Advertisement

30 seconds of google search , usually you don't want to read back pixels, you pass the texture generated in the fbo to a pixel shader to further elaboration, may I ask what you want exactly to achieve ?

Dependent on what you try to achieve. You may read pixels from the framebuffer directly - for instance to take screenshots.

But its almost always a better idea to use a Framebuffer Object (FBO). The FBO itself does little - but you can attach color & depth textures to it and bind it as a render target. This way you can render to textures which you can then use in shaders for further processing.

At the end of the render pipeline you may need to render to the screen by setting the render target to NULL. Usually what people do it to have a postprocessing shader do that. A simple postprocessing shader could, for example, adjust gamma and saturation. But you can also do complicated things like SSAO, FXAA, fog, outlines etc. but most require you to have a depth-buffer texture too.

Simplest implementation:

// CREATE FBO AND ATTACH COLOR & DEPTH BUFFER (USE glGetError() TO CHECK RESULT!)
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);

// ENABLE FBO
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // USE 0 TO DISABLE FBO

Make sure to have the depth buffer attachment to have the GL_DEPTH_COMPONENT format, the color attachment (texture) should have NATIVE_PIXEL_FORMAT_32BPP. From my experience using glTexStorage2D is not neccessary, but maybe check that out too. Using glTexImage2D should do the trick when creating render targets.

However, there are a few pitfalls when using FBOs. For example, you should always use glViewport to adjust the output to the size of the textures. Depth and Color must be the same size and the right format. You may also want to use glDrawBuffer and glReadBuffer to fix some problems that may occour from switching to FBOs and back.

Also glCheckFramebufferStatus(GL_FRAMEBUFFER) can help you with debugging your rendering pipeline in case of errors.

When using the render target textures in shaders (e.g. postprocessing), just unbind the FBO or the textures and use “uniform sampler2D” for both the color & depth. As I remember there is another sampler type for the depth buffer but I personally never needed it. You may simple do: float z = texture2D(DepthMap, co).z;

Thank you for the advice. I realize now that one must use depth and colour attachments of the same size. I’ll keep struggling. ?

i need to render to a texture, which I will use as input for a full screen quad.

Holy cow. I got it working. Does anyone feel like they’re constructing houses of cards, and one wrong move destroys 500 right moves. LOL

I used multiple framebuffers. One to calculate shadows, and one to render to a texture. Then I render that texture to the default framebuffer using a passthrough post-processing shader.

My question is now…. how do I use the depth and colour data to perform depth of field calculation? For instance, how do I use the depth data in the shader? I am basically calculating frag.r = pow(frag.r, 100.0);

To access the depth in the depth map, just bind the depth texture to the same texture stage you bind the uniform sampler to.

// set depthmap to texture stage 3
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE2D, depthmap);

// set "DepthMap" uniform in shader program to 3
waSetUniform1i(glGetUniformLocation(shader, "DepthMap"), 3);

Then in the fragment shader you may do:

uniform sampler2D DepthMap;

void main() {
	float z = texture2D(DepthMap, co).z;
	gl_FragColor.rgb = vec3(pow(z,100.0));   // try bigger values to make "z" visible
}

This should produce a visible image.

Thanks for the presentation. This is of course how I did it as well.

I think that I will use a compute shader to blur the image several times. once the blurred texture is generated, then calculating the rest is pretty straightforward.

Was your question how to blur an image based on depth-values?

yeah, all I need to do is blur the image now. Thanks for your help.

Blurring the image several times - maybe glGenerateMipmap can do that for you.

This topic is closed to new replies.

Advertisement