[OpenGL] 3D coordinates from 2D mouse click ( Convert Screen Coordinate to World Coordinate )

Skills/Programming 2015. 6. 22. 17:59





[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



설정

트랙백

댓글