Всем привет, меня зовут Григорий Дядиченко, и я обожаю VFX. В данной статье хочется больше поговорить про VFX Graph, про его функции и про то, как там можно сделать простенькие вихри (разными способами). Если вам интересна тема Unity и VFX, добро пожаловать под кат.

Сразу скажу, что эта статья скорее про работу с VFX Graph, чем про создание самого по себе вихря. С двух точек зрения. Если вам нужно сделать красивое торнадо, есть способы оптимальнее и лучше. Как пример один способ описывается тут и он часто будет оптимальнее, проще и эффектнее. С другой стороны, я не буду разбирать "симуляцию вихря", уравнения Навье-Стокса или циркуляционную теорему Кельвина. Мы будем разбирать, как сделать эффект похожий на вихрь, какие инструменты есть для этого в VFX Graph и т.п. Подобная работа с частицами может скорее дополнить эффект из видео выше, или сделать через частицы воздействие на окружение подобных торнадо. Ну для начала покажем что получилось.

Подготовка графа

В отличии от Shuriken в VFX Graph эммитеры по форме не выравнивают скорость по этой форме. Если мы хотим сделать аля торнадо, первое что нам нужно сделать — это эммитер в виде конуса. Такой в VFX Graph есть.

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

Конус в сущности представляет из себя "закрученный" треугольник. Если разобрать треугольник, то в нашем случае он состоит из Top Raduis и Height. При этом из математики известно, что тангенс угла равен отношению противолежащей стороны к прилежащей в прямоугольном треугольнике. Так как задавать нам нужно высоту и угол, то осталось найти Top Radius. На рисунке ниже можно посмотреть расчёт.

То есть радиус равен тангенс угла при основании, умноженный на высоту. Давайте перенесём это всё в VFX Graph.

Так как углы привычнее задавать в градусах, а не в радианах, а в тангенсе угол в радианах, то сначала мы переводим градусы в радианы по формуле:

radAngle = \frac{Angle * \pi}{180}

Но так как мне удобнее использовать общий угол из основания конуса, то мы делим его на 2 или вместо 180 делим на 360. Всё вынесено в графе в внешние параметры для удобства контроля, теперь мы можем регулировать наш конус углом и высотой.

Так же в VFX Graph мы можем контролировать спавн частиц. В целом чтобы при изменении высоты и угла не менялась (до определённого предела) плотность частиц вихря, нам нужно изменять рейт спавна в зависимости от параметров. Так как я хочу, чтобы частицы были на боковой поверхности конуса, логично использовать за некий параметр использовать площадь боковой поверхности конуса. Формула прощади боковой поверхности конуса:

S = \pi R l

так что теперь нам надо найти l. Для этого есть несколько способов, как пример теорема Пифагора, но мы воспользуемся более простым, так как у нас есть угол, да ещё и в радианах. Как известно из той же тригонометрии:

cos(alpha)=\frac{h}{l}

в наших терминах. Поэтому искомая:

l = \frac{h}{cos(alpha)}

Запишем это в виде графа с формулой боковой поверхности конуса:

Итак, со спавном мы вроде разобрались. Да, стоит сказать что математика выше подходит чтобы получить равномерное распределение частиц на поверхности конуса. Для распределения частиц в объёме нужна формула объёма. То, что частицы спавнятся на поверхности задаётся в настройках Set Position (Shape: Arc Cone). И дополнительная константа в графе и параметр Rate нужны просто для удобства.

Путь 1. Касательная к окружности

Пора начать разбираться со скоростями. Первая идея, что мне пришла в голову, чтобы получить нужный эффект. Касательная к окружности конуса. Если посмотреть на конус сверху, то это просто серия вложенных окружностей. Мы всегда можем узнать позицию частицы в VFX Graph с помощью Get Attribute: position, а дальше всё дело техники. Так как у нас локальная система координат, то нужная нам касательная к окружности — это нормаль к радиусу. Нормаль в нашем случае представляет из себя:

