I ran the framebuffers example in this page -original code- (using glfw3 and glew in xcode 4.6 in osx 10.8), it worked fine, then I wanted to add multisampling (to avoid jagged edges on cube edges and on the floor, glfwWindowHint (GLFW_SAMPLES, 4) was enough when rendering directly to the back-buffer), found some answers directing to opengl.org, tried to use glTexImage2DMultisample but it displayed nothing (black screen). The framebuffer settings and rendering loop is:
// Create frame buffer
GLuint frameBuffer;
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
// Create texture to hold color buffer
GLuint texColorBuffer;
glGenTextures(1, &texColorBuffer);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texColorBuffer);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, width, height, GL_FALSE);
/*
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
*/
//glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texColorBuffer, 0);
// Create Renderbuffer Object to hold depth and stencil buffers
GLuint rboDepthStencil;
glGenRenderbuffers(1, &rboDepthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil);
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil);
// ...
while (!window->shouldClose()) {
static int rot = 0;
// Bind our framebuffer and draw 3D scene (spinning cube)
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
auto err_res = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(err_res != GL_FRAMEBUFFER_COMPLETE) {
ERR("Incomplete frameBuffer:%X!", err_res);
goto end;
}
glBindVertexArray(vaoCube);
glEnable(GL_DEPTH_TEST);
glUseProgram(sceneShaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texKitten);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texPuppy);
// Clear the screen to white
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
// Draw cube
glEnable(GL_MULTISAMPLE);
glDrawArrays(GL_TRIANGLES, 0, 36);
glEnable(GL_STENCIL_TEST);
// Draw floor
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
glDepthMask(GL_FALSE);
glClear(GL_STENCIL_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 36, 6);
// Draw cube reflection
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilMask(0x00);
glDepthMask(GL_TRUE);
model = glm::scale(glm::translate(model, glm::vec3(0, 0, -1)), glm::vec3(1, 1, -1));
glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
glUniform3f(uniColor, 0.3f, 0.3f, 0.3f);
glDrawArrays(GL_TRIANGLES, 0, 36);
glUniform3f(uniColor, 1.0f, 1.0f, 1.0f);
glDisable(GL_STENCIL_TEST);
/*
// Bind default framebuffer and draw contents of our framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
glBindVertexArray(vaoQuad);
glDisable(GL_DEPTH_TEST);
glUseProgram(screenShaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texColorBuffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
*/
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Make sure no FBO is set as the draw framebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer); // Make sure your multisampled FBO is the read framebuffer
glDrawBuffer(GL_BACK); // Set the back buffer as the draw buffer
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
// Swap buffers
glfwSwapBuffers(window->getHandle());
glfwPollEvents();
}
The 'EXT' additions are probably unnecessary but I also tried to run without them before and the result was the same. What am I doing wrong?
EDIT: Now binding GL_TEXTURE_2D_MULTISAMPLE and getting GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE error!
If you checked your framebuffer object for completeness, you would probably have caught this by now... your depth/stencil buffer needs to be multisampled as well.
A framebuffer is considered multisample incomplete by both core and the EXT FBO extension if one attachment has a different number of samples than any other attachment. In your case, you have a color buffer attachment with 4 samples and a depth/stencil attachment with 1 sample.
Name
glCheckFramebufferStatus— check the completeness status of a framebufferDescription
glCheckFramebufferStatusqueries the completeness status of the framebuffer object currently bound totarget.targetmust beGL_DRAW_FRAMEBUFFER,GL_READ_FRAMEBUFFERorGL_FRAMEBUFFER.GL_FRAMEBUFFERis equivalent toGL_DRAW_FRAMEBUFFER.The return value is
GL_FRAMEBUFFER_COMPLETEif the framebuffer bound to target is complete. Otherwise, the return value is determined as follows:[...]
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLEis returned if the value ofGL_RENDERBUFFER_SAMPLESis not the same for all attached renderbuffers; if the value ofGL_TEXTURE_SAMPLESis the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value ofGL_RENDERBUFFER_SAMPLESdoes not match the value ofGL_TEXTURE_SAMPLES.
glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
By the way, since your implementation is >= 3.0, you do not need the EXT suffix on anything. All of the constants defined by the EXT extension are identical to ARB / core FBOs, but some of the EXT functions (such as glCheckFramebufferStatusEXT) have more restrictive behavior (requiring each attachment to have the same image dimensions, for instance).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With