Unity 6.3
0 онлайн 17 гостей 3 в системе
Вход

Перемещение объектов с векторами

Векторы — это фундаментальное математическое понятие, которое позволяет описать направление и величину. В играх и приложениях векторы часто используются для описания фундаментальных свойств, таких как положение персонажа, скорость движения или расстояние между двумя объектами.

Векторная арифметика является фундаментальной для многих аспектов компьютерного программирования, таких как графика, физика и анимация, и полезно понимать ее глубоко, чтобы получить максимальную отдачу от Unity.

Векторы могут быть выражены в нескольких измерениях, и Unity предоставляет классы Vector2, Vector3 и Vector4 для работы с 2D, 3D и 4D векторами. Эти три типа классов Векторов имеют много общих функций, таких как величина, поэтому большая часть информации на этой странице относится ко всем трем типам Векторов, если не указано иное.

Эта страница содержит обзор классов Вектор и их общего использования при создании скриптов с ними. Для исчерпывающей справки по каждому члену классов векторов, обратитесь к страницам справки по скриптам для Vector2, Vector3 и Vector4.

Понимание векторной арифметики

Сложение

Когда два вектора сложены вместе, результат эквивалентен принятию первоначальных векторов в качестве “шагов”, один за другим. Обратите внимание, что порядок двух параметров не имеет значения, так как результат одинаков в обоих случаях.

Вектор a — это вектор 2D с x-компонентой 3 и y-компонентой 5. Вектор b — это вектор 2D с x-компонентой 2 и y-компонентой -1. Сложение a и b даёт вектор c, вектор 2D с x-компонентой 5 и y-компонентой 4. Отношение трех векторов к точке начала образует скалярный треугольник.
Вектор a — это вектор 2D с x-компонентой 3 и y-компонентой 5. Вектор b — это вектор 2D с x-компонентой 2 и y-компонентой -1. Сложение a и b даёт вектор c, вектор 2D с x-компонентой 5 и y-компонентой 4. Отношение трех векторов к точке начала образует скалярный треугольник.

Если первый вектор рассматривается как точка в пространстве, то второй вектор можно интерпретировать как смещение или «прыжок» от этой позиции. Например, чтобы найти точку на 5 единиц выше места на земле, можно использовать следующий расчет:

 var pointInAir = pointOnGround + new Vector2(0, 5);

Если векторы представляют силы, то более интуитивно думать о них с точки зрения их направления и величины (величина указывает на размер силы). Добавление двух векторов силы приводит к новому вектору, эквивалентному комбинации сил. Эта концепция часто полезна при применении сил с несколькими отдельными компонентами, действующими одновременно (например, ракета, движущаяся вперед, может также подвергаться воздействию бокового ветра).

Примеры здесь используют векторы 2D, но то же самое понятие применяется к 3D и 4D векторам.

Вычитание

Векторное вычитание чаще всего используется для получения направления и расстояния от одного объекта к другому. Обратите внимание, что порядок двух параметров не имеет значения для при вычитании:

Вектор 2D a вычитается из вектора 2D b, что дает вектор 2D с x-компонентом 5 и y-компонентом 4. Это показано в виде одной линии со стрелкой от точки a до точки b.
Вектор 2D a вычитается из вектора 2D b, что дает вектор 2D с x-компонентом 5 и y-компонентом 4. Это показано в виде одной линии со стрелкой от точки a до точки b.
// The vector d has the same magnitude as c but points in the opposite direction.
var c = b - a;
var d = a - b;

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

// These both give the same result.
var c = a - b;
var c = a + -b;

Отрицательное значение вектора имеет ту же величину, что и первоначальное, и указывает на ту же линию, но в точно противоположном направлении.

Направление и расстояние от одного объекта к другому

Если одну точку в пространстве вычесть из другой, то получится вектор, который «указывает» от одного объекта к другому:

// Gets a vector that points from the player's position to the target's.
var heading = target.position - player.position;

Так же, как и указывая в направлении объекта цели, величина этого вектора равна расстоянию между двумя позициями. Вам может понадобиться “нормализованный” вектор, дающий направление к цели, но с фиксированным расстоянием (скажем, для направления снаряда). Вы можете нормализовать вектор, разделив его на собственную величину:

var distance = heading.magnitude;
var direction = heading / distance; // This is now the normalized direction.

Этот подход предпочтительнее, чем использование величины и нормализованных свойств отдельно, поскольку оба они довольно CPU-голодные (оба они включают вычисление квадратного корня).

Если вам нужно использовать расстояние только для сравнения (например, для проверки близости), то вы можете полностью избежать вычисления величины. Свойство sqrMagnitude дает квадрат значения величины, и вычисляется как величина, но без затратной на время операции квадратного корня. Вместо сравнения величины с известным расстоянием, вы можете сравнить квадрат величины с квадратом расстояния:

