«Нефелия: Сквозь облака»: полезные ассеты для неба и погоды

Всем привет, мы делаем ролевую игру/симулятор дирижабля «Нефелия: Сквозь облака» и я хотел рассказать про адаптацию чужих ассетов и создание своих ассетов для неба и облаков.

Было/стало
Было/стало

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

Оптимизация спавнера

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

Облаков мало и они довольно близко. Впрочем, статичный скайбокс на фоне не даёт хорошо определять расстояния
Облаков мало и они довольно близко. Впрочем, статичный скайбокс на фоне не даёт хорошо определять расстояния

При попытке хотя бы немного её увеличить fps просто катастрофически падал. Прочие способы оптимизации уже себя исчерпали: переход на пул объектов, появившийся в последних версиях Unity, лишь чуть улучшил положение, добавление LOD к моделям облаков тоже особо ничего не дало. Можно было решить эту проблему в стиле Silent Hill, но это превратило бы окружающее пространство в равномерную неинтересную серую стену. Завихрения тумана хорошо смотрятся, если хотя бы что-то проглядывается за туманом, а на фоне более далёкого слоя тумана будет выглядеть аналогично заливке одним цветом. К тому же, для облаков использовались 3d-модели с обычными вершинами, пусть и с анимирующим их шейдером (ассет Stylized clouds pack), а хотелось в итоге прийти к более реалистичному отображению. Поэтому пришлось вернуться к тому, что под разными предлогами (на самом деле — достаточно существенными вроде реализации кор-механик) откладывал больше года: нужно начинать адаптировать давно купленный ассет под названием SkyMaster. Почему так не хотелось этим заниматься?

пока удалось прийти примерно к такому внешнему виду
пока удалось прийти примерно к такому внешнему виду

Во-первых, мне гораздо проще взять небольшой ассет с минимумом функций, разобраться в том, как он работает, и добавить необходимый функционал (например, мне не хватало тегов в отдельных выборах в нарративном движке Ink, я добавил их поддержку), чем разбираться в монструозном большом комбайне. Но у таких комбайнов есть хорошая особенность: они могут работать сразу из коробки, если у вас плюс-минус стандартная ситуация. Вот только при любом отклонении от стандартных условий большая часть фич начинает работать не так, как нужно. Если в принципе начинает.

Малая часть часть настроек SkyMasterManager
Малая часть часть настроек SkyMasterManager

Вторая причина более специфична для ассетов для погоды в целом — они в основном заточены на игры, в которых небо является фоном для происходящего на земле. То есть во всём «мире» будет везде одна и та же погода (пусть и настраиваемая). Все облака будут рисоваться одним шейдером за один draw-call. Но при этом теряется возможность отдать обратно на уровень C# данные о тех участках неба, которые стали облаками в соответствии с действовавшим на стороне GPU алгоритмом их генерации. С точки зрения производительности это самое оптимальное решение. Если на облака можно просто смотреть, или даже просто летать сквозь них без каких-либо изменений с точки зрения геймплея, в этом нет никакой проблемы.

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

Вырвавшись из грозы
Вырвавшись из грозы

Системы частиц спешат на помощь

К счастью, в ходе переписки с автором SkyMaster удалось узнать, что кроме систем облаков на шейдерах есть ещё возможность использовать кастомные системы частиц. Идея довольно проста: кто сказал, что в трёхмерной игре обязательно нужны по-настоящему трёхмерные эффекты? Часто хватает нескольких биллбордов (всегда обращённых к камере полигонов), на которых показывается похожая на трёхмерный объект анимация или добавляется имитация объёма для каждой частицы с помощью специального шейдера. Для первого способа у Unity есть свой туториал, где используются анимированные текстуры (flipbooks).

туториал Unity по созданию анимированных псевдо-трёхмерных эффектов на флипбуках

Второй способ используется в SkyMaster и позволяет располагать облака именно там, где захотел спавнер, и в целом действовать почти как раньше, когда это были простые модели из полигонов. В дальнейшем стало ясно, что второй способ больше подходит для кучевых облаков, а с помощью первого можно ограниченно имитировать перистые, хотя для них, конечно, лучше всего подходят настоящие 3d-облака с процедурной отрисовкой через шейдер (в случае URP это происходит через модификацию графического пайплайна — render feature).

перистые 3D-облака из SkyMaster 
перистые 3D-облака из SkyMaster 
псевдо-3D облако на основе систем частиц
псевдо-3D облако на основе систем частиц

Производительность

