Reputation: 9606
I need to detect mouse motion and draw a ball at the mouse's position. I need the ball to be in world coordinate. So I'm trying to use glUnProject
for this task and seems I'm not succeeding till now. This is my motionFunc
:
void motionFunc( int x, int y)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
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); //printf("winz: %f posz: %f\n",winZ,posZ);
Ball.x=posX;
Ball.y=posY;
Ball.z=posZ;
//printf("%f %f %f\n",Ball.x,Ball.y,posZ);
glutPostRedisplay();
}
now, I added a breakpoint on glutPostRedisplay. Turns out when I click-drag mouse, the Ball's coordinates(Ball.x,Ball.y,Ball.z) are something like:
(Ball).x -727.175354
(Ball).y 407.310242
(Ball).z -865.000610
why is the z coordinate so far? My camera is at z=+135. And other objects in my model are like, at z= -3 to +3. I need the ball's z coordinate to be in the same range.
now, what exactly is winZ
? Here, I checked it always turns out to be 1.00. I tried to hardcode winZ
and I found at winZ=0.85
, the ball seems like to be always under the mouse(I can drag the ball with my mouse and the ball is always under the pointer). But then the Ball's coordinates are like:
(Ball).x -4.67813921
(Ball).y 2.57806134
(Ball).z 128.370895
which is so close to the camera but x and y coordinates are not good for me. they always come out to be near the origin. which is not what I want. My other objects' x and y coordinates have a wider range.
Finally, my question is, what is the correct way to do glUnproject
or something of the same sort?
Upvotes: 0
Views: 4120
Reputation: 22033
A 2D mouse coordinate cannot unambiguously unmapped to a 3D world coordinate. The 2D coordinate corresponds with a line in 3D space. The winz influences which point on this line is returned. When you use 0.0 for winz you will get the point at the near clipping plane. When you use 1.0 you will get the point at the far clipping plane.
If you are using a depth buffer you could retrieve the value from the depth buffer using the glReadPixels function and use that as winz. Here a piece of code from a toy project of mine in Java
FloatBuffer depth = BufferUtils.createFloatBuffer(1);
glReadPixels(mouse_x, mouse_y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth);
depth.rewind();
FloatBuffer farPos = BufferUtils.createFloatBuffer(3);
GLU.gluUnProject(mouse_x, mouse_y, depth.get(),
mainContext.getModelviewMatrix(),
mainContext.getProjectionMatrix(), viewport, farPos);
Most is the same in C/C++ except for the weird NIO buffers.
Upvotes: 1