gluUnproject gives non-logical values (C++) - c++

I'm currently working on a project, and I need to be able to move objects with my mouse, and to do some mouse picking. I generate a 1024*768 window, and my code with gluUnproject is :
glm::vec3 GetOGLPos(int x, int y)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ; // posX2, posY2, posZ2;
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
winX = (float)x;
winY = (float)viewport[3] - (float)y;
glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
std::cout << "PosX = " << posX << " - PosY = " << posY << " - Pos Z = " << posZ << std::endl;
return glm::vec3(posX, posY, posZ);
}
And I use it this way :
glm::ivec2 pos = _input.getMousePosition(); //0, 0 is high left corner
glm::vec3 posIn = GetOGLPos(pos.x, pos.y);
The position in pixels are good, but the position I get are, I think, false.
Here is some output I have if I click in the center of the screen (My object origin is in (0, 0, 0)) :
Xpixel = 512 Ypixel = 364 XOGL = 0 YOGL = -0.0111111 ZOGL = 1
And the output I have when i click somewhere else :
Xpixel = 237 Ypixel = 207 XOGL = -0.537109 YOGL = 0.425 ZOGL = 1
So I have two problems here :
The Z value doesn't change (so maybe it is a vector and not coordonates)
The object moves toward my mouse (since I translate my object to the new coordonates, so the new origin point should be XOGL, YOGL, ZOGL) but only on few pixels. So the values are either wrong or misused.
Can someone help me?

Related

How to produce correct coordinates of a point by using glReadPixels and gluUnproject?