n = (-dz; dx)

Так как мы находимся в плоскости XZ. Но в локальной системе координат мы возьмём ещё за упрощения, что все частицы вращаются вокруг оси (0, 0). Так что dx = x - 0 = x, где x — позиция конкретной частицы. То есть:

n = (-z; x)

Что в графе превратится в

и выглядит как-то так:

Выглядит в целом неплохо, но у этого способа есть одна проблема. Если мы попробуем добавить скорость вращения частиц, то частицы начнут выходить на новые орбиты чисто из-за принципа решения. Для примера скорость вращения частиц 5:

Если что скорость делается просто домножением вектора скорости на константу.

Путь 2. Вращение частиц

Чтож, так не получилось. Давайте попробуем что-нибудь другое. Тут я пожалуй сразу покажу граф целиком, а потом объясню, что он делает и почему:

Выглядит этот вихрь уже вот так:

Идея такова, что мы работаем теперь не в скоростях, а в позиция. У нас есть центральная ось и вокруг неё в плоскости XZ мы вращаем частицы. Поэтому важно, что теперь задаётся позиция, а не скорость. Скорость зависит от радиуса окружности, чтобы частицы двигались быстрее, если они находятся на большей орбите + добавлен небольшой рандом для более "натурального" эффекта. Верхняя часть с эммишеном частиц никак не изменилась, по сути мы изменили только принцип движения. Визуально в целом неплохо и можно менять скорость, при этом ни одна частица не уйдёт с орбиты. Но потом я решил добавить ещё одну функцию "наклон орбит" и граф стал таким:

Что уже позволило делать такие эффекты:

В заключении

Спасибо за внимание! Существует множество способов делать эффекты вихря, торнадо и прочего в играх. Данный способ будет скорее полезен в ознакомительных целях с функционалом VFX Graph + ознакомлением с некоторыми идеями, которые могут кому-то пригодится. А также показывает, что знание математики бывает весьма полезно в работе разработчика игр. Хотя данный эффект я бы возможно применил не для самого торнадо, а для визуализации его последствий или какой-то "рядом летающей пыли". Это конечно не совсем вихри, так как в реальном вихре кривые будут сходиться к центру и вниз, но как некоторый сильно упрощённый визуальный эффект может быть кому-то полезен.

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


  1. aml
    29.05.2022 07:21

    Вы используете vfx graph, а не текстовый код для шейдеров, потому что это удобнее, или в нем возможно что-то, что в тексте нельзя сделать?


    1. DyadichenkoGA Автор
      29.05.2022 18:04
      +1

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

      1. Высокий уровень абстракции может оптимизироваться автоматически

      Шейдеры написанные на glsl и hlsl нельзя оптимизировать компилятором, так как это довольно чёткие инструкции о том, что надо сделать. А вот графы проще оптимизировать, проще подсовывать им реализации под VR с сингл пасс стерео рендером, так как это условно "логическое описание, а не чёткая инструкция". Но как обратная сторона любой абстракции высокого уровня, её нельзя тонко настраивать и зная юнитеков, если там будут баги - это может стать проблемой

      2. Дебаг шейдеров

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

      В общем кодом я так же шейдеры пишу, но сейчас я пишу и так, и так. Просто если не требуется прям до спичек оптимизировать - графы норм. Если нужно сначала за прототипировать, описать сам эффект, глянуть его, а потом уже переписать нормально - граф в среднем будет быстрее с точки зрения "попробовать разное". А когда сам шейдер идейно готов, уже можно написать оптимально, если вдруг тормозит.


      1. aml
        30.05.2022 10:16

        Спасибо за ответ. Меня немного граф пугает, потому что код-ревью делать невозможно и diff/merge нормально не работают в git.


  1. iwchak
    31.05.2022 00:39

    Отличная статья, спасибо Вам за труды.