Это первая из двух частей, посвящённых ориентации одного объекта на другой в Unity. В частности, мы увидим, как заставить 3D-модель камеры наблюдения автоматически поворачиваться в сторону Player, отслеживая его перемещения по сцене.


Видеоверсия этого руководства в настоящее время недоступна на этом языке.


Текстовая расшифровка видео

Всем привет!

Это первая из двух частей, посвящённых ориентации одного объекта на другой в Unity. В частности, мы увидим, как заставить 3D-модель камеры наблюдения автоматически поворачиваться в сторону Player, отслеживая его перемещения по сцене.

Этот урок создан в Unity 2022 и разделён на две части.

В первой части мы проанализируем задачу и решим её с помощью метода Rotate, чтобы получить мгновенный поворот камеры.

Во второй части мы будем использовать кватернионы и метод Slerp для создания более плавного и постепенного вращения.

Перед тем как переходить к реализации, разберём саму задачу.

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

И 3D-модель камеры наблюдения, и Player, как и все игровые объекты, имеют координаты позиции XYZ, которые определяют их положение в сцене.

Нас не интересует координата position.y, потому что камера может вращаться только вокруг этой локальной оси, поэтому мы будем учитывать только координаты x и z, как если бы оба объекта находились на одной плоскости с одинаковым значением y.

В нашем случае камеру наблюдения можно считать началом системы координат, то есть точкой 0,0 на декартовой плоскости.

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

Мы можем определить направление, соединяющее виртуальную камеру и позицию Player в сцене. Это просто вектор, который в нашем случае мы также будем рассматривать только в двух измерениях, то есть по глобальным X и Z.

Следовательно, вращение, которое нужно применить к камере наблюдения, определяется углом между текущей ориентацией модели, её отрицательной локальной осью Y, и идеальным вектором, соединяющим камеру с Player. Найдя этот угол, мы получим значение поворота вокруг локальной вертикальной оси 3D-модели.

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

Конкретно Atan2 вычисляет угол между осью X декартовой плоскости и вектором направления между началом координат и целью.

В нашем случае начало координат задаётся X и Z координатами 3D-модели камеры наблюдения, поэтому координаты цели x и y будут равны разности координат между камерой и Player, а ось X совпадает с отрицательной локальной осью Y камеры.

Функция принимает параметры в обратном порядке. В декартовой системе это atan2(y, x). В нашем случае, учитывая систему координат Unity, где ось x является боковой, ось z фронтальной, а ось y вертикальной, которую мы здесь не учитываем, мы будем писать atan2(x, z).

Согласно документации Unity, Mathf.Atan2 принимает координаты y и x, которые в нашем случае будут x и z, и возвращает значение типа float, представляющее угол в радианах, тангенс которого равен y/x.

Функция Rotate в Unity принимает угол поворота в градусах, поэтому при написании кода необходимо учитывать различие единиц измерения и выполнить преобразование.

Теперь, когда мы разобрали задачу и её решение, перейдём к первой реализации: мгновенный поворот с помощью Rotate.

Сначала создадим новый C#-скрипт под названием LookAtObject и привяжем его к самой камере наблюдения. Я говорю «к самой камере», потому что этот ассет состоит из трёх элементов: основания для крепления на стене, pivot-элемента и самой камеры.

Нас интересует, чтобы камера вращалась вокруг своей вертикальной оси, то есть вокруг своей локальной вертикальной оси.

В виртуальном пространстве Unity глобальная вертикальная ось — это ось y, но у каждого объекта может быть собственная локальная система координат. В случае 3D-модели камеры наблюдения это локальная ось Z, что можно увидеть, переключившись в режим отображения LOCAL в редакторе Unity.

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

Сначала создадим ссылку на объект, за которым нужно следить. Для этого объявим переменную типа Transform с именем objectA и свяжем её с Player в Inspector.

[SerializeField] private Transform objectA;

После этого можно перейти в метод Update для реализации решения. Напоминаю, что локальная вертикальная ось камеры — это её ось Z.

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

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

Во второй строке вычислим величину поворота вокруг локальной оси Z камеры для достижения нужной ориентации.

В третьей строке выполним сам поворот с помощью метода Rotate, которому нужно передать два параметра: локальный вертикальный вектор и величину поворота вокруг этого вектора.

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

Мы уже видели, что в двумерной плоскости Atan2 принимает два параметра: разность координат Y и разность координат X двух точек, в порядке цель и наблюдатель.

В нашем случае, с глобальной системой координат Unity, где X и Z лежат в плоскости, а глобальная ось Y является вертикальной осью сцены, нужно написать:

float theta = Mathf.Atan2((objectA.transform.position.x - transform.position.x),(objectA.transform.position.z - transform.position.z)) * Mathf.Rad2Deg;

Таким образом мы сразу переводим результат в градусы.

Переходим ко второй строке, где вычисляем величину поворота в градусах:

float deltaAngle = Mathf.DeltaAngle(transform.eulerAngles.z, theta);

Здесь transform.eulerAngles.z — это текущая ориентация камеры наблюдения, а theta — ориентация, рассчитанная на предыдущем шаге, которую она должна принять.

Третья и последняя строка выполняет поворот камеры:

transform.Rotate(Vector3.forward, deltaAngle);

Обратите внимание, что используется Vector3.forward, который обозначает локальную ось Z объекта, вокруг которой выполняется вращение. В данной 3D-модели локальная ось Z соответствует вертикальной оси объекта, а не направлению вперёд и назад.

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

ПРИМЕЧАНИЕ - Если камера наблюдения не направлена на цель, убедитесь, что начальные значения XYZ Rotation камеры в Inspector установлены в 0, и попробуйте снова.

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

Затем мы реализовали мгновенный поворот объекта, заставляя его в каждом кадре игры смотреть на Player с помощью функции Rotate.

Во второй части мы рассмотрим вычисление кватернионов вращения и использование функции Slerp для более плавного поворота объекта.

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


РАСШИРЕННАЯ ИНФОРМАЦИЯ О ПОЛИТИКЕ КОНФИДЕНЦИАЛЬНОСТИ И ИСПОЛЬЗОВАНИИ ФАЙЛОВ COOKIE