Search code examples
c++openglsdl-2opengl-4

glReadPixels changing the buffer data?


I'm having a strange issue where calling glReadPixels appears to be changing the data of the pixels being read. I'm reading from two RGBA textures on a framebuffer, which are used to encode the position and velocity of particles.

While debugging, I use glReadPixels to output the data of some of the pixels, and I noticed that my particle system behaved differently when I read them.

The offending code is this:

glBindFramebuffer( GL_READ_FRAMEBUFFER, fbo);
glReadBuffer( GL_COLOR_ATTACHMENT0 );
GLfloat *pixels = new GLfloat[ width * height * 4];
glReadPixels( 0, 0, width, height , GL_RGBA, GL_FLOAT, pixels);
std::cout << "Position:     " << pixels[0] << "  " << pixels[1] << "  " << pixels[2] << "  " << pixels[3] << std::endl;
glReadBuffer( GL_COLOR_ATTACHMENT1 );
glReadPixels( 0, 0, width, height, GL_RGBA, GL_FLOAT, pixels);
std::cout << "Velocity:     " << pixels[0] << "  " << pixels[1] << "  " << pixels[2] << "  " << pixels[3] << std::endl;
delete pixels;
glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );

I'm reading from the fbo framebuffer, which was previously bound and rendered to as a GL_DRAW_FRAMEBUFFER (though it was unbound before reaching this code).

Reading a larger or smaller number of pixels also has a larger or smaller impact on the results of the particle system.

What am I doing wrong here?


Solution

  • Turned out the issue was not directly with the posted code. That was just a symptom.

    It had to do with how I was calculating the elapsed time between frames. Since I calculated the elapsed time in the loop after reading the pixels, I would end up with a large initial time value when calculating the first frame because reading the pixels is expensive. Getting an initial large value has a large impact on my results. This also makes sense why reading a larger number of pixels threw things off more (because it takes longer).

    Calculating the elapsed time before this point in the code solves the issue. The problem could similarly be avoided by not reading pixel values on the first frame.