is it possible to copy the default framebuffer to another framebuffer object in OpenGL? - c++

I am trying to copy the default framebuffer after rendering on to the screen to another custom framebuffer in OpenGL. Below is my code. Do you see anything wrong? BLit call is successful but I don't see anything rendering.
void drawDisplayList() {
setNormalDraw();
clear();
drawDisplayLists();
drawDisplayLists();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glReadBuffer(GL_FRONT);
glBindFramebuffer(GL_FRAMEBUFFER, geomFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, geomFBO);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, _scrWidth, _scrHeight, 0, 0, _scrWidth, _scrHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
GLenum errorCode1;
errorCode1 = glGetError();
if (errorCode1 != GL_NO_ERROR) {
printf("glBlitFramebuffer Success!");
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
My FBO Intialization
void createFboBuffers()
{
glGenFramebuffers(1, &geomFBO);
glBindFramebuffer(GL_FRAMEBUFFER, geomFBO);
glGenRenderbuffers(1, &color_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, color_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, this->size().width(), this->size().height());
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_rbo);
glGenRenderbuffers(1, &depth_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, depth_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, _scrWidth, _scrHeight);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rbo);
}
Any pointers please. Looks like Nothing is copied to another FrameBuffer.

The instruction glBindFramebuffer(GL_FRAMEBUFFER, geomFBO) binds the framebuffer object to both the read and draw framebuffer targets (see glBindFramebuffer). This breaks the binding of the default framebuffer to the read framebuffer target. Just remove:
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glReadBuffer(GL_FRONT);
// glBindFramebuffer(GL_FRAMEBUFFER, geomFBO); <-- DELETE
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, geomFBO);

Related

Write to OpenGL multiple renderbuffer failed

Not sure what is the problem, it failed to read the pixels when writing to multiple renderbuffer. Here is the code:
setup code:
// gen framebuffer object
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// gen renderbuffer 0
glGenRenderbuffers(1, &rbo_color0);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_color0);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, w, h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo_color0);
// gen renderbuffer 1
glGenRenderbuffers(1, &rbo_color1);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_color1);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RED_INTEGER, w, h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rbo_color1);
// gen depth buffer
glGenRenderbuffers(1, &rbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
render and read pixel code:
// setup shader and uniforms...
// bind framebuffer and clear color/depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glEnable(GL_DEPTH_TEST);
glClearColor(0.f, 0.f, 0.f, 0.1f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const GLuint buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, buffers);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, (void*)0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, data);
glReadBuffer(GL_COLOR_ATTACHMENT1);
glReadPixels(x, y, 1, 1, GL_RED_INTEGER, GL_INT, (int*)(data) + 4);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
I used layout qualifier in the shader for the outputs, shouldn't be any problems there. So I think probably there is something wrong the the buffer setup or render code.
I've succeed in reading the pixels when there is only one renderbuffer(rbo_color0). The main difference is:
no generation code for renderbuffer1;
use glDrawBuffer(rbo_color0) when rendering;
the format of rbo_color0 is GL_RGBA(double checked the format setting in corresponding glRenderbufferStorage/glReadBuffer calls, no problem here);
no read pixel call for rbo_color1.
Any helps?
GL_RED_INTEGER is not a proper internal format, as it can be used for the 2nd parameter of glRenderbufferStorage.
A proper enumerator constant for the internal format would be GL_R32I.
See OpenGL 4.6 API Compatibility Profile Specification; 8.26. TEXTURE IMAGE LOADS AND STORES; page 334
If you would check for OpenGL erros (glGetError), then you would get an INVALID_ENUM error.
Change the render buffer storage specification, to solve the issue:
glRenderbufferStorage(GL_RENDERBUFFER, GL_R32I, w, h);
Note, you should check the framebuffer completeness by glCheckFramebufferStatus:
GLenum fb_status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if ( fb_status != GL_FRAMEBUFFER_COMPLETE )
{
// error handling
}

OpenGL Framebuffer Missing Faces

