Графические эффекты в четырех стихиях — опыт разработчиков Norland

Всем привет! Мы небольшой командой уже несколько лет разрабатываем 2D стратегию Norland — симулятор средневекового королевства.

Это вторая статья про 2Д рендеринг разнообразных эффектов в нашей игре. Предыдущую статью можно прочитать здесь. Напомню, что игра двухмерная и разрабатывается на движке Game Maker Studio 2.

Сегодня рассмотрим четыре стихии — воду, огонь, землю и воздух. Какие графические эффекты они скрывают в себе? Давайте узнаем.

Вода

Пока что вода не оказывает глубокого влияния на геймплей в Norland — ну на ней нельзя строить здания — вот и все. Рыбу пока не половить, корабли не построить. Но, тем не менее, ее все равно нужно как-то рендерить.

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

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

Мокап воды
Мокап воды

Я примерно понимал, как сделать шейдер для воды — бесшовная текстура с “каустикой” накладывается на тайлы с водой, а волны и рябь имитируются с помощью движения UV координат поверхности воды по особой текстуре с шумом (эффект, более известный как Displacement).

Каустику я нашел на OpenGameArt, а вот где взял текстуру для сдвига UV координат уже не помню — в интернете они фигурируют под разными именами (например bump mapping water texture)

Графические эффекты в четырех стихиях — опыт разработчиков Norland

Эффект прост — в каждой точке я беру r и b компоненту цвета Displacement текстуры — это значение сдвига, которое я прибавляю к текстурным координатам каустики. При этом Displacement текстура зациклена и постоянно сдвигается в каком-то направлении (в этом же направлении будет распространяться рябь воды).

Итоговый эффект на движке игры
Тот же эффект в SHADERed

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

Код фрагментного шейдера можно увидеть, кликнув дважды на “Simple” в “Pipeline” проекта.
Код фрагментного шейдера можно увидеть, кликнув дважды на “Simple” в “Pipeline” проекта.

Я опускаю некоторые тонкости конкретно нашей реализации — в Noralnd используется 3 тайлсета для воды — берег, дно и пену, из которых собирается итоговый тайл с водой. Поэтому шейдер выглядит сложнее, чем тот, который я представил в SHADERed — например для пены используется своя displacement текстура для более мягкого движения, а также происходит смешивание цветов всех текстур для получения итоговой картинки.

Графические эффекты в четырех стихиях — опыт разработчиков Norland

Огонь

Изначально для создания эффекта горящих домов использовались только частицы. Однако я быстро столкнулся с проблемой: чтобы достичь плотного и насыщенного огненного эффекта, требовалось значительное количество частиц. Это, в свою очередь, негативно сказывалось на производительности игры (Game Maker Studio 2.3 не самый производительный движок), особенно когда пожар охватывал половину города. К тому же мне не нравился получившийся эффект — огонь казался не плотным и не особо вписывался в окружение. Результаты этой работы можно увидеть в анонсном трейлере игры.

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

Эффект состоит из нескольких частей:

  • Создание текстуры огня из шума перлина, наложение этой текстуры на здание и анимация полученного результата (простое движение огня снизу вверх);
  • Потемнение текстуры здания и последующее его “растворение” (эффект, более известный, как Dissolve) для полного уничтожения здания, охваченного пожаром;
  • Частицы нескольких типов — дым, разлетающиеся от пожара искры и старый эффект огня, который использовался в гораздо меньших масштабах, чем раньше.
Соблюдайте...
...технику безопасности

Этот эффект я также перенес в SHADERed.

Земля

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

Пример плохого тайлинга
Пример плохого тайлинга

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

Вот такие предварительно нарисованные «кляксы» случайно распределялись по карте
Вот такие предварительно нарисованные «кляксы» случайно распределялись по карте

Минус клякс был очевиден — чтобы обеспечить равномерное покрытие карты, размером 31,500 x 22,500 нужно разместить очень много таких декалей, они так или иначе будут пересекаться между собой, создавая overdraw (лишняя отрисовка пикселей, которые будут не видны на экране, из-за перекрытия объектов). И то их может быть недостаточно (как оказалось). К тому же форма этих клякс заранее определена, чтобы добавить новые – нужно создавать их вручную в редакторе.

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

Скажем спасибо редизайну - в нем больше нет блока "Код"<br />
Скажем спасибо редизайну - в нем больше нет блока "Код"

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

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

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

Результат до и после.

Воздух

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

LUT (Look-Up-Table) — штука, более известная в среде фотографов и видеографов. Но ее назначение везде одинаковое — покрасить изображение определенным образом.

LUT представляет собой текстуру (обычно 512х512 пикселей), в которой зашифрован весь RGB диапазон цветов. Представьте, что это куб, разделенный по слоям. Текстура может выглядеть как-то так:

Нейтральная LUT-текстура, которая не будет менять цвета после применения шейдера цветокоррекции
Нейтральная LUT-текстура, которая не будет менять цвета после применения шейдера цветокоррекции

Идея в том, что каждому RGB цвету соответствует определенный пиксель в этой текстуре (rgb компоненты цвета используются в качестве координат в этой текстуре. Например для красного цвета (#ff0000 ) это будет правый верхний пиксель в самом первом квадрате).

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

Например мы хотим сделать эффект заката солнца с погружением мира в красные тона. Снимаем скриншот из игры, загружаем его в какой-нибудь фото-редактор и начинаем играться с параметрами цвета в различных инструментах (Hue/Saturation, Brightness, Contrast и т. д.). Я, пожалуй, остановлюсь на сдвиге Hue в красную сторону и увеличением насыщенности, но можно не останавливать полет фантазии — например, можно выкрутить saturation только у красного цвета, а все остальное сделать серым (привет, Город грехов)

После этого, нужно применить те же настройки цвета для нейтральной LUT-текстуры. На выходе получим вот такой результат:

LUT-текстура, к которой применили настройки изменения цвета<br />
LUT-текстура, к которой применили настройки изменения цвета

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

Код шейдера можно посмотреть здесь

Скажем спасибо редизайну - в нем больше нет блока "Код"
Скажем спасибо редизайну - в нем больше нет блока "Код"

В Norland мы используем комплект из 5 разных LUT-текстур, каждая из которых соответствует какому-то времени суток — утро, день, вечер, закат, ночь, а также особую текстуру для освещения искусственными источниками света. В каждый момент времени активны какие-то 2 текстуры, которые смешиваются между собой для эффекта плавного изменения цветокора. Например, если утро в игре начинается в 6 часов, а день в 12, то в 8 часов будет применен цветокор, путем смешивания 33:66 двух LUT-текстур (утра и дня).

Графические эффекты в четырех стихиях — опыт разработчиков Norland
Смена дня и ночи

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

Надеюсь, вам было интересно! Спасибо!

6363
30 комментариев

Круть. Жду релиз, когда он кстати?) Вроде бы хотели осенью прошлого года, а в стиме апдейт про март 23го.

1

Участвуем в фестивале демок Steam летом (вот-вот уже почти), и потом почти сразу в ранний доступ выходим. Так что скоро!

7

Красавчики, вы. Мне тоже нужна такая вода срочно! У меня в 2д всего лишь одна сцена карта Кампании. И там вода пока жуткая, саму карту решил делать повеселее раньше это было противопоставление черного и белого как в шахматах, но смотрелось уныло.

1

Выглядит весьма симпатично (теней только не хватает, на мой вкус, для контрастности) 👍

1

Спасибо за статью - простым языком про полезные штуки)

Рад, что понравилось)

2

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