Hello. I have a multisampled framebuffer with two color attachments, one with RGBA8
and another with R32F
and I want to blit it to another framebuffer, to resolve the multisampling (, do some other work) and finally render the final image.
After I blit the first framebuffer to the second, I want to read from the second framebuffer with glReadPixels
, to implement mouse picking, so read one pixel, one specific float value. The problem is that when I hover my mouse on and read from any edge of any model (that is anti-aliased), the value read is something apparently random, not the the correct one.
I disabled multisampling and tried the same thing and everything works fine, the float values read are always correct. This tells me that when I blit the framebuffer and I resolve both attachments, the float values at the edges get transformed in some way, which is not what I want.
My question is: is there some way to prevent this, or fix this problem? Can I do something?
If this is an anti-aliased model rendered on the screen, then the pipes represent the pixels with correct float values, and the colons represent the incorrect values:
:::::::::::::
:|||||||||||:
:|||||||||||:
:|||||||||||:
:|||||||||||:
:::::::::::::
Code for first framebuffer:
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// First attachment
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorageMultisample(
GL_RENDERBUFFER, samples, RGBA8, width, height
);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_RENDERBUFFER, renderbuffer
);
// Second attachment
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorageMultisample(
GL_RENDERBUFFER, samples, R32F, width, height
);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1, GL_RENDERBUFFER, renderbuffer
);
// Depth and stencil...
GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, attachments);
Code for second framebuffer:
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// First attachment
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexStorage2D(GL_TEXTURE_2D, 1, RGBA8, width, height);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, texture, 0
);
// Second attachment
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorage(
GL_RENDERBUFFER, R32F, width, height
);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1, GL_RENDERBUFFER, renderbuffer
);
GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, attachments);
Code for blitting:
glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_framebuffer);
for (size_t i = 0; i < 2; i++) {
glReadBuffer(GL_COLOR_ATTACHMENT0 + i);
glDrawBuffer(GL_COLOR_ATTACHMENT0 + i);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
glDrawBuffers(2, attachments);
All rendering looks somewhat like this:
// Bind the first, multisampled framebuffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(0, 0, width, height);
// Disable blending to not mess up the second, floating-point attachment
glDisablei(GL_BLEND, 1);
// Render all models...
// Re-enable blending
glEnablei(GL_BLEND, 1);
// Blit the resulted scene texture to an intermediate texture, resolving anti-aliasing
// Bind the second, normal framebuffer
// Read one pixel with glReadPixels
// Here I can print and see the float value
// Render the final image to the screen
I can provide more details, if needed.