if (heading.sqrMagnitude < maxRange * maxRange) {
    // Target is within range.
}

Это гораздо более эффективно, чем использование истинной величины в сопоставлении.

Иногда, когда работаете в 3D, вам может понадобиться "надземный курс" к цели. Например, представьте игрока, стоящего на земле, которому нужно приблизиться к цели, плавающей в воздухе. Если вы вычтете позицию игрока из позиции цели, то полученный вектор будет указывать вверх к цели. Это не подходит для ориентации преобразования игрока, так как они также будут указывать вверх; то, что действительно необходимо, это вектор от позиции игрока к позиции на земле прямо под целью. Вы можете получить это, взяв результат вычитания и установив координату Y на нуль:

var heading = target.position - player.position;
heading.y = 0;  // This is the overground heading.

Скалярное умножение и деление

При обсуждении векторов обычно называют обычное число (например, число с плавающей запятой) скаляром. Смысл этого заключается в том, что скаляр имеет только «масштаб» или величину, в то время как вектор имеет как величину, так и направление.

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

Аналогичным образом, скалярное деление делит величину первоначального вектора на скаляр.

Эти операции полезны, когда вектор представляет смещение движения или силу. Они позволяют изменить величину вектора без изменения его направления.

Когда любой вектор делится на свою собственную величину, результатом является вектор с величиной 1, который известен как нормализованный вектор. Если нормализованный вектор умножается на скаляр, то величина результата будет равна этому скалярному значению. Это полезно, когда направление силы постоянно, но сила контролируется (например, сила от колеса автомобиля всегда толкает вперед, но мощность контролируется водителем).

Точковое произведение

Произведение точек берёт два вектора и возвращает скаляр. Этот скаляр равен величинам двух векторов, умноженных вместе и результату, умноженным на косинус угла между векторами. Когда оба вектора нормализованы, косинус по сути говорит о том, насколько далеко первый вектор простирается в направлении второго (или наоборот — порядок параметров не имеет значения).

Два вектора 2D, представленные как направленные линии, проходят через одну и ту же точку начала. Вектор a продолжается прямо вверх с положительным компонентом y, но без компонента x. Вектор b продолжается вверх на меньший компонент y, чем вектор a, и вправо с положительным компонентом x. Линия, описывающая область оси y, охватываемую обоими векторами, обозначается как a умноженное на b.
Два вектора 2D, представленные как направленные линии, проходят через одну и ту же точку начала. Вектор a продолжается прямо вверх с положительным компонентом y, но без компонента x. Вектор b продолжается вверх на меньший компонент y, чем вектор a, и вправо с положительным компонентом x. Линия, описывающая область оси y, охватываемую обоими векторами, обозначается как a умноженное на b.

Ниже вы можете увидеть сравнение того, как векторы различных углов по сравнению с референцным вектором возвращают значение продукта точки между 1 и -1 :

Серия векторов излучается под углом от 0 до 180 градусов от вектора отсчета. Между 0 и 90 градусами от вектора отсчета произведение точек находится между 1 и 0 и уменьшается с увеличением угла. Между 90 и 180 градусами от вектора отсчета произведение точек находится между 0 и -1 и уменьшается с увеличением угла.
Серия векторов излучается под углами от 0 до 180 градусов от векторной точки отсчета. Между 0 и 90 градусами от векторной точки отсчета произведение точек находится между 1 и 0 и уменьшается с увеличением угла. Между 90 и 180 градусами от векторной точки отсчета произведение точек находится между 0 и -1 и уменьшается с увеличением угла.

Произведение точек является математически более простой операцией, чем вычисление косинуса, так что его можно использовать вместо функции Mathf.Cos или операции величины вектора в некоторых обстоятельствах (она не делает точно то же самое, но иногда эффект эквивалентен). Однако вычисление функции произведения точек занимает гораздо меньше CPU времени и поэтому может быть ценной оптимизацией.

Произведение точек полезно, если вы хотите рассчитать величину одного вектора, которая лежит в направлении другого вектора.

Например, спидометр автомобиля обычно работает, измеряя скорость вращения колес. Автомобиль может не двигаться прямо вперед (например, он может скользить вбок), в этом случае часть движения не будет в направлении, в котором движется автомобиль — и поэтому не будет измеряться спидометром. Величина вектора объекта rigidbody.velocity даст скорость в направлении общего движения, но для изолирования скорости в направлении вперед, вы должны использовать произведение точек:

var fwdSpeed = Vector3.Dot(rigidbody.velocity, transform.forward);

Направление может быть любым, но вектор направления всегда должен быть нормализован для этих расчетов. Не только результат более точен, чем величина скорости, он также избегает медленной операции квадратного корня, связанной с поиском величины.

Перекрестное произведение

Перекрестное произведение имеет смысл только для векторов 3D. Оно принимает два вектора 3D в качестве входа и возвращает еще один вектор 3D в качестве результата.

