Реалистичная вода в мидкоре: как сохранить FPS и красоту
Реалистичная вода может стать ключевым аспектом при создании филлинга в игре. Слишком сложный и детализированный визуал воды нагружает CPU и GPU, приводя к вылетам на большинстве девайсов.
Рассмотрим, какие бывают подходы к созданию воды в мобильных играх (на примере мидкор-проекта Railroad Empire) и на ПК.
Бонусом ссылки на шейдеры с комментариями в конце статьи.
Подходы
Всё сильно зависит от сеттинга. Где-то вода — всего лишь «заполняющий элемент», а где-то — неотъемлемая часть сложной многопоточной механики.
Суммарно, я бы разделил создание воды на две группы:
- С имитацией волн (дорого, подходит для ПК и консолей).
- Без имитации волн (дешево, подходит для мобильной разработки).
Имитация волн
Есть много способов реализации: от просчета вершин в лоб на 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 (на мобильных устройствах не поддерживается), а иногда рациональнее вообще перенести колыхание поверхности на кости.