Всё бы хорошо, но после простой замены предыдущих облаков на системы частиц производительность сразу упала примерно на 10 кадров в секунду. Правда, потом оказалось, что если вместо десятка мелких облаков рисовать одно большое + уменьшить число одновременно существующих частиц, ресурсов тратится существенно меньше, чем до всех изменений, и теперь можно просчитывать окружающий мир в радиусе 4 километров, о чём раньше и думать было нельзя. Но необходимость увеличения облаков привела к большому количеству изменений геймплея: например, раньше имела смысл попытка срезать путь через грозу, лавируя между небольшими тучами, а теперь гроза — просто способ рассечь линейное пространство + место, где можно зарядить конденсаторы, поймав молнию громоотводом.

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

Молнии

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

С молниями ничего не получилось по причине того, что ассет в целом не ориентирован на области с различной погодой в них: можно статически определить параллелепипед, внутри которого будут молнии (предполагается, что это и будет весь игровой мир, если мы «включили» в нём грозу), но динамически добавлять и убирать точки спавна молний или привязать их к префабу облака как с системой частиц здесь не получится. Поэтому пока пришлось использовать собственную систему частиц с трейлами (кстати, трейлы — это один из моментов, в которых старые системы частиц до сих пор превосходят VFX Graph), в дальнейшем планирую перейти на этот ассет.

туториал по созданию молний с помощью старой системы частиц

Скайбокс

В простейшем случае скайбокс — это «бесконечно далёкая» текстура, которая отрисовывается самой первой в кадре. В случае динамического скайбокса это шейдер, на выходе которого получается окружение, недостижимое для игрока: солнце, луна, далёкие облака и т. д. До того, как руки дошли до переделывания облаков, использовалась статичная текстура из бесплатного ассета AllSky Free.

Неплохие скайбоксы + плюс есть возможность настраивать некоторые параметры вроде оттенка: мне это пригодилось для имитации смены цвета неба при изменении высоты полёта. Но, конечно, это совсем не то, что хотелось бы видеть в итоге.

В SkyMaster есть множество демок с различными настройками для реалистичного неба, но, к сожалению, чтобы нормально настроить свои оттенки неба, нужно быть автором ассета: цвет задаётся 2 градиентами, которые по некоторым законам задают оттенки неба в разное время суток. По словам автора, всё очень физически достоверно, но совершенно недоступно для понимания. Поэтому я плюнул и начал использовать Super simple Skybox от OccaSoftware.

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

Всё действительно очень просто настраивается через Shader Graph (например, я переделал изменение цвета неба, чтобы оно зависело не только от времени суток, но и от высоты над горизонтом, и к ней же привязал количество фоновых 2d облаков). Единственное, что я пока не осилил — это добавить текстуру луны, чтобы она корректно преобразовывала попавшие в шейдер uv-координаты: получалось, что текстура проецируется на всё небо в целом и фрагмент этой текстуры проецируется на круг, а вместо этого нужно семплировать в пределах круга, который является частью луны в данный момент времени.

Луна может светить, но вот отображать текстуру - пока нет
Луна может светить, но вот отображать текстуру - пока нет

Одним шейдером рисуется небо, фоновые облака, звёзды, луна, закаты и восходы. Правда, на пользователе целиком остаётся реализация вращения светил для смены дня и ночи: необходимо назначить 2 источника света в сцене на роль солнца и луны, корректно вращать их, плавно включать и выключать на закате и восходе — но в целом в этом уже нет ничего сложного.

Эффект объёмного света взят из другого ассета того же автора  - <a href="https://api.dtf.ru/v2.8/redirect?to=https%3A%2F%2Fassetstore.unity.com%2Fpackages%2Fvfx%2Fshaders%2Ffullscreen-camera-effects%2Flspp-volumetric-lighting-god-rays-and-light-shafts-215146&postId=1370602" rel="nofollow noreferrer noopener" target="_blank">LSPP</a> 
Эффект объёмного света взят из другого ассета того же автора  - LSPP 

Оказалось, у Occa Software действует программа, по которой они бесплатно отдают ещё один свой ассет в обмен на положительный отзыв в AssetStore. Попросил у них более продвинутый скайбокс Altos и получил промокод на него.

Хорошо в этом ассете то, что уже есть нормальная смена дня и ночи из коробки, а также текстура луны и по-настоящему трёхмерные облака, которые можно расположить в качестве фоновых. Плохо то, что на границе между обычными моделями и полупрозрачными системами частиц появляются артефакты, далёкие объекты заливаются одним цветом и игнорируют полупрозрачные перед ними + производительность сразу ощутимо падает. Если бы я использовал этот ассет для игры, действие которой происходит на земле, он был бы однозначным фаворитом среди всего перепробованного в плане сочетания большого количества фич и простоты их настройки, но увы.

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

Дальнейшие планы

В следующей статье напишу о том, что использовалось для моделирования тумана и ветра и что ещё хочется сделать по визуалу.

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

Буду рад новым подписчикам в девлоге в telegram, группе vk, а также обратной связи по (теперь уже изрядно устаревшей) демке на itch.io

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