Point Cloud Morphing FX на Unreal Engine 4

Как создать эффект 3d морфинга на движке Unreal Engine 4.

Всем привет!

В статье опишу алгоритм и процесс создания своей версии Point Clouds Morphing VFX для Unreal Engine 4.

Что из себя представляет Point Clouds Morphing?

Это эффект трансформации (плавного перехода) между 3d моделями, которые представлены в виде particles (частиц) в трехмерном пространстве:

Point Cloud Morphing FX на Unreal Engine 4

Прежде чем начать работу над VFX, я сформулировал требования, которым итоговая реализация должна удовлетворять:

  • Полностью на BluePrint без использования C++.

  • Не должно быть сложных и тяжелых расчётов на CPU.
  • Лимит по количеству частиц позволяющий показать среднюю по детализации 3d модель.
  • Морфинг любого количество исходных частиц в любое целевое в пределах лимита.
  • Поддержка трансформации вращения и перемещения.
  • Возможность кастомизации по цвету и другим параметрам.
  • Возможность масштабирования лимита для C++ версии.

Итак, у нас есть две 3d модели и нам нужно трансформировать одну модель в другую.

Как мы знаем, 3d модель содержит в себе информацию о vertex (вершинная координата). На основе вертексов формируются треугольники, которые затем видеокарта отрисовывает.

Каждый вертекс содержит всю необходимую информацию для рендеринга 3d модели, но нам в данном случае для создания эффекта нужны только координаты вертекса, описывающие его положение в пространстве, т.е. XYZ:

Point Cloud Morphing FX на Unreal Engine 4

Разумеется, пересчитывать координаты, трансформации и т.д. на CPU было бы крайне неэффективно, поэтому весь расчет производится на GPU.

После некоторого резёрча и процесса подумать, стало очевидно - самый простой и эффективный способ хранить данные и оперировать с ними при помощи GPU, это запечь (bake) координаты вертексов в текстуру. На выходе мы и получим тот самый Point Cloud. Фактически - текстуру в которой хранятся координаты вертексов модели в специальном формате.

Упаковываем координаты в текстуру

Следующий вопрос - как запечь координаты в текстуру средствами Unreal Engine 4 при этом только используя BluePrint?

Для этого я использовал RenderTarget и отрисовку данных непосредственно в него. Фактически мы рисуем в текстуру с помощью доступных в UE4 средств смещаясь по текстуре (Pixel Coordinate).

Для рисования используется DrawLine функция с параметрами линии шириной в 1 пискел и длиной в 1 пиксел.

Т.е. мы поточечно рисуем всю текстуру:

Point Cloud Morphing FX на Unreal Engine 4

Т.о. мы берём из 3d модели все координаты её вертексов и отрисовываем их значения. На выходе получаем вот такую Point Cloud текстуру:

Здесь нужно более подробно рассказать о формате в котором хранятся данные в текстуре.

Дело в том, что изначально координаты в 3d модели представлены в виде float значений. А каждый такой float занимает 4 байта или 32 бита. Соответственно, чтобы нам сохранить данные о координате всего лишь одного вертекса потребуется 12 байт.

Это достаточно расточительно и потребовалось бы значительно увеличивать размер текстуры. Поэтому я ограничил размер модели, которая может быть использована для эффекта в диапазоне от -32767 до +32767.

Фактически под один компонент координаты вертекса (X, Y или Z) отводится 16 бит integer значения. Т.е. это не число с плавающей точкой.

16й бит это знак + или - и остальные 15 битов непосредственно для задания координаты.

Т.о. чтобы упаковать все три компоненты вертекса в Point Cloud текстуру нам нужно 6 байтов вместо 12.

Разумеется можно было бы упаковать и полноценный float, но сам по себе эффект используется локально и очень маловероятно что потребуется использовать большие диапазоны.

Второй момент который нужно было учитывать - это процесс распаковки (декодирования) координаты из текстуры в назначения на GPU.

16 bit значение состоит из Hi Byte и Low Byte:

Point Cloud Morphing FX на Unreal Engine 4

Мы округляем значение координаты до Integer. Если в модели координата имеет значение 345,783, то алгоритм упаковки выполнит округление до 346.

Дробная часть нам не нужна, т.к. мы не работаем с полигонам, а лишь задаем координаты для центра частиц близко к оригинальным значениям из 3d модели.

Например, число 12345 будет представлено в виде двух байтов:

HiByte = 48

LowByte = 57

48 * 256 + 57 = 12345

Далее, полученные два байта конвертируется в два компонента linear цвета для точки, которым мы и рисуем в текстуре.

Третий компонент RGB цвета отвечает за видимость частицы - это visibility флаг

На выходе мы получаем цвет точки которую и рисуем в RenderTarget текстуру, показанную в видео выше.

