Публикация направлена на новичком или людей плохо знакомых с VFX Graph
.
Перед началом:
Использована версия
Unity 2022.3
, должно работать на всех версиях выше2020.2
Перед началом поставьте галочку в
Preferences > Visual Effect > Experemental Operators/Blocks
Данные кривых будут указаны как "значение" = "точка х" или "промежуток от х до у". Вы можете использовать свои кривые, я даю их в основном для справки. Это не удобно для чтения, но способа лучше не нашлось.
Если значения кривой не указаны в каком-то промежутке, значит они свободно интерполируют между указанными точками.
Создаём следующий скелет:
Эффект будет состоять из Strip
'ов, так что добавляем все необходимые блоки в System
. Создаём две первые переменные, они нам понадобятся в дальнейшем.
![](https://habrastorage.org/getpro/habr/upload_files/109/40e/e6e/10940ee6e3c84198f63228e51ff2b125.png)
Добавляем Set custom attribute
в Initialize
, в инспекторе даём ему имя Progress
. Устанавливаем атрибут при помощи оператора Get Attribute: spawnIndexInStrip
(обычный spawnIndex даёт неверные значения) делённого на переменную PartAmount
. Теперь в этом атрибуте хранятся числа в диапазоне от 0 до 1 в зависимости от положения на линии.
Добавляем Get Custom Attribute
, в инспекторе указываем имя атрибута Progress
, добавляем оператор Sample Bezier
, добавляем Set Position
. Соответствующим образом подключаем их друг к другу. Теперь мы можем увидеть дугу, поместив ассет на сцену! Всё что будет дальше, это операции над линией, с целью придания ей характеристик молнии.
![](https://habrastorage.org/getpro/habr/upload_files/15a/efb/ec5/15aefbec5b84a12ed72f9df00834dc6d.png)
![](https://habrastorage.org/getpro/habr/upload_files/ae4/b6b/6fb/ae4b6b6fba32cb6d19b81c0fae89f03d.png)
Чтобы было удобнее размещать молнию на сцене, создаём четыре переменных для задания позиции кривой Безье, переводим позиции из local
в world
. Добавляем на GameObject
с Visual Effect
VFX Property Binder
, соответствующим образом устанавливаем значения всех переменных как позиции других GameObject
. Теперь мы можем контролировать форму и позицию кривой Безье прямо в редакторе меняя позиции указанных GameObject
'ов, избегая хардкодинга.
![Промежуточный результат со значением Set Size = 0.05. Промежуточный результат со значением Set Size = 0.05.](https://habrastorage.org/getpro/habr/upload_files/9c9/d76/e6a/9c9d76e6a4ad43d6a6c1b42221199a49.png)
Set Size
= 0.05. Теперь добавим оператор шума и необходимые для его контроля переменные. Быстро перечислю переменные и их значения: NoiseFrequency
(2), NoiseOctaves
(3), NoiseRoughness
(0.5), NoisePower
(0.1), MoveDelta
(1.5). Все их подключаем к оператору Value Noise 3D
. Noise Power
и -Noise Power
используется для создания Vector 2
, и передаётся в Range
. Чтобы молния слишком не отклонялась от первой и конечной точки, умножаем Vector2
на Sample Curve
, в качестве Time
которой использован Custom Progress
. Sample Curve
равна 0 = 0, 1 = от 0.1 до 0.9, 0 = 1. Get Position
передаём в качестве координат шуму. Результат в виде Derivatives
передаём в Add Position
в Udate
.
![](https://habrastorage.org/getpro/habr/upload_files/d9d/293/13f/d9d29313f80f837f714bd367b27544f4.png)
![С добавлением шума. С добавлением шума.](https://habrastorage.org/getpro/habr/upload_files/65f/2fd/bf4/65f2fdbf4db920967df1d63d94aabe89.png)
![](https://habrastorage.org/getpro/habr/upload_files/3d7/712/774/3d771277409606adf16b103757581945.png)
Однако, молния каждый раз одинаковая, поскольку шум детерминистический. К тому же, молния не двигается. В реальной жизни удар молнии состоит из двух этапов: 1) сначала молния движется сверху вниз и ветвится, 2) как только одна из ветвей достигает земли по ней проходит мощный той, происходит основная вспышка. Чтобы не перегружать эффект симуляцией ветвления и оставить туториал простым (к тому же, все кроме первой достигшей поверхности ветви должны быть тусклее основной), будем просто менять координаты шума в первую половину эффекта. После вспышки молния будет замирать и исчезать.
Добавляем новый кастомный атрибут MoveSpeed
и устанавливаем его равным Total Time(Game)
. В Update также устанавливаем значение MoveSpeed
= Delta Time(VFX) * Noise Speed * Sample Curve + MoveSpeed
. Для T
кривой используем Age Over Lifetime
. Sample Curve
равна 1 = от 0 до 0.5, 0 = от 0.6 до 1. Добавляем результат MoveSpeed
к координатам шума. Кривая будет регулировать количество движения.
![](https://habrastorage.org/getpro/habr/upload_files/9d6/d90/9b1/9d6d909b1862ff1647dc98ad3ef046da.png)
Добавляем HDR цвет (Мой равен R 3.08
G 7.12
B 22.6
) (Чтобы HDR работал, добавьте в Post Procces Bloom
). Умножаем цвет на кривую с T
AgeOverLife
равную 0.1 в промежутке от 0 до 0.5, 1 = от 0.6 до 0.8, и 0.4 = на координате 1.
Устанавливаем альфу тоже как кривую с таким же T
, значения 0 = 0 до 0.1, 0.1 = 0.2, 0 = 0.3 до 0.5, 1 = 0.5 до 0.85, 0 = 1. Я также умножаю альфу на кривую использованную с NoisePower, чтобы скрыть острые края начала и конца молнии.
![](https://habrastorage.org/getpro/habr/upload_files/4c4/a8e/ebb/4c4a8eebb43af758d4e6fcb916079b6f.png)
![Получается уже довольно неплохо! Получается уже довольно неплохо!](https://habrastorage.org/getpro/habr/upload_files/4bf/c0c/7e9/4bfc0c7e96eb9dac513e95b03efce467.gif)
Чтобы вторая часть эффекта выглядела лучше и отделялась от первой, добавим вспышку. А раз есть вспышка, для баланса нужна ещё и область с тёмным цветом. Это улучшит баланс контраста.
Для вспышки создаём простой (копеечный) Initialize Particle
с Output Particle Quad
. Настраиваем его по своему вкусу, здесь главное чтобы момент вспышки совпал с началом второй части молнии. Для удобства использования ассета я также нахожу центр между Pos1
и Pos2
, и устанавливаю его в качестве координаты вспышки, а расстояние между этими точками использую для Scale
по вертикали. Момент вспышки регулирую с помощью Curve
0 = 0 до 0.5, 1 = 0.6, 0 = 0.75 до 1.
![](https://habrastorage.org/getpro/habr/upload_files/d09/bf1/76f/d09bf176fa191361aa9b30bfd58d839d.png)
![](https://habrastorage.org/getpro/habr/upload_files/12a/305/87f/12a30587f5ffd9b57167521cccd2b06d.png)
Теперь, тёмная часть. Это будет декаль на поверхности, в которую ударяет молния. Всё просто, создаём партикль, поворачиваем его на -90 градусов по х, чтобы он проецировался на поверхность снизу. Для цвета использую Color2
(R 4.28
G 1.09
B 0
) (понадобиться дальше) делённый на 4, а для альфы кривую 0 = 0 до 0.5, 0.6 = 0.6, 0 = 1.
![](https://habrastorage.org/getpro/habr/upload_files/b5e/678/4e2/b5e6784e229354355218278eb5dfc794.png)
![](https://habrastorage.org/getpro/habr/upload_files/b79/a48/2f1/b79a482f140b6ff46c1b1334703e6bbd.png)
![](https://habrastorage.org/getpro/habr/upload_files/78a/cbd/9c1/78acbd9c105afae1012cb1044534f518.gif)
Я дополнительно добавлю стилизованное перекрестье в нижней точке молнии + небольшие отлетающие частицы, чтобы передать импакт.
Единственный примечательный момент графа перекрестья состоит в том, что чтобы корректно повернуть Quad
к камере, для угла z используется Camera.transform.angles.z + spawnIndex * 90 + 45
. То есть, первая линия перекрестья появится под углом 45 градусов к камере (spawnIndex
считает с нуля), а вторая линия под углом 135.
![](https://habrastorage.org/getpro/habr/upload_files/4bf/b81/708/4bfb81708ba866c2917cfc8e1e5b810e.png)
![](https://habrastorage.org/getpro/habr/upload_files/db2/8db/501/db28db50171d73f2e0fb37a1d61eb695.png)
Для разлетающихся частиц располагаем их на сфере в Initialize
, а в Update
добавляем Conforn To Sphere Attraction Force
относительно сферы с большим радиусом (или же отрицательный Attraction Force
для сферы (или точки) меньшего диаметра).
![](https://habrastorage.org/getpro/habr/upload_files/6f3/047/baf/6f3047bafea644359095712e76c43974.png)
![](https://habrastorage.org/getpro/habr/upload_files/09b/6bb/f8c/09b6bbf8c87402590dcea17aff302d7b.png)
![Итого Итого](https://habrastorage.org/getpro/habr/upload_files/c79/c1f/283/c79c1f2831cd635b90781158f31914b1.gif)
Итого мы имеем ассет, который имеет:
Удобные якоря
GameObject
для расположения на сцене.Форму мелких неровностей, которая условно случайная.
Баланс контраста.
Ощущение импакта.