PDA

View Full Version : glCopyPixels(), Pre-rendering + recalling colour & depth channels.



TheSuese
08-06-2012, 07:35 AM
I am using OpenGL in 2D mode to make a game with a static environment from a fixed camera perspective.

I want to
1. Pre-render the static environment.
2. Store the resulting 2D image to the GPU including both colour and depth channels
3. Recall the pixels quickly.

Here is what I think I am supposed to do:

1. Create a frame buffer object
2. Create two renderbuffer objects: one colour, one depth, both 256x256 pixels
3. Attach both renderbuffers to the appropriate attachment points on the framebuffer.
4. Bind the virtual frame buffer, draw an image with depth parameters specified.

5. use glCopyPixels() to copy it to the screen. <--XX DANGER: THIS IS WHERE THINGS GO WRONG


steps_1_through_4_above(); //create an FBO w/ 2xRBOs, and draw a picture to it.
glLoadIdentity ();
glOrtho (0, 256, 256, 0, 0, 1);
glViewport(0,0,256,256);
glMatrixMode (GL_MODELVIEW);
glPixelTransferi(GL_MAP_COLOR,true);
glRasterPos2i(256,256);
glCopyPixels(0,0,256,256,GL_COLOR);

My problem is specifically that I cannot seem to figure out how to copy the pixels from one frame buffer to another one.

I think I've isolated the problem to specifically this and nothing else that is obvious. steps 1 through 4 are working properly, and I am properly invoking my OSes double-buffer switching routine in order to actually display the results. I get a black square but not the image I rendered, which I checked with some alternate code that renders to a texture (a technique I am familiar with).

I believe my problem is a misunderstanding with glCopyPixels(). I could not find a working example of glCopyPixels() copying from a virtual frame buffer object to the screen, so finally I ask for advice.

How do I copy pixels from one frame buffer object to another including the depth and colour components?

Thanks.

kyle_
08-06-2012, 07:54 AM
Please, dont use glCopyPixels, for anything.
You have FBO's then i assume you also have access to glBlitFramebuffer (they are actually very similar in how you could use them).

Since you want to copy from one framebuffer to another, you need to utilize read and draw framebuffer bindings:
If you want to use glCopyPixels you need to have RasterPos set to begining of the region (ie. 0,0).



glBindFramebuffer(GL_READ_FRAMEBUFFER, FBO); //this binds stuff you rendered as 'source'
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); //this binds default fbo (ie. window) as 'destanation'

//glCopyPixels/glBlitFramebuffer does actual copying here.

TheSuese
08-06-2012, 08:04 AM
Hmm, okay. I did not know this was possible.
The documentation says the first argument of glBindFramebuffer "Must always be GL_FRAMEBUFFER"

I tried it but it would not compile.



glBindFramebufferEXT(GL_READ_FRAMEBUFFER,my_fbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER,0);

Compiler says "GL_READ_FRAMEBUFFER undeclared".

Same thing happens if I try GL_READ_FRAMEBUFFER_EXT: Undeclared.

Suggestions?

kyle_
08-06-2012, 08:09 AM
Check your extension string. If you are on GL < 3.0 and dont have GL_ARB_framebuffer_blit extension then you wont have the tokens (and blit) without the suffix.
Versions with the suffix are in GL_EXT_framebuffer_blit. If you dont have this as well, then you wont be able to use glBlitFramebuffer nor glCopyPixels to directly copy from one framebuffer to another.

You will have to write a simple shader that samples the texture (you will need to render to texture and not renderbuffer) and fills fullscreen quad with its content.

TheSuese
08-06-2012, 08:18 AM
So are these features particularly well-supported in various environments? I'm testing in C but I will be working in Java for Android / OUYA. Am I really getting a performance boost by firing this technique through the graphics accelerator or should I just brave the dirty-stinking home-brew java code that's going to push hundreds of sprites onto the screen using a z-depth map and pray it performs?

TheSuese
08-06-2012, 08:42 AM
void select_texture(){
glLoadIdentity();
glOrtho (0, 256, 0, 256, 0, 1);
glViewport(0,0,256,256);
glMatrixMode (GL_MODELVIEW);

}

void select_screen(int w,int h){
glLoadIdentity ();
glOrtho (0, w, h, 0, 0, 1);
glViewport(0,0,w,h);
glMatrixMode (GL_MODELVIEW);

}
int main() {

GLuint my_fbo;
GLuint color_rb;

set_gfx_mode(GFX_OPENGL_WINDOWED, 512, 512, 0, 0);

glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);

glGenRenderbuffersEXT(1,&color_rb);

glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, color_rb);
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_RGB, 256, 256 );

glGenFramebuffersEXT(1, &my_fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL _COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, color_rb );

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,my_fbo);
select_texture();
glClearColor(0,0,1,1);
glClear( GL_COLOR_BUFFER_BIT );


//clear our 'screen'.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
glClearColor(0.2,0.2,0.2,1);
glClear( GL_COLOR_BUFFER_BIT );

select_screen(512,512);
glBindFramebufferEXT(GL_FRAMEBUFFER_INCOMPLETE_REA D_BUFFER_EXT,my_fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_INCOMPLETE_DRA W_BUFFER_EXT,0);
glPixelTransferi(GL_MAP_COLOR,GL_TRUE);
glRasterPos2i(0,256);
glCopyPixels(0,0,256,256,GL_COLOR);

/* Flip the backbuffer on screen */
allegro_gl_flip();

return 0;
}



My expectation is a blue box. The result is a black box.

These were the closest symbols I could find to GL_READ_FRAMBUFFER and GL_DRAW_FRAMEBUFFER. I also couldn't find FrameBufferBlit()

BionicBytes
08-06-2012, 09:48 AM
void select_texture(){
glLoadIdentity();
glOrtho (0, 256, 0, 256, 0, 1);
glViewport(0,0,256,256);
glMatrixMode (GL_MODELVIEW);

You are not specifying the correct matrix before using this, are you?
glMatrixMode (GL_PROJECTION);

For the blit functionality, you need to be checking for ARB_FRAMEBUFFER_OBJECT and then initialise those pointer functions and use the appropriate header(s).

TheSuese
08-06-2012, 07:04 PM
Hmm.. Thanks for the reply.

Check out select_screen(w,h) function in my example above, then check out how it is applied:



select_screen(512,512);
glBindFramebufferEXT(GL_FRAMEBUFFER_INCOMPLETE_REA D_BUFFER_EXT,my_fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_INCOMPLETE_DRA W_BUFFER_EXT,0);
glPixelTransferi(GL_MAP_COLOR,GL_TRUE);
glRasterPos2i(0,256);
glCopyPixels(0,0,256,256,GL_COLOR);

New identity loaded,the orthogonic projections are set, Viewport set, and GL_MODE_VIEW is definitely selected.

Does it look like I am at least close to getting it right?

TheSuese
08-06-2012, 10:06 PM
I re-read your comment with a little more scrutiny. I will let you know...

TheSuese
08-06-2012, 10:23 PM
I tried this:



void select_screen(int w,int h){
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, w, h, 0, 0, 1);
glViewport(0,0,w,h);
glMatrixMode (GL_MODELVIEW);
}


and this:



void select_screen(int w,int h){
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, w, h, 0, 0, 1);
glViewport(0,0,w,h);
}


Neither seems to do what I'm expecting.

Perhaps if someone could show me a working example that would help clear everything up. I can't find one on the net.

Thanks.