ScreenToWorldPoint возвращает координаты камеры при параметре Input.mousePosition

79
08 февраля 2022, 00:20

Изучаю Unity и не могу разобраться с ScreenToWorldPoint:

if(Input.GetMouseButtonDown(0))
{
    Debug.Log(GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition));
}

Вроде как написано всё правильно и координаты должно переводить, но куда не нажми - выдаёт координаты самой камеры. Помогите разобраться пожалуйста.

Answer 1

Идем в документацию:

Конкретно нас интересует приписка к первой перегрузке метода:

plus a z position for depth (for example, a camera clipping plane)

Камера - это, вообще говоря, довольно запутанная штука для неподготовленного человека:

Зачастую, экран - это и есть near clipping plane, в любом случае "экран" - это секущая фрустум камеры плоскость, куда мышь и кликает в данном случае.

Проблема в том, что точки на этой плоскости имеют 3 координаты:

  1. x - ось x
  2. y - ось y
  3. z - расстояние от камеры до плоскости

А мышь, чисто логически, имеет 2 координаты - x и y, про какой-то z она ничего не знает. Input.mousePosition вообще возвращает Vector3, с 0 вместо координаты z. И на самом деле это валидная ситуация: плоскость на расстоянии 0 от камеры - это плоскость с как бы "нулевой" площадью, т.е. любая точка на этой плоскости будет спроецирована в 3д пространство с такими координатами:

  • x => cameraX + 0, 0, т.к. у нас "пустая" плоскость, никуда там не деться
  • y => cameraY + 0, 0, т.к. смотри x
  • z => cameraZ + 0, 0, т.к. мы передали нулевое расстояние от плоскости до камеры

В итоге получаем преобразование:

input: Vector3(x, y, 0)
output: Vector3(cameraX, cameraY, cameraZ)

Как видно, координаты изначальной точки вообще никак не влияют на преобразованные координаты, а все дело кроется именно в z = 0 во входных данных.

Решение?

Использовать плоскость экрана, которая удалена от камеры на расстояние, прописанное в камере:

var screenToCameraDistance = camera.nearClipPlane;

TL;DR

var camera = GetComponent<Camera>();
var mousePos2D = Input.mousePosition;
var screenToCameraDistance = camera.nearClipPlane;
var mousePosNearClipPlane = new Vector3(mousePos2D.x, mousePos2D.y, screenToCameraDistance)
// искомая точка в мировых координатах
var worldPointPos = camera.ScreenToWorldPoint(mousePosNearClipPlane);
READ ALSO
Отключение IDisposable

Отключение IDisposable

Допустим, есть интерфейс IConnectionОн в своей иерархии имеет IDisposable

109
Scroll в RichTextBox и LinkLabel

Scroll в RichTextBox и LinkLabel

Вывожу в RichTextBox список LinkLabel-ов

86
Метод Рунге-Кутта 4-го порядка для CДУ C#

Метод Рунге-Кутта 4-го порядка для CДУ C#

Нужно решить систему из двух дифференциальных уравнений методом Рунге-Кутты 4-го порядка с коррекцией шага по правилу Рунге

131
Построение оптимального сплайна Безье (C#). Проблема с нахождением контрольных точек

Построение оптимального сплайна Безье (C#). Проблема с нахождением контрольных точек

Реализую свой метод интерполяции сплайна Безье дефекта 1Перед написанием кода вдохновлялся этим Построение оптимального сплайна Безье

65