Skip to main content
gamedev.net
🔒 Locked

glReadPixels (problem solved)

Started by LarrxX 13 replies 12.3k views
Original Post
LarrxX
LarrxX
Are there any special OGL variables to set to be able to use glReadPixels? The only thing I can think about (for using it the way I am) is to enable depth testing, when I use the following code: Glfloat z = -10.0; glReadPixels( X, _viewport[3]-Y, 1, 1,GL_DEPTH_COMPONENT, GL_FLOAT, (GLvoid*)(&Z) ); I ALWAYS get either 1 or -10.0 in Z, whatever the X and Y window coordinates. In case there's no obvious thing that should be done before using glReadPixels(), here's exactly what I'm doing: -First I select an area of the viewport, you know like when u click the left mouse button and drag it to form a square and select everything inside. -I use this square to create a gluPickMatrix before using the gluProjection to set up the GL_PROJECTION matrix. -Then in GL_MODELVIEW I apply the reverse camera transformations. -I switch to feedback mode. -I render the scene into the feedback buffer. -I parse the buffer and get the X and Y coordinates of the vertices which I pass to glReadPixels to get the Z in the depth buffer. My question is, because of the use of gluPickMatrix, do I have to manually change the Raster Position to match the viewport area selected? I tried glRasterPos(0,0) and glRasterPos( X-(width/2), Y-(height/2) ), and both gave the same result. Perhaps there's something I'm missing entirely... Thanx for the help [edited by - LarrxX on September 1, 2003 5:37:03 AM] [edited by - LarrxX on September 2, 2003 8:20:50 AM]
Mihail121
Mihail121
Seems perflectly correct to me.I only need to know some stuff.Do u render any objects at all?What is your depth clearing value.Post some rendering code,post some feedback buffer code.That''s enough.

"Tonight we strike,there is thunder in the sky,together we''ll fight,some of us will die,but they''ll always remember that we''ve made a stand and many will die by hand!" - ManOwaR

GDSAUBY GameDev Society For UnBanning YodaTheCoda
If you want to see yoda unbanned then put this in your sig
ShlomiSteinberg
ShlomiSteinberg
Do NOT use glReadPixels!! It is very very slow. As you project will get more complicated glReadPixels will become a bigger bottleneck.

"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Member of the Shove Pouya Off A Cliff club, SPOAC. (If you wish to join, add this line to your signature.)Member of "Un-Ban nes8bit" association, UNA (to join put this in your sig)
Mihail121
Mihail121
quote:
Original post by ShlomiSteinberg
Do NOT use glReadPixels!! It is very very slow. As you project will get more complicated glReadPixels will become a bigger bottleneck.

"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"


Ehm...you probably mean that glDrawPixels is very very slow....cause glReadPixels is rather faster since it''s working with processed buffers like for example the depth component.Since OpenGL keeps an array with size vp_width*vp_height in the memory and uses it for depth buffering it ain''t slow at all just to copy that buffer into users buffer.

"Tonight we strike,there is thunder in the sky,together we''ll fight,some of us will die,but they''ll always remember that we''ve made a stand and many will die by hand!" - ManOwaR

GDSAUBY GameDev Society For UnBanning YodaTheCoda
If you want to see yoda unbanned then put this in your sig
LarrxX
LarrxX
quote:
Original post by Raduprv
Are you doing it on Windows or Linux?
I am asking because Nvidia drivers on Linux have a bug with it..



I''m using RedHat Linux 8.0 and I''m also using openGL through FLTK if that''s relevant.

As for posting code and such, I''m on a weekend away from it all to clear my head, will do a fresh post on monday.

Thanx for your replies all, c u on monday
Anthony Serrano
Anthony Serrano
The cases don''t match on the z''s. The one in the variable declaration is lowercase, the one in the glReadPixels parameter list is capitalized.

Also, remember that the contents of the framebuffer are not changed when in feedback mode.

Why not try using GL_3D for the feedback buffer type, instead of GL_2D? That way, you''ll also have the Z coordinate in the feedback buffer, and you won''t need to bother reading it out from the framebuffer.
LarrxX
LarrxX
quote:
Original post by Anthony Serrano
The cases don''t match on the z''s.[...]



Very perceptive about the case but it''s not that

Now when you say:
quote:
Original post by Anthony Serrano
Also, remember that the contents of the framebuffer are not changed when in feedback mode.


What I do is (and what''s below is not compilable, I''m just writing from memory):
glClear( GL_COLOR_BUFFER | GL_DEPTH_BUFFER );
glRenderMode( GL_FEEDBACK );
glFeedbackBuffer( ...,GL_3D,... );
do Projection transformations;
for each object in scene:
do modelview transformations (between pushMatrix and popMatrix)
render object
end for
int size = glRenderMode( GL_RENDER)

