Jump to content
  • Advertisement
Sign in to follow this  
Java_newbie

OpenGL Help with 3D Mouse Coordinate Detection

This topic is 3606 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello all and thanks for looking at this thread. I have a game in which I want a paddle to move by having it follow the user's mouse. When I searched for OpenGL coordinate detection, I came across two methods of OpenGL-mouse interaction - glPickMatrix( ) and gluUnProject( ). I know that glPickMatrix( ) is used to detect hits on an object, but I just want the 3D coordinates of the mouse. Instead I decided that gluUnProject( ) would be more appropriate, and I used this code: public Point3[] transform(int realX, int y, GL gl, GLU glu) { int[] viewport = new int[4]; int x = realX; double[] modelviewMatrix = new double[16]; double[] projectionMatrix = new double[16]; // Returned coordinates: double[] worldCoords = new double[4]; Point3[] worldValues = new Point3[2]; gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0); gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, modelviewMatrix, 0); gl.glGetDoublev(GL.GL_PROJECTION_MATRIX, projectionMatrix, 0); // viewport[3] is the height of the window in pixels. int realY = viewport[3] - y - 1; // Cursor coordinates at (x, y) glu.gluUnProject((double)x, (double)realY, 0.0, modelviewMatrix, 0, projectionMatrix, 0, viewport, 0, worldCoords, 0); // World coordinates at z = 0.0 are (worldCoords[0], [1], and [2]) worldValues[0] = new Point3((float)worldCoords[0], (float)worldCoords[1], (float)worldCoords[2]); glu.gluUnProject((double)x, (double)realY, 1.0, modelviewMatrix, 0, projectionMatrix, 0, viewport, 0, worldCoords, 0); // World coordinates at z = 1.0 are (worldCoords[0], [1], and [2]) worldValues[1] = new Point3((float)worldCoords[0], (float)worldCoords[1], (float)worldCoords[2]); gl.glFlush( ); return worldValues; } However, the coordinates returned are always (0, 0, 0). Also, is this the right way to get the 3D coordinates of the mouse, or should I use some other method? Thanks very much for your help; it is greatly appreciated!

Share this post


Link to post
Share on other sites
Advertisement
The arguments RealX and y are the mouse coordinates, corret? Otherwise you need to get the mouse coordinates somewhere. Also make sure that all the unproject arguments are correct, and make sure that the viewport object is properly initialized, and that the projection matrix is set.

One method I used to use is to make a cursor object (like a sphere) inside the view, then attach its position to the actual cursor's coordinates, and constantly adjust the multiplication values until it looks right. This only works for fixed cameras.

You could also just track the changes to the mouse coordinates and update the paddle's position using those.

Share this post


Link to post
Share on other sites
Thanks for your quick reply, Super Llama. I checked the values for the arguments, and they seem to be correct. If it helps, I used it from this method (coords is an instance of the class containing the transform( ) method):

this.addMouseMotionListener(new MouseMotionAdapter( ) {

public void mouseMoved(MouseEvent e) {

if (coords != null) {
Point3[] pts = new Point3[2];
pts = coords.transform(e.getX( ), e.getY( ), gl, glu);
}

}

});

Share this post


Link to post
Share on other sites
I'm a DirectX person, so forgive me if I say something stupid :P

Point3[] pts = new Point3[2];
pts = coords.transform(e.getX( ), e.getY( ), gl, glu);

Does coords.transform return an array? What exactly is the array for? I'm assuming that Point3 means an XYZ value (3 values), so why do you need two of them? One for each paddle? This probably isn't the problem because if it were, it wouldn't even compile, but it could have something to do with the array. I had a problem once where my two arrays were overlapping, and it really messed everything up. Someone told me to use vectors, and that fixed everything. If all else fails, try implementing vectors into the program instead of arrays.

Also, you could add a messagebox or something to output the current mouse coordinates at the time that the event is recieved. If this is (0, 0), then there's a problem with the way you retrieved the mouse coords.


this.addMouseMotionListener(new MouseMotionAdapter( ) {

public void mouseMoved(MouseEvent e) {

if (coords != null) {
Point3[] pts = new Point3[2];
pts = coords.transform(e.getX( ), e.getY( ), gl, glu);
char[256] buffer; //declare buffer
sprintf(buffer,"%f, %f",e.getX( ), e.getY( )); //write values into buffer (the %f might be wrong, not sure what the XY values are declared as)
printf(buffer); //print buffer
}

}

});


Share this post


Link to post
Share on other sites
Thanks for responding! I got it to work now, but the mouse coordinates are very inaccurate because the only z-coordinate values returned are those from the near and far clipping planes (in my case, either from around 1.0 or -5000.0). As a result, the x and y coordinates also become inaccurate. Each Point3 holds a 3D coordinate of the mouse click from each clipping plane. The return value from transform( ) is an array of two Point3 objects; the first holds the data from the near clipping plane and the last from the far one. I checked the values, and I'm pretty sure that they're not overlapping. I read somewhere that it's possible to find a vector going from the camera angle to the mouse and find where that vector hits an object on the rendered scene, sort of like ray tracing. This seems like a very accurate and reliable method to determine the 3D location of the mouse, but how can a 3D vector be created if the mouse only has a single x and y position? Or am I still using gluUnProject( ) incorrectly?

Share this post


Link to post
Share on other sites
The key is the 3rd coordinate, the "window Z" coordinate. Project point:
m1 = gluUnproject(< mouseX, mouseY, z1 >), and
m2 = gluUnproject(< mouseX, mouseY, z2 >), where 0.0 <= z1 < z2 <= 1.0
then the mouse vector is:
mv = |m2 - m1|
This ray can then be traced and the first intersection is the closest surface in your scene that is under the mouse.

Share this post


Link to post
Share on other sites
The last item in the GLU FAQ gives a better explanation, but in essence, if you want the first intersection in 3d space, you need to feed gluUnProject a window-z coordinate as well. You can read back this value from the depth buffer by using glReadPixels(mouseX, mouseY, 1, 1, GL_DEPTH_COMPONENT).

Share this post


Link to post
Share on other sites
Also, there's a function in most 3D libraries for RayIntersect, where you can intersect a ray with a mesh and return the distance. If you set up a mesh from the xy of the mouse, then you could do a RayIntersect and get a Z distance.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!