Вектор результата перпендикулярен двум входным векторам. Вы можете использовать «правило винта правой руки», чтобы запомнить направление выходного вектора из порядка входных векторов. Если вы можете закрутить пальцы в порядке входных векторов, ваш большой палец указывает в направлении выходного вектора. Если порядок параметров обратен, то результатный вектор будет указывать в точно противоположном направлении, но будет иметь ту же величину.

Величина результата равна величинам входных векторов, умноженных вместе, а затем это значение умножено на синус угла между ними. Некоторые полезные значения синусовой функции показаны ниже: -

Серия векторов излучается под углом от 0 до 180 градусов от вектора отсчета. Между 0 и 90 градусами от вектора отсчета, поперечное произведение находится между 0 и 1, и увеличивается по мере увеличения угла. Между 90 и 180 градусами от вектора отсчета, поперечное произведение находится между 1 и 0, и уменьшается по мере увеличения угла.
Серия векторов излучается под углом от 0 до 180 градусов от вектора отсчета. Между 0 и 90 градусами от вектора отсчета, поперечное произведение находится между 0 и 1, и увеличивается по мере увеличения угла. Между 90 и 180 градусами от вектора отсчета, поперечное произведение находится между 1 и 0, и уменьшается по мере увеличения угла.

Кросс-произведение может показаться сложным, так как оно объединяет несколько полезных частей информации в возвращаемом значении. Однако, как и точечное произведение, оно очень эффективно математически и может быть использовано для оптимизации кода, который в противном случае зависит от более медленных трансцендентных функций, таких как синус и косинус.

Расчет нормального/перпендикулярного вектора

“Нормальное” вектор (т.е. вектор, перпендикулярный к плоскости) часто требуется во время создания сетки и также полезно в пути следования и других ситуациях. Заданные три точки в плоскости, скажем, вершины треугольника сетки, вы можете найти нормальное следующим образом:

  • Выберите одну из трех точек
  • Вычитаем его из каждой из двух других точек отдельно (в результате получаем два новых вектора, «Страна 1» и «Страна 2»)
  • Рассчитать перекрестное произведение вектора «Страна 1» и «Страна 2»
  • Результатом перекрестного произведения является новый вектор, который перпендикулярен плоскости, на которой лежат три первоначальные точки — «нормальной».
Три точки a, b и c в координатном пространстве 3D образуют вершины треугольника. Векторное вычитание b и c из a даёт длинные стороны треугольника, сторону 1 от a до b и сторону 2 от a до b. Пересечение вектора стороны 1 и вектора стороны 2 даёт новый вектор, перпендикулярный плоскости, на которой лежат три первоначальные точки.
Три точки a, b и c в координатном пространстве 3D образуют вершины треугольника. Векторное вычитание b и c из a даёт длинные стороны треугольника, сторону 1 от a до b и сторону 2 от a до b. Пересечение вектора стороны 1 и вектора стороны 2 даёт новый вектор, перпендикулярный плоскости, на которой лежат три первоначальные точки.
Vector3 a;
Vector3 b;
Vector3 c;

Vector3 side1 = b - a;
Vector3 side2 = c - a;

Vector3 normal = Vector3.Cross(side1, side2);
Левая рука демонстрирует правило левой руки для определения порядка ввода векторов для расчета перекрестного произведения. Указательный и большой палец вытянуты под прямым углом друг к другу, а средний палец вытянут в третьей плоскости под прямым углом к указательному. Указательный и большой палец представляют первый и второй вводные векторы для расчета перекрестного произведения соответственно. Средний палец представляет полученную нормаль.
Левая рука демонстрирует правило левой руки для определения порядка ввода векторов для расчета перекрестного произведения. Указательный и большой палец вытянуты под прямым углом друг к другу, а средний палец вытянут в третьей плоскости под прямым углом к указательному. Указательный и большой палец представляют первый и второй вводные векторы для расчета перекрестного произведения соответственно. Средний палец представляет полученную нормаль.

«Правило левой руки» может быть использовано для определения порядка, в котором два вектора должны быть переданы в функцию перекрестного произведения. Как только вы смотрите вниз на верхнюю сторону поверхности (от которой нормаль будет указывать наружу), первый вектор должен проходить по часовой стрелке до второго:

Результат будет указывать в точно противоположном направлении, если порядок входных векторов будет изменен.

Для мешей нормальный вектор также должен быть нормализован. Это можно сделать с помощью свойства normalized, но есть другой трюк, который иногда полезно использовать. Вы также можете нормализовать перпендикулярный вектор, разделив его на его величину:-

float perpLength = perp.magnitude;
perp /= perpLength;

Другое полезное примечание, что площадь треугольника равна perpLength / 2. Это полезно, если вам нужно найти площадь поверхности всей сетки или хотите выбрать треугольники случайно с вероятностью, основанной на их относительных площадях.

Дополнительные ресурсы