Point Cloud Morphing FX на Unreal Engine 4

Компоненты X,Y и Z рисуются в текстуру с определенным смещением в RGB каналы текстуры:

X компонента со смещением 0 по горизонтали и вертикале.

Y компонента со смещением 128 по горизонтали и 0 по вертикале.

Z компонента со смещением 0 по горизонтали и 128 по вертикале.

В четвертую область текстуры я записываю значение видимости - т.е. Visibility flag.

Point Cloud Morphing всегда отрисовывает заданное количество частиц.

Но т.к. разные модели содержат разное количество вертексов, и если количество точек в модели меньше чем заданное, то несуществующие я помечаю, как невидимые.

На картинке выше красным цветом - это те точки которые существуют в исходной модели. Координаты же дублируются до максимального возможного значения 16384.

Отрисовка на GPU

Имея запеченные в текстуры координаты вертексов и флаг их видимости можно отрендерить частицы.

Для того, чтобы процесс отрисовки не отнимал очень много ресурсов и выполнялся за 2 draw calls я использовал одну из features UE4 - Instanced Static Mesh Component.

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

Вся отрисовка происходит внутри материала (shader). В качестве параметров в материал подается две текстуры, а так же все другие необходимые данные, например степень морфинга (0...1), цвет частиц и т.д.

Первая текстура - текущая модель.

Вторая текстура - модель в которую будет происходить морфирование.

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

Point Cloud Morphing FX на Unreal Engine 4

Внутри выполняются следующие действия:

  • Декодирование координаты для вертекса из HiByte и LowByte в значение для обеих Cloud текстур. Это и будет центр частицы.
  • Поворот полученной точки вокруг центра эффекта на требуемые углы и смещение если требуется.
  • Применение цвета, свечения и других пользовательских настроек.
  • Если частица невидима (Visibility flag равен 0), то частица рисуется размером 0.
  • Интерполяция между координатами, цветом и др. параметрами текущей модели и целевой.

В зависимости от смещения (0,128) материал декодирует требуемую компоненту для её сборки в координату.

Если же целевая модель имеет больше точек чем исходная то в процессе морфинга идет увеличение размера частицы от 0 до 1.0, ровно так же и и обратную сторону - интерполяция значения от 1.0 до 0.

Т.к. координаты продублированы в Point Cloud текстуре - создается эффект того, что частицы создаются из существующих и формируют новую структуру.

Если же в целевой модели меньше частиц, частицы из исходной будут стремиться в координаты существующих точек у целевой модели.

Добавляется дополнительный пользовательский distortion, а также custom значения для scale.

Определенный хак пришлось сделать, чтобы определять какой частице соответствует индекс в текстуре.

К сожалению нельзя получить внутри материала индекс Instanced Mesh Component'а, поэтому изначально все инстансы создаются со смещением.

Разница в смещении инстанса (world position) и есть индекс по которому материал выбирает нужную координату из Point Cloud текстуры и рассчитывает частицу.

Частица представлена в виде двух треугольников, которые всегда обращены к камере.

Результат геометрического расчёта отправляется на WPO (World Position Offset) вход материала.

В финале получаем результат:

Подводя итог:

Эффект почти полностью рассчитывается на GPU.

На CPU выполняется лишь логика смены текстур и передача некоторых параметров в материал - цвет, настройки distortion, степень морфинга и т.д.

16384 частиц (с возможностью расширения в С++ версии).

Полностью на UE4 BluePrint.

PointCloud текстура 256x256 точек, RGB. Не требует много места.

Рендер происходит за 2 draw calls.

Возможностью запечь любую модель в пределах 16384 точек и размером от -32767 до +32767.

Эффект протестирован на PC (SM5), PS4 и Nintendo Switch.

Время на разработку ... undetermined =)

На этом всё, благодарю за внимание!

4040
6 комментариев

Прикольно. Но на практике такое же делают в Niagara вроде как без проблем.

Ответить

На практике ниагара еще в глубокой бете, что у некоторых товарищей по цеху периодически вызывает лютую попаболь, и когда из нее выйдет - хз.

Опять же, если посмотреть на дату создания видео, то Ниагарой там и не пахло даже. .)

4
Ответить

На практике за каждый ms идёт борьба ) А так в целом можно и алебмик с мофингом сетки ))

1
Ответить

так то всё просто, тут крутость в том что два дроукола

Ответить

Как по мне наиболее сложный момент здесь это как раз сделать адекватного вида материал. Не раз встречались с моментом когда буквально один мат сжирал всю производительность)

Ответить

Вероятно тяжелых операций поменьше, вроде выборки из текстурных сэплеров в большом количестве и т.д. А так же общее количество инструкций. PCM не тяжелый материал - 216 инструкций и 5 сэмплеров, если убрать повороты и трансформацию будет ещё легче.

Ответить