Problem with taking screenshot using glReadPixels

Hi,

I have a an GUI application written in wxPython which uses opengl. I use glReadPixels to save currently rendered scene to image (ppm/tif). The problem is that statusbar and menubar are included in the picture. I call glReadPixels this way:


glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], GL_RGBA, GL_UNSIGNED_BYTE, *pixbuf)

The viewport is set according to the canvas size.

I asked this question on wxpython mailing list but I got no answer. This problem doesn’t have to be related to wxpython because I have similar experience with Tcl/Tk. Sorry if this question is not appropriate for this forum but I thought someone had similar problems and could help me.

Thanks a lot
Anna

glReadPixels from the system framebuffer (typically a window) will return the pixels in the window’s region of the framebuffer. If another window happens to be on top (obscuring part/all of your window), then you’ll get its appearance in the readback.

If you don’t want this behavior, don’t render to the on-screen window (system framebuffer). Instead render to an off-screen texture or renderbuffer using a framebuffer object (FBO). Then you don’t have to worry about other windows occluding yours, obscuring readbacks.

Thanks for your reply. I tried to use FBO but I can’t make it work. I used the same code as here (without the texture stuff).
When I call


glGenFramebuffersEXT(1, &fb);

and check fb, its 0 but I get no error. What could be wrong with it?

Anna

Have you created a GLX context and and made it active first?

Firstly, what do u mean “without the texturing stuff”. You will need at least one texture if u want to render to an offscreen image.
Secondly, the returned value of the fbo variable does not tell u anything about the FBO. You should first glGenFramebuffers then glBindFramebuffers and then attach the COLORATTCHMENT textures and finally check the framebuffer status. If the status is not FRAMEBUFFERCOMPLETE there is something wrong and you need to check the fbo settings and texture formats etc. So in a typical use case, the fbo setup code is this,


GLuint fboID; //our fbo object
GLuint texID; //the offscreen texture where the rendering will be drawn to.
void InitFBO(int textureWidth, int textureHeight) {
   glGenFramebuffers(1, &fboID);
   glGenTextures(1, &texID);

   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
   glBindTexture(GL_TEXTURE_2D, texID);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight,  0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 
   glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,	
GL_TEXTURE_2D,texID,0);

   GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
   if (status == GL_FRAMEBUFFER_COMPLETE ) {
	printf("FBO setup succeeded.");
   } else {
	printf("Problem with FBO setup.");
   }
	
   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}

See if this helps.

Thanks a lot, this helped. What should be the next steps to render the scene to an image? I thought I don’t need any texture for that.
Sorry for my silly questions, I try to google a lot but in the end I’m just confused.

Thanks
Anna

For rendering on the offscreen texture, you would first setup the viewport to the size of the offscreen texture. Then bind your fbo. Then call glDrawBuffers(1, &attchID[0]); Then you will call glClear and finally render whatever you want. So in code, this is the typical use case.


GLenum attchID[1]={GL_COLOR_ATTACHMENT0};

void RenderOffscreen(int texWidth, int texHeight) {
   glPushAttribute(GL_VIEWPORT_BIT);
   glViewport(0,0,texWidth, texHeight);
   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
   glDrawBuffers(1, attchID);		
   glClear(GL_COLOR_BUFFER_BIT);
      //Render your stuff here
   glBindFramebuffer( GL_FRAMEBUFFER, 0 );
   glReadBuffer(GL_BACK);
   glDrawBuffer(GL_BACK); 
   glPopAttribute(GL_VIEWPORT_BIT);
}

Now the above code assumes that you do not use the depth test. If you need that, you will need to add renderbuffer to the fbo. Details can be found in the fbo tutorials on the internet.

See if this helps.

If I understand it correctly, after this step, the scene is rendered to the texture. How can I save the texture to an image? I thought there exists a more straightforward way.

Thanks
Anna

How can I save the texture to an image?

What do u mean? You want to save it as a jpeg/gif/png? If thats the case, use glReadPixels and then dump it into a file. It would be better to use somthing like DevIL which does this for a lot of formats with a single function.