我正在尝试使用OpenTK制作2D画布。为此,我将相机眼睛放在点(0,0,100),我已将相机目标位置设置为(0,0,0),将相机向上矢量设置为(0,1,0)。此外,我有一些轴来帮助可视化。结果可以在下一张图片中看到:
我只允许两个动作:
此时一切正常。现在,当我点击屏幕时,我得到一个2D点,我想要更改为我的世界空间坐标。为此,我构建了一个透视矩阵和一个视图矩阵:
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;
}
现在我有两个矩阵,我尝试使用下一个代码将我的屏幕坐标转换为我的世界坐标:
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;
}
进行一些测试,我已经意识到它对屏幕的中心点有效(它总是点[Eye.X,0]),但它不适用于其他点。
此外,看起来变换后的点不会随缩放而缩放。如果我不移动屏幕的中心,屏幕的边缘总是具有相同的值(如果我缩小很多,边缘之间的差异应该比放大时大得多)。
修改
我的问题已被标记为可能重复,但该帖子正在解决另一个问题。此外,该问题的链接已被打破,已超过5年。