Vector3 magnitude что это
Unity3d. Уроки от Unity 3D Student (B21-B24)
Базовый урок 21 — Вычисление расстояния между объектами
В уроке будет показано, как получить расстояние между двумя точками в трехмерной сцене, используя метод Vector3.Distance. Кроме того, в дополнение к оригинальному уроку я расскажу о свойстве Vector3.sqrMagnitude, при помощи которого можно получить более оптимизированный код вычисления расстояния.
При разработке игры часто возникает необходимость узнать расстояние между объектами. Один из самых простых способов это сделать — использовать метод Distance класса Vector3.
Рассмотрим следующую сцену: кубик fallbox, падающий вниз на более большой куб Cube; точечный источник света Point light, находящийся между ними; и, конечно, камера.
Если мы захотим, чтобы источник света загорался только тогда, когда он находится в пределах определенной дистанции от падающего куба, то нужно создать следующий скрипт:
Код на JavaScript:
В скрипте мы сперва объявляем переменную box, в которой будем хранить ссылку на компонент Transform нашего падающего ящика. Затем в Update вызываем метод Vector3.Distance, передав в качестве аргументов координаты объектов, между которыми требуется вычислить расстояние. Полученное расстояние заносим в переменную dist и сравниваем его с необходимым значением (10 в нашем примере). Если расстояние не превышает заданное значение — включаем компонент света, в противном случае — выключаем. При помощи метода Debug.Log выводим значение текущего расстояния в консоль.
Добавляем скрипт на объект света Point Light, в поле скрипта Box перетаскиваем fallbox, запускаем сцену. Кубик падает вниз, свет не горит. При расстоянии между светом и кубиком
В уроке рассказывается, как сделать паузу (задержку) в игре с использованием метода WaitForSeconds и инструкции yield.
Если вы хотите реализовать паузу между некими игровыми событиями (например, создание игровых объектов через определенные промежутки времени), то необходимо воспользоваться Корутинами (сопрограммами). Корутина — это специальным образом оформленный метод, работающий в основном потоке игры, и обычно вызываемый после метода Update. Корутина, в зависимости от заданных условий, может прервать свое выполнение в определенной точке своего кода, а затем вновь продолжить работу (подробнее о корутинах есть на хабре — прим. переводчика).
Посмотрим на сцену ниже. На ней есть куб, играющий роль земли, источник света, камера и пустой объект под именем spawn point, висящий над землей. Кроме того, в папке Project есть префаб weight — кубик с компонентом rigidbody. Наша цель — периодически создавать кубики из префаба в точке spawn point, после чего они будут падать на землю.
Создать объект легко — нужно воспользоваться уже знакомым методом Instantiate. Однако, если мы просто напишем вот такой скрипт и добавим его к объекту spawn point…
Код на JavaScript:
… то получим примерно следующую картину:
Буквально за пару секунд выполнения у нас создалось слишком много объектов. Это не удивительно, ведь мы поместили создание объекта в метод Update, который вызывается каждый кадр игры, т. е. несколько десятков раз в секунду. Любые попытки как-то вставить задержку в метод Update, чтобы объекты создавались реже, ни к чему хорошему не приведут — это уменьшит FPS игры. Вместо этого нам поможет корутина.
Давайте реализуем скрипт создания объектов следующим образом:
Код на JavaScript:
Итак, в переменный box мы храним ссылку на префаб порождаемого объекта. Булева переменная readynow служит для определения, запускать ли сейчас метод-корутину MakeBox, которая создает объект. Внутри корутины MakeBox мы сперва запрещаем ее вызов (readynow = false), потом создаем объект методом Instantiate, а затем используем связку yield / WaitForSeconds (обратите внимание на различия в коде для JS и в коде для C# — прим. переводчика). Эта связка позволяет приостановить выполнение корутины, в данном случае, на 2 секунды, а потом вернуться обратно и продолжить выполнение, где мы теперь разрешаем вызов корутины (readynow = true). Метод Update при этом не простаивает эти 2 секунды, а продолжает выполняться, только не запускает заново новую корутину, пока не отработает предыдущая.
Напоминаю, что скрипт надо добавить к объекту spawn point, перетащить в поле скрипта Box префаб кубика и запустить сцену. Теперь кубики создаются через каждые 2 секунды.
Дополнительные материалы:
Базовый урок 23 — Система частиц
Если вы хотите создать дым, огонь, пыль или иное распространение неких частиц, то можно использовать систему частиц. В этот раз на нашей сцене есть падающий кубик, который исчезает при соприкосновении с землей. Наша цель — сделать так, чтобы исчезновение сопровождалось эффектом взрыва.
Теперь необходимо написать небольшой скрипт и добавить его к нашему взрыву. Это скрипт будет отвечать за уничтожение системы частиц со сцены, после того, как все ее частицы прекратят существование:
Код на JavaScript:
В скрипте мы сохраняем компонент системы частиц в переменной ps. В методе Update проверяем присутствие компонента на сцене. Если он есть — проверяем, «жив» ли он. Это делается при помощи вызова метода IsAlive — он вернет false, если система частиц больше не генерирует частицы и все ранее сгенерированные частицы исчезли. Если это так — удаляем объект системы частиц.
Дополнительные материалы:
Базовый урок 24 — Работа с циклом «For»
В уроке рассказывается об использовании оператора цикла «For», с помощью которого можно повторять необходимые действия, пока выполняется заданное условие.
При создании игры часто возникает задача выполнить несколько раз подряд некие повторяющиеся действия. Для этого не стоит «копипастить» код, а нужно воспользоваться циклами.
На нашей сцене есть земля, свет, камера и пустой объект creator.
Мы хотим, чтобы из объекта creator с небольшими паузами создались из префаба несколько других объектов. Для этого напишем следующий скрипт:
Код на JavaScript:
Vector3.magnitude
Success!
Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.
Submission failed
For some reason your suggested change could not be submitted. Please try again in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.
Description
Returns the length of this vector (Read Only).
If you only need to compare magnitudes of some vectors, you can compare squared magnitudes of them using sqrMagnitude (computing squared magnitudes is faster).
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
Is something described here not working as you expect it to? It might be a Known Issue. Please check with the Issue Tracker at
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
You’ve told us this page needs code samples. If you’d like to help us further, you could provide a code sample, or tell us about what kind of code sample you’d like to see:
You’ve told us there are code samples on this page which don’t work. If you know how to fix it, or have something better we could use instead, please let us know:
You’ve told us there is information missing from this page. Please tell us more about what’s missing:
You’ve told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You’ve told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You’ve told us there is a spelling or grammar error on this page. Please tell us what’s wrong:
You’ve told us this page has a problem. Please tell us more about what’s wrong:
Thanks for helping to make the Unity documentation better!
Is something described here not working as you expect it to? It might be a Known Issue. Please check with the Issue Tracker at issuetracker.unity3d.com.
Copyright © 2020 Unity Technologies. Publication Date: 2021-02-24.
Математика в Gamedev по-простому. Матрицы и аффинные преобразования
Всем привет! Меня зовут Гриша, и я основатель CGDevs. Сегодня хочется продолжить тему математики в геймдеве. В предыдущей статье были показаны базовые примеры использования векторов и интегралов в Unity проектах, а сейчас поговорим о матрицах и аффинных преобразованиях. Если вы хорошо разбираетесь в матричной арифметике; знаете, что такое TRS и как с ним работать; что такое преобразование Хаусхолдера – то вы возможно не найдёте для себя ничего нового. Говорить мы будем в контексте 3D графики. Если же вам интересна эта тема – добро пожаловать под кат.
Начнём с одного из самых главных понятий в контексте статьи – аффинные преобразования. Аффинные преобразования – это, по сути, преобразование системы координат (или пространства) с помощью умножения вектора на специальную матрицу. К примеру, такие преобразования, как перемещение, поворот, масштабирование, отражение и др. Основным свойствами аффинных преобразований является то, что вы остаётесь в том же пространстве (невозможно сделать из трёх мерного вектора двумерный) и то, что если прямые пересекались/были параллельны/скрещивались до преобразования, то это свойство после преобразования сохранится. Помимо этого, у них очень много математических свойств, которые требуют знания теории групп, множеств и линейной алгебры, что позволяет работать с ними проще.
TRS матрица
Вторым важным понятием в компьютерной графике является TRS матрица. С помощью неё можно описать самые частые операции, используемые при работе с компьютерной графикой. TRS матрица – это композиция трёх матриц преобразования. Матрицы перемещения (Translation), поворота по каждой оси (Rotation) и масштабирования (Scale).
Выглядит она так.
Где:
Перемещение – это t = new Vector3(d, h, l).
Масштабирование – s = new Vector3(new Vector3(a, e, i).magnitude, new Vector3(b, f, j).magnitude, new Vector3(c, g, k).magnitude);
Поворот – это матрица вида:
А теперь перейдём чуть глубже к контексту Unity. Начнём с того, что TRS матрица – это очень удобная вещь, но ей не стоит пользоваться везде. Так как простое указание позиции или сложение векторов в юнити будет работать быстрее, но во многих математических алгоритмов матрицы в разы удобнее векторов. Функционал TRS в Unity во многом реализован и в классе Matrix4x4, но он не удобен с точки зрения применения. Так как помимо применения матрицы через умножение она может в целом хранить в себе информацию об ориентации объекта, а также для некоторых преобразований хочется иметь возможность рассчитывать не только позицию, а изменять ориентацию объекта в целом (к примеру отражение, которое в Unity не реализовано)
Все примеры ниже приведены для локальной системы координат (началом координат считается позиция GameObject’а, внутри которого находится объект. Если объект является корнем иерархии в юнити, то начало координат – это мировые (0,0,0)).
Так как с помощью TRS матрицы можно в принципе описать положения объекта в пространстве, то нам нужна декомпозиция из TRS в конкретные значения position, rotation и scale для Unity. Для этого можно написать методы-расширения для класса Matrix4x4
Кроме того, для удобной работы можно реализовать пару расширений класса Transform, чтобы работать в нём с TRS.
На этом плюсы юнити заканчиваются, так как матрицы в Unity очень бедны на операции. Для многих алгоритмов необходима матричная арифметика, которая в юнити не реализована даже в совершенно базовых операциях, таких как сложение матриц и умножения матриц на скаляр. Кроме того, из-за особенности реализации векторов в Unity3d, так же есть, ряд неудобств, связанных с тем, что вы можете сделать вектор 4х1, но не можете сделать 1х4 из коробки. Так как дальше пойдёт речь про преобразование Хаусхолдера для отражений, то сначала реализуем необходимые для этого операции.
По сложению/вычитанию и умножению на скаляр – всё просто. Выглядит достаточно громоздко, но ничего сложного тут нет, так как арифметика простая.
Но для отражения нам понадобится операция умножения матриц в конкретном частном случае. Умножение вектора размерности 4х1 на 1х4 (транспонированный) Если вы знакомы с матричной математикой, то знаете, что при таком умножении надо смотреть на крайние цифры размерности, и вы получите размерность матрицы на выходе, то есть в данном случае 4х4. Информации по тому, как перемножаются матрицы достаточно, поэтому это расписывать не будем. Вот для примера реализованный конкретный случай, который нам пригодится в будущем
Преобразование Хаусхолдера
В поисках того, как отразить объект относительно какой-либо оси, я часто встречаю совет поставить отрицательный scale по необходимому направлению. Это очень плохой совет в контексте Unity, так как он ломает очень много систем в движке (батчинг, коллизии и др.) В некоторых алгоритмах это превращается в достаточно нетривиальные вычисления, если вам надо отразить не банально относительно Vector3.up или Vector3.forward, а по произвольному направлению. Сам метод отражения в юнити из коробки не реализован, поэтому я реализовал метод Хаусхолдера.
Преобразование Хаусхолдера, используется не только в компьютерной графике, но в этом контексте — это линейное преобразование, которое отражает объект относительно плоскости, которая проходит через «начало координат» и определяется нормалью к плоскости. Во многих источниках оно описано достаточно сложно, и непонятно, хотя его формула – элементарна.
Где H – матрица преобразования, I в нашем случае – это Matrix4x4.identity, а n = new Vector4(planeNormal.x, planeNormal.y, planeNormal.z, 0). Символ T означает транспонирование, то есть после умножения n* (n^T) мы получим матрицу 4х4.
Тут пригодятся реализованные методы и запись получится очень компактной.
Важно: planeNormal должна быть нормализована (что логично), а также последней координатой n стоит 0, чтобы не было эффекта растяжения по направлению, так как оно зависит от длинны вектора n.
Теперь для удобства работы в Unity реализуем метод расширение для трансформа
На этом на сегодня всё, если этот цикл статей и дальше будет интересен, то буду раскрывать и другие применения математики в разработке игр. В этот раз проекта не будет, так как весь код помещается в статье, но проект с конкретным применением будет в следующей статье. По картинке можно догадаться о чём будет следующая статья.
Unity3d. Реализация зон видимости и слышимости
Сегодня расскажу о том, как можно реализовать систему видимости и слышимости для ваших проектов. Получилось нечто схожее с игрой Commandos.
Немного скриншотов.
Больше видимости.
Я тебя вижу
Как можно увидеть объект? Вариантов можно перечислить множество. Встречаются варианты с видимостью по коллайдерами, разбором картинки через рендер текстуру, лучи по точкам и т.д. В данном примере рассмотрим вариант лучей по точкам.
Следовательно нам понадобится базовый класс с точками для системы видимости.
Теперь. Нам нужно сформулировать требования к системе видимости.
Очевидно у юнита(не важно что это, друг, враг или камера видео-наблюдения) должен быть угол обзора и дистанция на которой он различает объекты. Близорукие и дальнозоркие тоже могут быть. Да и персонаж может, например, надеть очки и видеть дальше. Может что-то принять и видеть чуть шире боковым зрением. Следовательно параметры нам нужны цель, глаза, дальность и угол обзора.
LayerMask — нужен для лучей. Например на окно среагирует пуля но не зрение. Тоже самое с заборами или другими объектами. Следовательно, видимость игнорирует не нужные или прозрачные объекты. А спрятавшись в листве, можно обнулить список видимых точек. Также можно расширить или сузить список точек, в зависимости от логики самой игры. Например камуфляж или еще что-то.
Тут стоит обратить внимание на условие (hit.collider.gameObject == target). О том почему это так выглядит, будет понятно на примере использования. Системе отравляем желаемого юнита, и проверяем, реально ли мы можем его увидеть. Именно того которого хотим.
Тут не использовались хитрости с magnitude или преобразованием углов. Находим скалярное произведение. Если 1, значит точки направлены в одну сторону и угол можно опустить, иначе получаем угол и проверяем пределы.
А теперь я тебя еще и слышу
С системой слышимости все обстоит гораздо проще. На любой звук, мы перебираем всех допустимых юнитов (опустим как это реализовано. Главное что в текущей зоне или всей локации, есть какое-то количество юнитов) и передаем точку шума, ее радиус, и в данном случае еще и тип шума. Например на звук выстрела и звук падающего камня аи может реагировать по разному. Это зависит то того как вы это реализуете.
Система слышимости готова. Идем дальше.
Пример использования системы видимости
Ну а как-же без примера.
Нам понадобится метод получения доступных юнитов. Который по сути и будет точкой входа.
GetVisibleUnits — метод который вернет вам всех видимых юнитов, а дальше уже ваше непосредственная логика, что с этим делать.
Стоит обратить внимание. В этом примере есть глаза и возможные сенсоры. Сенсоры могут работать как угодно, например получение данных со спутника или с камер наблюдения, по запаху или еще как-нибудь. Мы их не рассматриваем в данном примере.
Дополнительно
Для существующей системы, дополнительно генерирую меш. Чтобы как в коммандос можно было определить, куда же смотрит противник. Ниже представлен код генерации меша (Повторять топологию местности задача вынесена за рамки текущей).
На деталях кода останавливаться не будем. Тут представлен обычный алгоритм генерации меша.
Подходим к концу.
Некоторые вещи не рассмотрены (Сенсоры или гизмо в редакторе) но вам не составит труда их реализовать отдельно. Надеюсь, данная статья вам помогла или подкинула пару идей.
Vector3.magnitude and vector3.normalized explanation
I am looking at this code and do not know what is this magnitude and normalized doing and how is this guy using them. In documentation there is only few thing but it doesn’t explain much.
Code i am looking at is:
And while i am here if someone could explain me Mathf.Clamp
Documentation for clamp is so unclear and how i got it is that i give top and bottom value 1 and 5 and if i set value = 3 it will return 3, but if i set value > 5 it will return 5 and if i set value Follow
3 Answers 3
Vector3.magnitude returns a float, its a single dimensional value expressing vector length (so it looses directional information)
The two are often useful for when you want to seperate those two ways of looking at a vector, for example if you need to have an influcence between two bodies where the influence is inversly proportional to the distance between them, you can do
this is the most typical use case for me, I am not sure what the author of the original code meant by his as it does seem he could just use a vector difference without using the two extra calls
Mathf.Clamp returns value of value lies between min and max, returns min if its lower and max if is greater.
Another interesting feature of Vector3 is sqrMagnitude which returns a^2+b^2+c^c without computhing the square root. While it adds a bit to the complexity to the code (you need to compare it with squared distance), it saves a relatively expensive root computation; The slightly optimised but a tiny bit harder to read version would look like this