I am using QGLWidget and QtOpenGL to display my point clouds and glReadPixels and gluUnProject to pick a point from a poiint cloud. The problem is that the glReadPixels does not seem to pick pixels of my points.
I've tried to use different point sizes as well as different block sizes in glReadPixels but the "ray" seems to go through the points. Im wondering if I need to calculate the closes point to the ray since its almost impossible to click right on the point.
The points are drawn with (just and example of a point in origon )
`
GLuint list = glGenLists(1);
glNewList(list, GL_COMPILE);
glPointSize(10.0f);
glBegin(GL_POINTS);
glColor3f(0.0f, 255.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glEnd();
glEndList();
updateScene();`
The point picking is done by the getObejctCoords function below.
`
void pclView::getObjectCoords(QMouseEvent *event)
GLdouble projection[16];
GLdouble modelView[16];
GLint viewPort[4];
GLdouble obj_coords0, obj_coords1, obj_coords2;
GLdouble pt_coords0, pt_coords1, pt_coords2;
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetIntegerv(GL_VIEWPORT, viewPort);
// Window parameters
winX = event->pos().x();
winY = viewPort[3] - event->pos().y();
// get Window Z
glReadPixels( event->pos().x(), int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
// Unproject 2D click to 3D location
gluUnProject( winX, winY, winZ, modelView, projection, viewPort, &obj_coords0, &obj_coords1, &obj_coords2);
std::cout << "x: " << obj_coords0;
std::cout << " y: " << obj_coords1;
std::cout << " z: " << obj_coords2 << std::endl;
`
At camera position (0,0,-50) rotation: (0, 0) (By clicking at the point at almost at origon (but on the point ) the function produces the following output
ยด x: 0 y: -0.578724 z: -950 `
And the actual result should (as I've understood it) should be something like
x: 0 y: -0.578724 z: -0

Obtaining model coordinates giving wrong values back in OpenGl

So i've got a little program that draws a few spheres, then i attempt to right click on them. Upon right clicking, it draws a line between the near and far planes, under the mouse when i click. However, its giving strange results, such as the line being out by quite a long way. The direction of the line is right however, just the line is maybe about 10 to the left along X, or 5 to right right along Y (Those are random examples).
Here's my code :
Positioning the camera
gluLookAt(mouse.getScrollY(), 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f);
glRotated(mouse.getAngleV(), 0.0f, -1.0f, 0.0f);
glRotated(mouse.getAngleH(), 0.0f, 0.0f, -1.0f);
mouse.getScrollY is simply a value based on how far the camera is scrolled back form the origin.
Obtaining the coordinates
void Mouse::GetGLPos(int x, int y)
{
//init vars:
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY;
GLdouble posX, posY, posZ;
GLdouble FposX, FposY, FposZ;
//get gl specs
glGetDoublev( GL_MODELVIEW_MATRIX, modelview ); //get Modelmatrix
glGetDoublev( GL_PROJECTION_MATRIX, projection ); //get projection matrix
glGetIntegerv( GL_VIEWPORT, viewport ); //get viewport values
//calculate the gl mouseposition
winX = (float)x;
winY = (float)viewport[3] - (float)y;
std::cout << "X "<< winX << " Y " << winY << endl;
gluUnProject( winX, winY, 0.0, modelview, projection, viewport, &posX, &posY, &posZ);
gluUnProject( winX, winY, 1.0, modelview, projection, viewport, &FposX, &FposY, &FposZ);
std::cout << "Near positions:" << posX << " | " << posY << " | " << posZ << endl;
std::cout << " Far positions:" << FposX << " | " << FposY << " | " << FposZ << endl << endl;
for (int i = 0; i <= 15; i++)
{
cout << modelview[i] << endl;
}
if (counter == 5)
{
counter = 0;
}
LinestoreNear[counter + 1] = Vec3(posX, posY, posZ);
LinestoreFar[counter + 1] = Vec3(FposX, FposY, FposZ);
counter ++;
mouseOgl[0] = posX;
mouseOgl[1] = posY;
mouseOgl[2] = posZ;
}
x and y that are passed to it are simply the mouse's x and y coordinates on the screen. ((328,657) for example)
And finally, just in case, here is the drawing the line
glDisable(GL_LIGHTING);
for (int i = 0; i <= 4 - 1 ; i++)
{
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINES);
glVertex3f(mouse.LinestoreNear[i].a, mouse.LinestoreNear[i].b, mouse.LinestoreNear[i].c);
glVertex3f(mouse.LinestoreFar[i].a, mouse.LinestoreFar[i].b, mouse.LinestoreFar[i].c);
glEnd();
}
glEnable(GL_LIGHTING);
heres a very brief overview of the process you need to use
to get world coordinates that are correct you need to have a 4x4 model matrix for each object in your scene. The model matrix contains all the transformations convert manipulate model coordinates to/from world coordinates.
ie every time you call glTranslate, you have to transform the model matrix as follows:
T = [ 1 0 0 x ]
[ 0 1 0 y ]
[ 0 0 1 z ]
[ 0 0 0 1 ]
M' = M * T
You can then use the transformed model matrix to obtain world space coordinates
Homogenise the coords first however (or check they are already) ie. just set w = 1, if they are not already homogenous coordinates.
If you do not convert the coordinates between object space and world space then you will get the behaviour you are experiencing, and it is easy to do it at the wrong stage as well, so plan out the required steps and you should be fine:)
Hope this helps.
Finally got time to verify your results. It works exactly as it should.
With LookAt you specify (GLU will calculate these matrices for you) camera position and rotation matrices (indirectly, via 'up' and 'view point' vectors, but still it will result into these transformations). Just right after you specify two additional rotation matrices - which means, you rotating a world around a zero point (which is already shifted by LookAt). For you, this kind of rotation will look like camera rotating around certain point at space, maintaining constant distance. Lines keeping their place, with some distortion introduced by perspective transformation (if you have it), and being clipped by far clipping plane (this will look like lines becoming shorter and longer during rotation).

gluUnproject returning 0, seems to be related to modelview matrix

I'm working on a 2D image viewer, I want to retrieve openGL mouse position on texture but I can't get it to work if glTranslatef() or glScalef() calls are made on the modelview matrix.
I'm using a QGLWidget , of the famous Qt library.
Here are the important calls :
Resize function :
void ViewerGL::resizeGL(int width, int height){
glViewport (0, 0, width, height);
Display function :
void ViewerGL::paintGL()
{ int w = width();
int h = height();
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
//transX,transY are for panning around the image in the viewer
float left = (0.f+transX) ;
float right = (w+transX) ;
float bottom = (h-transY);
float top = (0.f-transY) ;
glOrtho(left, right, top, bottom, -1, 1);
... later in paintGL:
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
//padx,pady are used to translate the image from the bottom left corner
// to the center of the viewer
float padx,pady;
padx= ((float)width() - _dw.w()*zoomFactor)/2.f; // _dw.w is the width of the texture
pady =((float)height() - _dw.h()*zoomFactor)/2.f ;// _dw.h is the height of the texture
glTranslatef( padx , pady, 0);
//zoomX,zoomY are the position at which the user required a zoom
glTranslatef(-zoomX,-zoomY, 0.f);
glScalef(zoomFactor, zoomFactor,0.f);
glTranslatef(zoomX ,zoomY, 0.f);
Now here is my function to retrieve the openGL coordinates :
QPoint ViewerGL::openGLpos(int x,int y){
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX=0, winY=0, winZ=0;
GLdouble posX=0, posY=0, posZ=0;
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
winX = (float)x;
winY = height()- y;
if(winY == 0) winY =1.f;
glReadPixels( x, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
return QPoint(posX,posY);
}
So far , here is what I noticed:
The code like this returns always (0,0) and GLU_FALSE is returned from gluUnproject. I read somewhere on a forum that it could be because of the modelview matrix, so I put the identity matrix instead, but,if I do it, I get exactly the coordinates of the mouse in the window...
Before , I dealt with the zoom using the orthographic projection, but I couldn't make it work perfectly, so to make it simpler I decided to retrieve openGL position, and use glTranslatef/glScalef instead .
If I remove all the translating / scaling stuff in the paintGL function, everything is working...but the zoom doesn't work :x)
I'm requesting your help to make this damned zoom to point working, using the gluUnProject solution;)
Aigth , nevermind, I found the solution : I was zeroing out the z in glScalef(x,y,z)
so it made the matrix non-invertible...

Another zoom to point issue

I have a 2D application which is an image viewer.
I have the ability to pan around the image in the window and I have a basic zoom.
Now I'd like to improve the zoom so it zoom to the point under the mouse.
So far I've read everything possible on google and i've come close to something working,
but still can't find something working, here is what I got:
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
// w and h are respectivly the width and height of the window
// newzoom_pos is the point in openGL coordinates where the user requested the zoom
// zoomFactor is between [0.1,10.0] , 0.1 -> 1.0 means downscale, 1.0 -> 10.0 means upscale
// transX and transY are used to pan around the image
float left = (0.f+transX -newzoom_pos.x())/zoomFactor +newzoom_pos.x();
float right = (w+transX -newzoom_pos.x())/zoomFactor +newzoom_pos.x();
float bottom = (h-transY-newzoom_pos.y())/zoomFactor +newzoom_pos.y();
float top = (0.f-transY -newzoom_pos.y())/zoomFactor +newzoom_pos.y();
glOrtho(left, right, top, bottom, -1, 1);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
It almost works, but it is not okay, it doesn't zoom exactly to the requested point and when the image is small and does not fit yet in the viewer entirely ( there's black around), well it is messy and does not work...
btw, here is the code when the user zoom-in, in the mouse wheel event handler:
zoomFactor+=0.1;
QPoint oglpos = openGLpos(new_zoomPoint.x(), new_zoomPoint.y());
this->newzoom_pos = oglpos;
the openGLpos function is the following:
QPoint ViewerGL::openGLpos(int x,int y){
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX=0, winY=0, winZ=0;
GLdouble posX=0, posY=0, posZ=0;
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
winX = (float)x;
winY = viewport[3]- y;
if(winY == 0) winY =1.f;
glReadPixels( x, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
GLint b=gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
if(b==GLU_FALSE) cout << "failed unprojection" << endl;
return QPoint(posX,posY);
}
Could anybody help me through this?

gluUnProject not working

I am trying to use gluUnProject to get my mouse coordinates into world coordinates, however it seems to not be working, or I am just misunderstanding the functionality of the glUnProject function, here is the code I am working with, my matrices all check out fine and as for the -300 on the mouse x coordinate, I am using a C++ Win32 Dialog and the ScreenToClient is giving me funky results.
int appWidth = CApplication::GetInstance()->GetWidth();
int appHeight = CApplication::GetInstance()->GetHeight();
float fAspect = (float)appWidth / (float)appHeight;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, fAspect, 0.1f, 100000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(m_vecCamera.x, -m_vecCamera.y, m_vecCamera.z);
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
glEnable(GL_DEPTH);
//Retrieve the Model/View, Projection, and Viewport Matrices
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
//Retrieve the Mouse X and the flipped Mouse Y
winX = (float)pInput->msg.param1-300.0f;
winY = (float)viewport[3]-(float)pInput->msg.param2;
glReadPixels( int(winX), int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
This is however giving me coordinates relative to the center of my screen, and I am assuming is relative to my camera, I also tried implementing my own function
Vector2f MouseUnProject(int x, int y)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
glEnable(GL_DEPTH);
//Retrieve the Model/View, Projection, and Viewport Matrices
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
//Retrieve the Mouse X and the flipped Mouse Y
winX = (float)x;
winY = (float)viewport[3]-y;
glReadPixels( int(winX), int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
double projectionX, projectionY;
double viewX, viewY;
double worldX, worldY;
//Convert from Screen Coords to Projection Coords
projectionX = (double)winX / ((double)viewport[2]/2.0) - 1.0;
projectionY = (double)winY / ((double)viewport[3]/2.0) + 1.0;
//Convert from projection Coords to View Coords
viewX = projectionX * modelview[14];
viewY = projectionY * modelview[14];
//Convert from View Coords to World Coords
worldX = viewX + modelview[12];
worldY = viewY - modelview[13];
return Vector2f(worldX, worldY);
}
It works to a certain mount, but when moving the camera, the numbers instantly go off a bit, the conversion from projection to view coords 'seems' to be ok, and the projection coords are definitely good.
I would really prefer to use glUnProject rather then my own function, but I can't get it to work for the life of me and all of the google searches I found don't seem to answer my question. What exactly does the GL documentation mean by 'object space' perhaps my understanding of that is wrong, and if so what do I additionally have to do to get my coordinates in the right space?
was posted a year ago,but anyways....so you are getting coordinates relative the the screen because you made a call to gluPerspective. this call internally calls glfrustum which will generate normalized coordinates in the range {-1, 1}. However if you called glfrustum directly with your near/far values you would have got the result from gluUnproject in that range.
To get back to your map editor coordinates, simply take the result from gluUnproject and manually range convert back to your editor coordinate system, ie{-1,1} => {0, max}
To get started you should test gluUnProject by inputting (0,0), (midX, midY), (maxX, maxY) and the result from gluUnProject should be (-1, -1, depth), (0, 0, depth) and (1, 1, depth). If you setup the projection matrix using glFrustum then the above result will be returned in the near/far range.