Reading texture/framebuffer data with glReadPixels()

Started by
5 comments, last by V-man 16 years, 1 month ago
Hi, I'm rendering an image to the screen, and I then want to get the screen buffer and dump all the colour data per pixel to a set of three arrays (one per colour channel). I've sorta played with this stuff before, but not actually getting data from the buffer back to the application. Heres what I've got so far:


void GetTextureData()
{
//Setup FBO
		// First we bind the FBO so we can render to it
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
		
		// Save the view port and set it to the size of the texture
		glPushAttrib(GL_VIEWPORT_BIT);
		glViewport(0,0,width,height);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
		glLoadIdentity();									// Reset The View

		PreDisplay();			//Setup to draw in ortho
		glBindTexture(GL_TEXTURE_2D, imageTexture[0]);
 		glEnable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);
		glDisable(GL_DEPTH_TEST);	//Disable depth testing and masking
		glDepthMask(GL_FALSE);

		float dimensionsNeg = 0.0f;
		float dimensionsPos = 1.0f;

		PreDisplay();			//Setup to draw in ortho
			glColor3f(1.0f,1.0f,1.0f);
			glBegin(GL_QUADS);
				glTexCoord2f(0.0f, 0.0f); glVertex3f(dimensionsNeg, dimensionsNeg, 0.0f);
				glTexCoord2f(0.0f, 1.0f); glVertex3f(dimensionsNeg, dimensionsPos, 0.0f);
				glTexCoord2f(1.0f, 1.0f); glVertex3f(dimensionsPos, dimensionsPos, 0.0f);
				glTexCoord2f(1.0f, 0.0f); glVertex3f(dimensionsPos, dimensionsNeg, 0.0f);
			glEnd();
		ViewPerspective();

			for(int i = 0 ; i < N ; i++)
			{
				for(int j = 0 ; j < N ; j++)
				{
					glReadPixels(i,j,1,1,GL_RED, GL_FLOAT, &dens_prev_r[IX(i,j)]);
					glReadPixels(i,j,1,1,GL_GREEN, GL_FLOAT, &dens_prev_g[IX(i,j)]);
					glReadPixels(i,j,1,1,GL_BLUE, GL_FLOAT, &dens_prev_b[IX(i,j)]);
					dens_r[IX(i,j)] = dens_prev_r[IX(i,j)];
					dens_g[IX(i,j)] = dens_prev_g[IX(i,j)];
					dens_b[IX(i,j)] = dens_prev_b[IX(i,j)];

				}
			}

		// Restore old view port and set rendering back to default frame buffer
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
		glPopAttrib();
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);


}


The data pumped to the arrays is either 1.0f or 0.0f, with nothing in between.
Advertisement
I'm not the biggest expert, but that just looks horrible to have glreadpixels in a double-nested loop like that.
I always recommend that you read the FBO in the same format that it is in because this case MUST be correctly implemented in the driver.
It is possible that other cases are not well tested, not well debugged by driver team, or fall into the who-cares category.

Depending on your format :

glReadPixels(i,j,1,1,GL_BGRA, GL_FLOAT, pixels);
or
glReadPixels(i,j,1,1,GL_BGRA, GL_UNSIGNED_BYTE, pixels);
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
How do you store GL_BGRA ? With GL_FLOAT it made sense to store it in a single variable. If i store GL_BGRA, do I have to dissasemble it into different channels?
You read the different elements of the array.
GLfloat pixel[4];glReadPixels(i, j, 1, 1, GL_BGRA, GL_FLOAT, pixel);

pixel now contains the four channels of a pixel.
thanks, I tried that (I didn't realise it would be so intuitive but I'm still getting 1.0f for everything.

Could it be that I've setup the framebuffer object wrong? It's based mostly on a sample, and I think it might be setup to record depth and not colour, or something?

void SetupFBO(){	// Setup our FBO	glGenFramebuffersEXT(1, &fbo);	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);	// Create the render buffer for depth		glGenRenderbuffersEXT(1, &depthBuffer);	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);	// Now setup a texture to render to	glGenTextures(1, &img);	glBindTexture(GL_TEXTURE_2D, img);		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  width, height, 0, GL_RED, GL_FLOAT, NULL);		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//  The following 3 lines enable mipmap filtering and generate the mipmap data so rendering works//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//	glGenerateMipmapEXT(GL_TEXTURE_2D);	// And attach it to the FBO so we can render to it	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, img, 0);	// Attach the depth render buffer to the FBO as it's depth attachment	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBuffer);		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);	if(status != GL_FRAMEBUFFER_COMPLETE_EXT)		exit(1);		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);	// Unbind the FBO for now}
Try to render some of red color and see if it returns red
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

This topic is closed to new replies.

Advertisement