Doesn''t this put anything in the frame buffer? Is this why I get all 1 or -10 values?

quote:
Original post by Anthony Serrano
Why not try using GL_3D for the feedback buffer type, instead of GL_2D? That way, you''ll also have the Z coordinate in the feedback buffer, and you won''t need to bother reading it out from the framebuffer.


I do use GL_3D but I read somewhere in the openGL FAQ that the Z value returned in this mode is not valid and that the correct one should be read using glReadPixels(). Like I said, I use gluUnproject to get the feedback buffer coordinates in world coordinates, and when I use the Z value returned by GL_3D mode, I get really weird positions. I''m starting to think there''s a problem with my matrices and that there''s nothing wrong with my Zs. I''ll post the code on monday, hopefully someone will see what I''m not.
jitspoe
jitspoe
glReadPixels also does not work on Radeon''s (the 9700 at least) if you have FSAA on. Just thought I''d throw that out (hopefully the next set of drivers will fix that!)

Raduprv
Raduprv
quote:
Original post by jitspoe
glReadPixels also does not work on Radeon''s (the 9700 at least) if you have FSAA on. Just thought I''d throw that out (hopefully the next set of drivers will fix that!)




This sucks!
My game RELIES on that, without it you can''t do a lot of stuff (mouse interactions with the world).

Height Map Editor | Eternal Lands | Fast User Directory
LarrxX
LarrxX
Here's the code! I tried to put in everything relevant but it looks really ugly. I would really really appreciate it if someone took the time to read the code thouroughly because I know it's kind of complicated. I just want to explain a few things. There are 2 main classes, GLView which handles all the viewing stuff and contains a list of GLObject classes. I first use GL_SELECT to pick on of the objects (which is refered to as _activeGLObject in the code ) and I only render this object in GL_FEEDBACK. What I'm trying to do is to select a part of this object by dragging the mouse in a rectangular area over the object. So I get some stuff in the feedbak buffer that I'm trying to project on the object itself. Thank you all for your help. One final note, all variables beginning with '_' are class members, their names should be explicit enough.

void GLView::setupWorld( bool pickMatrix,
const GLdouble x, const GLdouble y,
const GLdouble width, const GLdouble height )
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
if( pickMatrix )
{
gluPickMatrix( x, _viewport[3] - y, width, height, _viewport );
}
gluPerspective( 60.0, w()/h(), _zNear, _zFar );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

glTranslatef( _xTrans, _yTrans, _zTrans - 4.0);

glRotatef( _xAngle, 1.0, 0.0, 0.0 );
glRotatef( _yAngle, 0.0, 1.0, 0.0 );
}

void GLView:: Project( GLdouble &x, GLdouble &y, GLdouble &z )
{
GLdouble mvmatrix[16];
GLdouble projmatrix[16];

glGetDoublev( GL_MODELVIEW_MATRIX, mvmatrix );
glGetDoublev( GL_PROJECTION_MATRIX, projmatrix );

//_viewport is a class member
gluUnProject( x, _viewport[3]-y, z, mvmatrix, projmatrix, _viewport, &x, &y, &z );
}

