Реалистичная вода в мидкоре: как сохранить FPS и красоту

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

Рассмотрим, какие бывают подходы к созданию воды в мобильных играх (на примере мидкор-проекта Railroad Empire) и на ПК. 

Бонусом ссылки на шейдеры с комментариями в конце статьи.

Подходы

Всё сильно зависит от сеттинга. Где-то вода — всего лишь «заполняющий элемент», а где-то — неотъемлемая часть сложной многопоточной механики.

Суммарно, я бы разделил создание воды на две группы:

  1. С имитацией волн (дорого, подходит для ПК и консолей).
  2. Без имитации волн (дешево, подходит для мобильной разработки).

Имитация волн

Есть много способов реализации: от просчета вершин в лоб на CPU до запекания в Vertex Animation Texture или Alembic (для синематиков).

Наш фаворит среди алгоритмов «колыхания воды» — герстнеровские волны (они же трохоидальные волны). Это база, если речь идет о AAA-проекте и вода является частью геймплея.

Для тех, кто хочет поподробнее разобраться в этом алгоритме, в конце статьи я написал небольшой сетап для URP на HLSL. Есть облегченная (подходит для мобильной разработки) и продвинутая версии (не подходит для мобильной разработки) с использованием тесселяции. 

Дальнейшие улучшения, чтобы сделать воду еще более красивой и реалистичной, происходят за счет: 

  • добавления дополнительных шумов;
  • добавления отражений на воде;
  • каустики;
  • смешивания нормалей;
  • просчета глубины;
  • создания лагуны;
  • просчета дистанции отрисовки пены у берега 
  • и т.д.

Но все это уже больше для ПК и консолей, чем для мобильных игр.

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

В мобильной разработке при создании воды, как правило, ограничиваются парой циклов Герстнера, 30-40 трисами на чанк воды и 3-4 текстурами. Оставшаяся мощность идёт на игровые механики и UI.

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

Теперь поговорим про них.

Без имитации волн

«Плоская вода» значительно меньше бьет по вычислениям на CPU и GPU. Но всё, опять же, сильно зависит от сеттинга. 

Например, в Railroad Empire вода — заполняющий элемент сцены, поэтому у нас не было потребности в герстнеровских колебаниях и прочих украшательствах. 

Но, как оказалось, нас ждали другие челленджи.

Как делают воду в мобильной разработке (чаще всего)

Самым простым и часто используемым вариантом считается — смешать две нормали между собой, добавить кубмапу для фейковых отражений и сделать правильную развертку геометрии (например, реки). Тогда можно не прибегать к добавлению еще и флоумапы, так как дополнительные текстуры всегда утяжеляют шейдер.

Некоторые обходятся и без нормалей, экономя еще 4-6 FPS. Текстуры шума разносят по RGBA-каналам, лерпают их, уводят в пересвет. И вот на воде появляется приятное подобие бликов.

Но иногда рациональнее иметь один плоский mesh, сделать примитивный планарный мапинг и нарисовать флоумапу, по которой будет течь вода.

На всякий случай: флоумапа — это текстура, которую используют для определения направления потока жидкости или частиц в шейдерах.

Как делаем мы (в Railroad Empire)

На мидкор-проекте Railroad Empire мы использовали одну текстуру нормалей, но выжали из нее максимум. В результате получили мягкие рандомные блики, как и хотели. Фейковые отражения получили через кубмапу, а красивые лагуны вместе с пеной через маскирование.

Чтобы не использовать тяжелые алгоритмы просчета глубины, добавили на альфа-канал одной из текстур маску прозрачности, а переходы у берегов рисовали в другом канале вручную, чтобы придать воде «объем», при этом сохранить минимум текстур. 

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

Чтобы постоянно не рисовать флоумапу в 3D-редакторах перегоняя туда-сюда текстуры, был написан кастомный Flowmap-Painter, которым художники рисовали воду и её элементы прямо в Unity. 

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

Что еще бывает

Как уже писал, вариантов великое множество, но почти все они не про мобильную разработку.

Кто-то даже умудряется создавать целые чёрно-белые секвенции на 100 с лишним кадров и более — лишь бы получить красивую текстуру колыханий волн и запустить её как паттерн смещения вертексов. Кто-то запекает цикловые анимации в Alembic (на мобильных устройствах не поддерживается), а иногда рациональнее вообще перенести колыхание поверхности на кости.

Bonus

Вернуться в блог