[1]
GLpoint GetOGLMousePos(GLint x, GLint y)
{
GLfloat winX = 0.0, winY = 0.0, winZ = 0.0; // never ever make a mistake between float and double.
I wasted my 4 days to solve this and the problem was, I was using GLdouble here instead of GLfloat.
Try GLdouble here you will see a hell difference in output values.
GLdouble posX = 0.0, posY = 0.0, posZ = 0.0;
winX = (float)x;
winY = (float)OGLMviewport[3] - (float)y; // invert winY so that down lowers value
glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
gluUnProject( winX, winY, winZ, OGLMmodelview, OGLMprojection, OGLMviewport, &posX, &posY, &posZ);
return GLpoint(posX, posY, -posZ); // invert z value
}
[2]
private void glControl1_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (!loadedTK) return; // Play nice
int[] viewport = new int[4];
double[] modelViewMatrix = new double[16];
double[] projectionMatrix = new double[16];
if (checkBoxSelectPoints.Checked == true)
{
int mouseX = e.X;
int mouseY = e.Y;
//Get Matrix
OpenTK.Graphics.OpenGL.GL.GetInteger(OpenTK.Graphics.OpenGL.GetPName.Viewport, viewport);
OpenTK.Graphics.OpenGL.GL.GetDouble(OpenTK.Graphics.OpenGL.GetPName.ModelviewMatrix, modelViewMatrix);
OpenTK.Graphics.OpenGL.GL.GetDouble(OpenTK.Graphics.OpenGL.GetPName.ProjectionMatrix, projectionMatrix);
//Calculate NearPlane point and FarPlane point. One will get the two end points of a straight line
//that "almost" intersects the plotted point you "clicked".
Vector3 win = new Vector3(mouseX, viewport[3] - mouseY, 0);
Vector3 worldPositionNear;
Glu.UnProject(win, modelViewMatrix, projectionMatrix, viewport, out worldPositionNear);
win.Z = 1.0f;
Vector3 worldPositionFar;
Glu.UnProject(win, modelViewMatrix, projectionMatrix, viewport, out worldPositionFar);
//Calculate the lenght of the straigh line (the distance between both points).
double distanceNF = Math.Sqrt(Math.Pow(worldPositionNear.X - worldPositionFar.X, 2) +
Math.Pow(worldPositionNear.Y - worldPositionFar.Y, 2)+
Math.Pow(worldPositionNear.Z - worldPositionFar.Z, 2));
double minDist = distanceNF;
//Calculate which of the plotted points is closest to the line. In other words,
// look for the point you tried to select. Calculate the distance between the 2 endpoints that passes through
// each plotted point. The one that is most similar with the straight line will be the selected point.
int selectedPoint = 0;
for (int i = 0; i < PointsInfo.Count; i++)
{
double d1 = Math.Sqrt(Math.Pow(worldPositionNear.X - PointsInfo[i].Position.X, 2) +
Math.Pow(worldPositionNear.Y - PointsInfo[i].Position.Y, 2) +
Math.Pow(worldPositionNear.Z - PointsInfo[i].Position.Z, 2));
double d2 = Math.Sqrt(Math.Pow(PointsInfo[i].Position.X - worldPositionFar.X, 2) +
Math.Pow(PointsInfo[i].Position.Y - worldPositionFar.Y, 2) +
Math.Pow(PointsInfo[i].Position.Z - worldPositionFar.Z, 2));
if (((d1 + d2) - distanceNF) <= minDist)
{
minDist = (d1 + d2) - distanceNF;
selectedPoint = i;
}
}
//Just select/unselect points if the "click" was really close to a point. Not just by clicking anywhere in the screen
if (minDist < 0.000065)
{
if (selectedPoints.Contains(selectedPoint))
selectedPoints.Remove(selectedPoint);
else
selectedPoints.Add(selectedPoint);
glControl1.Invalidate(); //paint again
}
}
[3]
private Vector3d GetOGLPos(int x, int y)
{
int[] viewport = new int[4];
double[] matrixprojection = new double[16];
double[] matrixmodeview = new double[16];
double WinX, WinY;
float[] WinZ = new float[1];
double PosX, PosY, PosZ;
IntPtr PixelPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(float));
GL.glGetDoublev(GL.GL_PROJECTION_MATRIX, matrixprojection);
GL.glGetDoublev(GL.GL_MODELVIEW_MATRIX, matrixmodeview);
GL.glGetIntegerv(GL.GL_VIEWPORT, viewport);
GL.glEnable(GL.GL_DEPTH_TEST);
GL.glDepthMask(1);
GL.glDepthRange(0, 1);
System.Runtime.InteropServices.Marshal.Copy(WinZ, 0, PixelPtr, 1);
WinX = (double)x;
WinY = (double)viewport[3] - (double)y;
GL.glReadPixels(x, (int)WinY, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT, PixelPtr);
System.Runtime.InteropServices.Marshal.Copy(PixelPtr, WinZ, 0, 1);
System.Runtime.InteropServices.Marshal.FreeHGlobal(PixelPtr);
GL.gluUnProject(WinX, WinY,(double)WinZ[0], matrixmodeview, matrixprojection, viewport,out PosX,out PosY,out PosZ);
//PosZ = (double)WinZ[0];
Vector3d result = new Vector3d(PosX, PosY, PosZ);
return result;
}
* Ref
[1] http://www.gamedev.net/topic/632454-incorrect-3d-coordinates-from-2d-mouse-click/
[2] http://www.opentk.com/node/1892
[3] http://www.opentk.com/node/480