Why datas use glReadPixels read from GL_COLOR_ATTACHMENT0 and GL_BACK are different? - opengl

I have codes lide this:
void init()
{...
glGenRenderbuffers(1, &colorPattern);
glBindRenderbuffer(GL_RENDERBUFFER, colorPattern);
glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA,outputSize[0],outputSize[1]);
glGenRenderbuffers(1, &depthPattern);
glBindRenderbuffer(GL_RENDERBUFFER, depthPattern);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32F, outputSize[0], outputSize[1]);
glGenFramebuffers(1, &patternFrame);
glBindFramebuffer(GL_FRAMEBUFFER, patternFrame);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER, colorPattern);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthPattern);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
}
Then I draw something with GL_BLEND enabled both in main framebuffer glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);and framebuffer glBindFramebuffer(GL_DRAW_FRAMEBUFFER, patternFrame);
At last,read some data by glReadPixels():
void display(){
...
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, patternFrame);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_POINTS, 0, Num);
glBindFramebuffer(GL_READ_FRAMEBUFFER, patternFrame);
glReadBuffer(GL_COLOR_ATTACHMENT0);
float test[4];
glReadPixels(20, 200, 1, 1, GL_RGBA, GL_FLOAT, test);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_POINTS, 0, Num);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glReadBuffer(GL_BACK);
glReadPixels(20, 200, 1, 1, GL_RGBA, GL_FLOAT, test);
I find the data from all rgba chanel of patternFrame and framebuffer 0 is diferent.The alpha chanel of patternFrame is a fraction between 0 and 1, and constant 1 in main framebuffer.Why this happened?

Related

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

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);

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
}

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 glReadPixels gets 1282 error

I would like to create an offscreen renderer with OpenGL.
I've created a FBO and a RBO to call the glReadPixels(), but I always get an error.
This is my code:
// Init
GLuint fbo;
GLuint rbo;
glGenFramebuffers(1, &fbo);
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
// Render loop
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
...
std::vector<unsigned char> output(width * height * 4);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &output[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// Deinit
glDeleteRenderbuffers(1, &rbp);
glDeleteFramebuffers(1, &fbo);
The output doesn't contains anything and the glGetError() function always returns 1282 (GL_INVALID_OPERATION) after the call to glReadPixels().
What's the problem with this code?

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.