Преобразование точки экрана в точку мира с помощью OpenTK
Я пытаюсь сделать 2D-холст, используя OpenTK. Для этого я поместил глаз камеры в точку (0,0,100), установил целевое положение камеры (0,0,0), а вектор вверх камеры - (0,1,0). Кроме того, я поместил некоторые оси, чтобы помочь визуализации. Результат можно увидеть на следующем изображении:
Я разрешаю только два движения:
- Увеличение / уменьшение масштаба: я просто изменяю компонент Z глаза камеры
- Горизонтальное смещение: я изменяю компонент X как глаза камеры, так и цели
На данный момент все работает отлично. Теперь, когда я нажимаю на экран, я получаю 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 лет.