I'm having an issue using OpenGL to implement multi-pass shaders to enable HDR.
The first pass renders the scene to a framebuffer.
The second pass uses the framebuffer with color and depth to render to a quad.
(I'm following this tutorial.)
The problem is it does not render certain (front, top and one side) cube faces.
If I render without the framebuffer (without changing any of the other render code), it works as it should.
I have tried to change the winding of the faces using GL_CCW and GL_CW and changing the glDepthFunc to no avail.
This is the code the renderer is initialized with:
Renderer::Renderer(Window window): window(window) {
this->materials = std::map<std::string, Material>();
this->meshes = std::map<std::string, Mesh>();
// glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_FRAMEBUFFER_SRGB);
glViewport(0, 0, window.width, window.height);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
this->load_textures();
this->load_materials();
this->load_meshes();
this->load_shader_programs();
this->create_hdr(this->shader_programs.find("hdr")->second);
}
This generates the framebuffer before the first render:
void Renderer::create_hdr(ShaderProgram sp_hdr) {
glGenFramebuffers(1, &this->hdr_fbo);
glGenTextures(1, &this->color_buffer);
glBindTexture(GL_TEXTURE_2D, this->color_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, this->window.width, this->window.height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenRenderbuffers(1, &this->render_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, this->render_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, this->window.width, this->window.height);
glBindFramebuffer(GL_FRAMEBUFFER, this->hdr_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->color_buffer, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->depth_buffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "Framebuffer not complete!" << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(sp_hdr.id);
glUniform1i(glGetUniformLocation(sp_hdr.id, "hdr_buffer"), 0);
}
This renders the level in two passes:
void Renderer::render(Level level, Camera camera, std::vector<std::reference_wrapper<DirectionalLight>> d_lights, std::vector<PointLight> p_lights, std::vector<SpotLight> s_lights) {
// 1. First Pass - HDR
glBindFramebuffer(GL_FRAMEBUFFER, this->hdr_fbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ShaderProgram sp_render = this->shader_programs.find("render")->second;
glUseProgram(sp_render.id);
attach_camera(camera, sp_render);
attach_projection_matrix(camera, sp_render);
attach_view_matrix(camera, sp_render);
unsigned int d_light_num = 0;
for (DirectionalLight d_light : d_lights) {
attach_d_light(d_light, sp_render, d_light_num);
d_light_num++;
}
for (Block block : level.blocks) {
attach_position(block.position, sp_render);
Material material = this->materials.find(block.material_id)->second;
attach_material(material, sp_render);
Mesh mesh = this->meshes.find(block.mesh_id)->second;
draw_mesh(mesh, sp_render);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 2. Second Pass - Render to quad
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ShaderProgram sp_hdr = this->shader_programs.find("hdr")->second;
glUseProgram(sp_hdr.id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->color_buffer);
draw_mesh(this->meshes.find("quad")->second, sp_hdr);
}
I fixed this by actually connecting the correct depth render buffer:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->depth_buffer);
to
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->render_buffer);

How to render anti-aliased image to a texture (and then write to PNG)?

I'd like to use the "render to texture" paradigm to write a .png screenshot of my OpenGL 3D rendering. I have it working without multi-sampling, but I'm struggling to get an anti-aliased image.
First of all, is this possible?
Second, what is the right combination of API calls?
(meta third question, how can I better debug this? glCheckFramebufferStatus is clearly not enough).
Here's what I'm working with:
// https://stackoverflow.com/questions/7402504/multisampled-render-to-texture-in-ios
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
GLuint resolved_framebuffer, resolvedColorRenderbuffer;
glGenFramebuffers(1, &resolved_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, resolved_framebuffer);
glGenRenderbuffers(1, &resolvedColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, resolvedColorRenderbuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
GLuint colorRenderbuffer, depthRenderbuffer;
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
glClearColor(background_color(0), background_color(1), background_color(2), 0.f);
glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);
draw_scene();
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebuffer );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, resolved_framebuffer );
// https://forum.juce.com/t/ios-8-getting-the-demo-building/13570/20
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// ^--- this is throwing `GL_INVALID_OPERATION`
GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
writePNG(pixels);
Currently I'm getting a blank image and glBlitFramebuffer is throwing GL_INVALID_OPERATION. Apparently this error can correspond to many things, and I'm not sure which is applying. My buffers seem "good" according to glCheckFramebufferStatus.
This question has been asked in similar forms before:
Cannot render to texture with multisampling
Multisampled render to texture in ios
But none of the answers have lead to a complete working example. I would love to find/create a minimal example of this.
The tutorial at https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing basically had what I needed. The working solution is:
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a multisampled color attachment texture
unsigned int textureColorBufferMultiSampled;
glGenTextures(1, &textureColorBufferMultiSampled);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
// create a (also multisampled) renderbuffer object for depth and stencil attachments
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// configure second post-processing framebuffer
unsigned int intermediateFBO;
glGenFramebuffers(1, &intermediateFBO);
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
// create a color attachment texture
unsigned int screenTexture;
glGenTextures(1, &screenTexture);
glBindTexture(GL_TEXTURE_2D, screenTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); // we only need a color buffer
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
draw_scene();
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
writePNG(pixels);
It seems there're at least two errors in the code in the original question:
The framebuffer should have a multisample texture attached, not a renderbuffer (glFramebufferTexture2D(... GL_TEXTURE_2D_MULTISAMPLE instead of glRenderbufferStorageMultisample)
Must call glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); after blitting and before glReadPixels

OpenGL MSAA in 2 different ways. What are the differences?

I have been looking for OpenGL Multi Sample Anti Aliasing tutorials and I found many but I'll take 2.
They use a different way to do this. I have tested both ways and both work for my project so I can use any of them.
I use this to render my game engine scene to a texture.
This is the 1st way:
Create the FBO with MSAA
// create a texture object
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a MSAA framebuffer object
// NOTE: All attachment images must have the same # of samples.
// Ohterwise, the framebuffer status will not be completed.
glGenFramebuffers(1, &fboMsaaId);
glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId);
// create a MSAA renderbuffer object to store color info
glGenRenderbuffers(1, &rboColorId);
glBindRenderbuffer(GL_RENDERBUFFER, rboColorId);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, MSAA_level, GL_RGB8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// create a MSAA renderbuffer object to store depth info
// NOTE: A depth renderable image should be attached the FBO for depth test.
// If we don't attach a depth renderable image to the FBO, then
// the rendering output will be corrupted because of missing depth test.
// If you also need stencil test for your rendering, then you must
// attach additional image to the stencil attachement point, too.
glGenRenderbuffers(1, &rboDepthId);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepthId);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, MSAA_level, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach msaa RBOs to FBO attachment points
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboColorId);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepthId);
// create a normal (no MSAA) FBO to hold a render-to-texture
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach a texture to FBO color attachement point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
// attach a rbo to FBO depth attachement point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId);
//## disable color buffer if you don't attach any color buffer image,
//## for example, rendering the depth buffer only to a texture.
//## Otherwise, glCheckFramebufferStatus will not be complete.
//glDrawBuffer(GL_NONE);
//glReadBuffer(GL_NONE);
// check FBO status
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
And when I need to draw the scene
glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId);
glViewport(0, 0, width, height);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawScene();
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMsaaId);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
glBlitFramebuffer(0, 0, width, height, // src rect
0, 0, width, height, // dst rect
GL_COLOR_BUFFER_BIT, // buffer mask
GL_LINEAR); // scale filter
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, App->window->GetWidth(), App->window->GetHeight());
The 2nd way:
Create the FBO with MSAA
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a multisampled color attachment texture
unsigned int textureColorBufferMultiSampled;
glGenTextures(1, &textureColorBufferMultiSampled);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, SCR_WIDTH, SCR_HEIGHT, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
// create a (also multisampled) renderbuffer object for depth and stencil attachments
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// configure second post-processing framebuffer
unsigned int intermediateFBO;
glGenFramebuffers(1, &intermediateFBO);
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
// create a color attachment texture
unsigned int screenTexture;
glGenTextures(1, &screenTexture);
glBindTexture(GL_TEXTURE_2D, screenTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); // we only need a color buffer
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Intermediate framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
And when I need to draw the scene:
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, width, height);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawScene();
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, App->window->GetWidth(), App->window->GetHeight());
Summarizing:
1st way: Create FBO, create RBO for color and RBO for depth and use glRenderbufferStorageMultisample(...) to specify the MSAA level. Then create other FBO with texture for color and RBO for depth.
2nd way: Create FBO, create Texture for color and RBO for depth and using glTexImage2DMultisample(...) for MSAA level in the texture. Then create other FBO and a texture.
What are the differences on using one way or other? Is one better than the other?
MSAA setup in your example is actually the same in both cases. The only difference between the two methods you depicted is - different FBO attachment type. In general, you will want to attach a texture and not render buffer when you later need to use the information from that FBO for further render passes. In such a case you would plug previous render pass FBO's texture attachment into texture unit, and sample from it in the next pass shader program. Shadow mapping is one of such cases.

