Не понимаю TransformDirection в Unity

Допустим у нас есть куб в нулевых координатах сцены. Я изменяю его позицию, чтобы он сдвинулся вперед на 10 единиц:

transform.position = new Vector3(x, y, 10);

Когда я поверну куб на 45 градусов и снова сдвину его на 10 единиц по оси z, он точно так же сдвинется относительно координат сцены, то есть глобальных координат, он не сдвинется в направлении своей z. Однако же, использование TransformDirection означает преобразование значений вектора из локальных в глобальные:

Vector3 direction = new Vector3(x, y, z);
Vector3 worldDirection = transform.TransformDirection(direction);
transform.position += worldDirection;

И теперь, если я поверну куб на 45 градусов, то сдвинется он уже относительно своей оси z, так в чем же логика? Получается ведь наоборот, если я не использую TransfromDirection, то объект сам по-себе по дефолту движется по глобальной оси z, а использование TransfromDirection наоборот заставляет объект двигаться по своим собственным координатам. Прошу развеять мой конфуз, потому что в интернете не нагуглил вменяемого объяснения этого метода.


Ответы (1 шт):

Автор решения: Yaroslav

Изменение координаты, это НЕ ДВИЖЕНИЕ, а телепортация! При перемещении таким образом, не задействована физика и объект может проходить сквозь стены, хотя тело стены будет при симуляции пытаться выталкивать из себя тело передвигаемого объекта, но пройдёт ли зависимости от скорости, толщины тела стены и частоты кадров, что является не стабильным и не надёжным. При загрузке баннера, происходит лаг и персонаж вылетает за пределы карты, а пользователь удаляет игру.

На тему логики, почему прибавив к позиции 0, 0, 1 вектор 0, 0, 1, должно получиться не 0, 0, 2 ?? Какая разница, как там этот объект повернут и какой у него масштаб? position не зависят от rotation, а rotation не зависят от scale, изменяя их, другие значения не страдают.

Допустим у тебя есть корпус автомобиля и к нему прикреплено колесо, оно имеет некоторую координату 2, 1, 0 (переднее-правое) и было бы как то странно, если бы это колесо меняло свое местоположение при повороте. Ты почему то ожидаешь, что координаты изменятся относительно поворота колеса, причём не вокруг корпуса, а вокруг центра сцены ?.


Transform это параметры осей, сдвиг начала координат localPosition, поворот осей localRotation и масштаб localScale, в инспекторе мы видим именно их. Оси сцены являются корневыми родительскими для всех осей и называются глобальными. Значения осей объекта пересчитанные по иерархии, в глобальных осях это position, rotation и lossyScale.


У трансформа есть две группы методов, для конвертации координат между двумя системами осей, вектора и позиции.

Методы для получения локального вектора в значениях глобальных осей и на оборот, с учётом или без учёта масштаба (Transform.TransformVector и Transform.TransformDirection).

Написав один из этих вариантов:

transform.position += transform.TransformDirection(Vector3.forward) * distance;
transform.position += transform.forward * distance;
transform.Translate(transform.forward * distance, Space.World);
transform.Translate(Vector3.forward * distance);

Vector3.forward == new Vector3(0, 0, 1), у векторов есть статические свойства содержащие базовые направления и нулевое значение для удобства, а у transform свойства с методом TransformDirection для положительных направлений, поскольку часто используются.

В итоге это один и тот-же код с одним и тем-же результатом, перемещением объекта по направлению его локальной оси z.

Полёт от первого лица, относительно осей камеры, как это происходит в редакторе, выглядит так:

private void Update ()
{
    Vector3 input = GetInputAxis();
    float deltaSpeed = speed * Time.deltaTime;

    Vector3 vx = transform.right * input.x;
    Vector3 vy = transform.up * input.y;
    Vector3 vz = transform.forward * input.z;
    transform.position += (vx + vy + vz) * deltaSpeed;
    // или 
    transform.Translate(input * deltaSpeed);

    // так же, кроме своих, локальных Space.Self или мировых Space.World осей, 
    // можно указывать конкретно, относительно пространства какого объекта
    transform.Translate(input * deltaSpeed, Camera.main.transform);
}

private Vector3 GetInputAxis ()
{
    float x = Input.GetAxis("Horizontal");
    float z = Input.GetAxis("Vertical");
    float y = 0;
    if (Input.GetKeyDown("e")
        y++;
    if (Input.GetKeyDown("q")
        y--;
    return new Vector3(x, y, z);
}

Метод для получения локальнонй позиции в значениях глобальных осей, когда учитывается всё, и позиция и поворот и масштаб (Transform.TransformPoint).

→ Ссылка