Публикация направлена на новичком или людей плохо знакомых с VFX Graph.

Перед началом:

  • Использована версия Unity 2022.3, должно работать на всех версиях выше 2020.2

  • Перед началом поставьте галочку в Preferences > Visual Effect > Experemental Operators/Blocks

  • Данные кривых будут указаны как "значение" = "точка х" или "промежуток от х до у". Вы можете использовать свои кривые, я даю их в основном для справки. Это не удобно для чтения, но способа лучше не нашлось.

  • Если значения кривой не указаны в каком-то промежутке, значит они свободно интерполируют между указанными точками.

Создаём следующий скелет:

Эффект будет состоять из Strip'ов, так что добавляем все необходимые блоки в System. Создаём две первые переменные, они нам понадобятся в дальнейшем.

Добавляем Set custom attribute в Initialize, в инспекторе даём ему имя Progress. Устанавливаем атрибут при помощи оператора Get Attribute: spawnIndexInStrip (обычный spawnIndex даёт неверные значения) делённого на переменную PartAmount. Теперь в этом атрибуте хранятся числа в диапазоне от 0 до 1 в зависимости от положения на линии.

Добавляем Get Custom Attribute, в инспекторе указываем имя атрибута Progress, добавляем оператор Sample Bezier, добавляем Set Position. Соответствующим образом подключаем их друг к другу. Теперь мы можем увидеть дугу, поместив ассет на сцену! Всё что будет дальше, это операции над линией, с целью придания ей характеристик молнии.

Чтобы было удобнее размещать молнию на сцене, создаём четыре переменных для задания позиции кривой Безье, переводим позиции из local в world. Добавляем на GameObject с Visual Effect VFX Property Binder, соответствующим образом устанавливаем значения всех переменных как позиции других GameObject. Теперь мы можем контролировать форму и позицию кривой Безье прямо в редакторе меняя позиции указанных GameObject'ов, избегая хардкодинга.

Промежуточный результат со значением Set Size = 0.05.
Промежуточный результат со значением 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.

С добавлением шума.
С добавлением шума.

Однако, молния каждый раз одинаковая, поскольку шум детерминистический. К тому же, молния не двигается. В реальной жизни удар молнии состоит из двух этапов: 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 к координатам шума. Кривая будет регулировать количество движения.

Добавляем 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, чтобы скрыть острые края начала и конца молнии.

Получается уже довольно неплохо!
Получается уже довольно неплохо!

Чтобы вторая часть эффекта выглядела лучше и отделялась от первой, добавим вспышку. А раз есть вспышка, для баланса нужна ещё и область с тёмным цветом. Это улучшит баланс контраста.

Для вспышки создаём простой (копеечный) Initialize Particle с Output Particle Quad. Настраиваем его по своему вкусу, здесь главное чтобы момент вспышки совпал с началом второй части молнии. Для удобства использования ассета я также нахожу центр между Pos1 и Pos2, и устанавливаю его в качестве координаты вспышки, а расстояние между этими точками использую для Scale по вертикали. Момент вспышки регулирую с помощью Curve 0 = 0 до 0.5, 1 = 0.6, 0 = 0.75 до 1.

Теперь, тёмная часть. Это будет декаль на поверхности, в которую ударяет молния. Всё просто, создаём партикль, поворачиваем его на -90 градусов по х, чтобы он проецировался на поверхность снизу. Для цвета использую Color2 (R 4.28 G 1.09 B 0) (понадобиться дальше) делённый на 4, а для альфы кривую 0 = 0 до 0.5, 0.6 = 0.6, 0 = 1.

Я дополнительно добавлю стилизованное перекрестье в нижней точке молнии + небольшие отлетающие частицы, чтобы передать импакт.

Единственный примечательный момент графа перекрестья состоит в том, что чтобы корректно повернуть Quad к камере, для угла z используется Camera.transform.angles.z + spawnIndex * 90 + 45. То есть, первая линия перекрестья появится под углом 45 градусов к камере (spawnIndex считает с нуля), а вторая линия под углом 135.

Для разлетающихся частиц располагаем их на сфере в Initialize, а в Update добавляем Conforn To Sphere Attraction Force относительно сферы с большим радиусом (или же отрицательный Attraction Force для сферы (или точки) меньшего диаметра).

Итого
Итого

Итого мы имеем ассет, который имеет:

  • Удобные якоря GameObject для расположения на сцене.

  • Форму мелких неровностей, которая условно случайная.

  • Баланс контраста.

  • Ощущение импакта.

Комментарии (0)