Multisampling OpenGL FBO

I'm trying to render 3D scene to multisample FBO. I creating FBO with following code FBO:
GLuint fbo, vtex, depthbuffer;
glGenTextures(1, &vtex); GLCHECK();
glBindTexture( vtarget, vtex ); GLCHECK();
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, samples /*=4*/, GL_RGBA, width, height, false); GLCHECK();
glBindTexture(vtarget, 0); GLCHECK();
glGenRenderbuffers(1, &depthbuffer); GLCHECK();
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer); GLCHECK();
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples/*=4*/, GL_DEPTH_COMPONENT32, width, height); GLCHECK();
glBindRenderbuffer(GL_RENDERBUFFER, 0); GLCHECK();
glGenFramebuffers( 1, &fbo );GLCHECK();
glBindFramebuffer( GL_FRAMEBUFFER, fbo );GLCHECK();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer); GLCHECK();
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, vtex, 0 ); GLCHECK();
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
{
fprintf(stderr, "Can't allocate frame buffer! Status: 0x%x\n", status);
assert(0);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0); GLCHECK();
And I get error GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE. What I'm doing wrong?
A have read this topic, FBO documentation, but it doesn't help.
I can create FBO without depth attachment. But in this case it doesn't working when I trying bilt it to the screen:
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); GLCHECK();
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); GLCHECK();
glDrawBuffer(GL_BACK); GLCHECK();
glBlitFramebuffer(0, 0, resolution.width, resolution.height, 0, 0, resolution.width, resolution.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GLCHECK();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Help me please.
You need to specify fixed sample locations. e.g. GL_TRUE for the last parameter of glTexImage2DMultisample.
You can read about the reasons for GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE here.