I am trying to make a 2D canvas using OpenTK. For that purpose I have place the camera eye in the point (0,0,100), I have set the camera target position to (0,0,0) and the camera Up vector to (0,1,0). Also, I have place some axis to help the visualization. The result can be seen in the next image:
I am only allowing two movements:
- Zoom in/out: I just change the Z component of the camera eye
- Horizontal displacement: I change the X component of both, the camera eye and the target
At this point everything works fine. Now, when I click on the screen I get a 2D point that I want to change to my world space coordinates. To do this, I have built a perspective matrix and a view matrix:
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / (float)6.0, 1, 0.1f, 1000f);
Matrix4 view = LookAt(Vector3 eye, Vector3 target, Vector3 up);
public static Matrix4 LookAt(Vector3 eye, Vector3 target, Vector3 up)
{
Vector3 f = (target - eye).Normalize();
Vector3 s = f.Cross(up).Normalize();
Vector3 u = s.Cross(f).Normalize();
Matrix4 rotation = new Matrix4(
s.X, s.Y, s.Z, 0.0,
u.X, u.Y, u.Z, 0.0,
-f.X, -f.Y, -f.Z, 0.0,
0.0, 0.0, 0.0, 1.0);
Matrix4 translation = new Matrix4(
1.0, 0.0, 0.0, -eye.X,
0.0, 1.0, 0.0, -eye.Y,
0.0, 0.0, 1.0, -eye.Z,
0.0, 0.0, 0.0, 1.0);
return rotation * translation;
}
Now that I have both matrices, I try to convert my screen coordinates into my world coordinates with the next code:
view.Transpose(); // Apparently openGl works with the transpose of the view
Vector3 point = new Vector3(e.Point.X, e.Point.Y, 0);
Vector4 worldPoint = UnProject(ref perspective, ref view, ref size, point);
private static Vector4 UnProject(ref Matrix4 projection, ref Matrix4 view, ref Size viewport, Vector3 mouse)
{
Vector4 vec;
vec.X = 2f * mouse.X / (float)viewport.Width - 1;
vec.Y = -(2f * mouse.Y / (float)viewport.Height - 1);
vec.Z = 2f * mouse.Z - 1f;
vec.W = 1f;
Matrix4 viewInv = Matrix4.Invert(view);
Matrix4 projInv = Matrix4.Invert(projection);
Vector4.Transform(ref vec, ref projInv, out vec);
Vector4.Transform(ref vec, ref viewInv, out vec);
vec.X /= vec.W;
vec.Y /= vec.W;
vec.Z /= vec.W;
return vec;
}
Doing some tests, I have realised that it works good for the central point of the screen (it is always the point [Eye.X, 0]), but it does not work for the other points.
Also, it looks like that the transformed point does not scale with the zoom. If I do not move the center of the screen, the edges of the screen always have the same value (if I zoom out a lot, the difference between the edges should be much bigger than if I zoom in).
EDIT
My question has been marked as possible duplicate but that post is addressing a different problem. Moreover, the link on that question is broken and is more than 5 years old.