#define FEEDBACK_BUFSIZE 1024
void GLView::selectVertices( const GLdouble &x, const GLdouble &y, const GLdouble &width, const GLdouble &height )
{
GLfloat feedBuffer[FEEDBACK_BUFSIZE];

glFeedbackBuffer( FEEDBACK_BUFSIZE, GL_3D, feedBuffer );

GLint size;
glRenderMode( GL_FEEDBACK );

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

if( _activeGLObject != NULL )
{
setupWorld( true, x, y, width, height );
_activeGLObject->draw();
}

size = glRenderMode( GL_RENDER );

GLint i = 0;

while( i < size )
{
if( (GLenum)feedBuffer == GL_PASS_THROUGH_TOKEN )
{
i+=2;
cout << "Discarding GL_PASS_THROUGH_TOKEN " << feedBuffer[i-1] << endl;
}
else
{
setupWorld( true, x, y, width, height );

GLint type = (GLint)feedBuffer[ i++ ];
GLdouble *projectedBuffer;

switch( type )
{
case GL_POINT_TOKEN:
case GL_BITMAP_TOKEN:
case GL_DRAW_PIXEL_TOKEN:
case GL_COPY_PIXEL_TOKEN:

i+=3;
break;

case GL_LINE_RESET_TOKEN:
case GL_LINE_TOKEN:

i+=6;
break;

case GL_POLYGON_TOKEN:
{
GLint size = (GLint)feedBuffer[i++];

projectedBuffer = new GLdouble[3*size];

for( int j = 0; j < 3*size; j++ )
{
projectedBuffer[j] = (GLdouble)feedBuffer[i+j];
}

for( int j=0; j {
int index = 3*j;
//In MODELVIEW mode after the call to setupWorld()
glPushMatrix();
{
GLfloat Z = projectedBuffer[index+2];
glReadPixels( (GLint)projectedBuffer[index], _viewport[3]-(GLint)projectedBuffer[index+1], 1, 1,
GL_DEPTH_COMPONENT, GL_FLOAT, (GLvoid*)(&Z) );
projectedBuffer[index+2]=Z;
_activeGLObject->makeTransformations();
project( projectedBuffer[index], projectedBuffer[index+1], projectedBuffer[index+2] );
}
glPopMatrix();
}

//This method adds the vertices to a list in the selected object, won't post the code
_activeGLObject->selectVertices( type, projectedBuffer, size );

delete[] projectedBuffer;
i+=(3*size);
}
break;

default:
cerr << "Unknown token received" << endl;
}
}
}
}

void GLObject::makeTransformations( void )
{
glTranslatef( _x, _y, _z );

if( _rotX != 0.0 ) { glRotatef( _rotX, 1.0, 0.0, 0.0 ); }
if( _rotY != 0.0 ) { glRotatef( _rotY, 0.0, 1.0, 0.0 ); }
if( _rotZ != 0.0 ) { glRotatef( _rotZ, 0.0, 0.0, 1.0 ); }

if( _scaleX != 1.0 || _scaleY != 1.0 || _scaleZ != 1.0 ) { glScalef( _scaleX, _scaleY, _scaleZ ); }
}

void GLObject::draw( bool withSelection )
{
glMatrixMode( GL_MODELVIEW );

glPushMatrix();
{
glColor4f( _material[0], _material[1], _material[2], _material[3] );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, _material );

makeTransformations();

glutSolidCube( 1.0 );

drawSelectedVertices();//Just contains a glBegin(GL_POLYGON) with the vertices then glEnd();
}
glPopMatrix();
}


[edited by - LarrxX on September 1, 2003 4:16:46 AM]
Anthony Serrano
Anthony Serrano
quote:
Original post by LarrxX
What I do is (and what''s below is not compilable, I''m just writing from memory):
glClear( GL_COLOR_BUFFER | GL_DEPTH_BUFFER );
glRenderMode( GL_FEEDBACK );
glFeedbackBuffer( ...,GL_3D,... );
do Projection transformations;
for each object in scene:
do modelview transformations (between pushMatrix and popMatrix)
render object
end for
int size = glRenderMode( GL_RENDER)

Doesn''t this put anything in the frame buffer? Is this why I get all 1 or -10 values?



Yeah, the frame buffers are still empty, because no actual rendering takes place in feedback mode. You need to re-render the objects after glRenderMode(GL_RENDER).

LarrxX
LarrxX
First of all thanks to AnthonySerrano; glReadPixels() was indeed returning garbage because the framebuffer was empty. But it turns out that this wasn't my problem! But I managed to solve it, finally, and for those of you interested, read on.

The Z values returned by the GL_3D feedback mode are correct, so out goes the call to glReadPixels(). The problem came from the way openGL converted the window coordinates corresponding to the selection square. (I hope the ASCII art turns out alright).

....----------------------(W,H)
....|........-----(R,T)...|
....|........|....|.......|
....|........|....|.......|
....|....(L,B)-----.......|
....|.....................|
....|.....................|
(0,0)----------------------

openGL assumes that, in window coordinates, the full viewport has the Bottom Left corner at (0,0) and the Top Right corner at (Width, Height). The selection square has its corners at (L,B) and (R,T). So when in feedback mode, only the part inside the selection square is rendered to the full viewport (it's like calling glFrustum( L, R, B, T, near, far ); ). So when I needed to gluUnproject them, openGL had to caculate the window coordinates correspondig to the full scene before doing so. Suppose (Xo, Yo) a point in the feedback buffer, to get it's actual coordinates in the full scene the following calculations are done:

X = L + Xo(L-R)/W and Y = B + Yo(T-B)/H

It may look complicated, but it's not, especially to openGL veterans who should be used to much more difficult calculations. Now the problem is that the (0,0) corner is at the TOP LET in window managers usually, that's why, if you look at the code I already posted, I pass viewport[3]-y instead of just y to gluUnproject (viewport[3] being H, of course). So when I used glPickMatrix and then gluUnproject, the (Xo,Yo)->(X,Y) calculations were done as said above. But given the difference in Y, the correct formula is:

Y = T + Yo(B-T)/H

And so, by doing these calculations by hand and passing the modelview matrix to gluUnproject without the pick matrix, it all worked out.

Thanx for all your help guys, and I'm really sorry if this post is too wordy.






[edited by - LarrxX on September 2, 2003 8:19:57 AM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.