I’m relatively new to using OpenTK, and I suspect my issue might be a common one, but I haven’t found a satisfactory answer yet. I stumbled upon a similar question on this platform, but it remains unanswered. I’m unsure about the appropriate steps to follow to bring attention to that question, so I’ve decided to ask mine here.
My scenario involves drawing objects, essentially cubes, where all faces are situated with their tops at Z zero and extend below it in the negative Z direction. My goal is to determine the world coordinates (X, Y) from the 2D position of the mouse cursor. Below is the code snippet illustrating my scene setup, along with an “unproject” function I’ve assembled based on various examples I’ve come across.
private Vector3 Unproject(Vector3 ndcCoords)
{
Matrix4 invertedScaleMatrix = Matrix4.CreateScale(1 / zoom, 1 / zoom, 1);
Matrix4 invertedTranslateMatrix = Matrix4.CreateTranslation(-PanX, -PanY, 0);
Matrix4 invertedModelMatrix = invertedTranslateMatrix * invertedScaleMatrix;
// Invert the projection matrix
Matrix4 invertedProjectionMatrix = Matrix4.Invert(Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, glControl.Width / (float)glControl.Height, 1.0f, 1000.0f));
// Calculate the combined matrix (inverse of modelview-projection matrix)
Matrix4 invertedModelViewProjectionMatrix = invertedModelMatrix * invertedProjectionMatrix;
// Transform from normalized device coordinates to clip coordinates
Vector4 clipCoords = new Vector4(ndcCoords.X, ndcCoords.Y, -1.0f, 1.0f);
// Transform from clip coordinates to eye space
Vector4 eyeCoords = Vector4.Transform(clipCoords, invertedModelViewProjectionMatrix);
// Convert from homogeneous coordinates to cartesian coordinates
if (eyeCoords.W != 0.0f)
{
eyeCoords.X /= eyeCoords.W;
eyeCoords.Y /= eyeCoords.W;
eyeCoords.Z /= eyeCoords.W;
}
// Return the world coordinates
return new Vector3(eyeCoords.X, eyeCoords.Y, eyeCoords.Z);
}
Scene setup
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView((float)0.5, (float)1.5, 1, 1000); // Setup Perspective
Matrix4 lookat = Matrix4.LookAt(100, 100, 0, 0, 0, 0, 0, 1, 0); // Setup camera
GL.MatrixMode(MatrixMode.Projection); // Load Perspective
GL.LoadIdentity();
GL.LoadMatrix(ref perspective);
GL.MatrixMode(MatrixMode.Modelview); // Load Camera
GL.LoadIdentity();
GL.LoadMatrix(ref lookat);
GL.Viewport(0, 0, glControl.Width, glControl.Height); // Size of window
GL.Enable(EnableCap.DepthTest); // Enable correct Z Drawings
GL.DepthFunc(DepthFunction.Less); // Enable correct Z Drawings
// Rotating
GL.Rotate((double)Rotate1, 0, 0, 1);
GL.Rotate((double)Rotate2, 0, 1, 0);
GL.Translate(PanX, PanY, 0); // Apply camera translation
GL.Scale(zoom, zoom, zoom);