Как мы делали красивую двумерную воду в Unity

Cоздание почти трёхмерного окружения без трёхмерной графики.

Мы — это я, Егор, и Юра, наш художник, которому я упорно создаю след в сети, но он не торопится этим пользоваться. И, собственно, мы очень неспешно работаем над нашей игрой и иногда выкладываем всякие заметки о том, что там и как. В этот раз речь пойдёт о том, как мы захотели добавить водички в игру, но не смогли остановиться на слишком простом решении.

Сразу оговорюсь, что работаем мы в Unity и используем Universal Render Pipeline для отрисовки, но общие идеи можно перенести, конечно, и в другие пайплайны отрисовки и даже движки.

Макет

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

Макет

Сразу выделим, какие детали нужно будет реализовать:

  1. собственно, вода;
  2. пенка у колон и камней;
  3. туман.

План

Так как вся игра в 2D, доступа к высотам в точках у меня нет, и просто перенести 3D подход возможности не было. Поэтому я придумал другую хитрость — сделать отдельную камеру, копирующую основную, подменять в ней спрайты с помощью URP Renderer и дополнительных текстур и рисовать собственную карту высот, используя её. А по ней уже строить очертания моря и тумана.

Тут оговорюсь для людей, незнакомых с Unity, что URP (Universal Render Pipeline) — это один из вариантов пайплайнов отрисовки, который позволяет гибко настраивать, собственно, отрисовку. И идея тут в том, чтобы создать специальный способ отрисовки в специальной камере для некоторых игровых объектов.

Карта высот

Для начала нужно придумать, как её вообще рисовать. В обычном 3D она рисуется автоматически по мере записи в Depth Buffer (иногда и иначе, не будем задерживаться на этом), остаётся только взять её и использовать. Но так как у нас 2D-спрайты, то нам это, конечно же, не подходит.

Самый простой способ, как мне показалось, — это нарисовать специальную текстуру, копирующую текстуру колоны, где в каждом пикселе в B-канале (можно любой другой, это не так важно) будет записано, насколько этот пиксель текстуры ниже, чем точка «нуля».

Как мы делали красивую двумерную воду в Unity

В редакторе спрайтов Unity потом достаточно просто добавить вторичную текстуру и дать ей название.

Как мы делали красивую двумерную воду в Unity

Теперь нужно написать шейдер, который будет, собственно, заменять основную текстуру на дополнительную. Помимо этого, он должен немного перекодировать данные, потому что в текстуру влезет всего 256 значений (если она не sRGB, то больше, но это детали), а высота может быть раньше. В шейдер добавляем проперти _Meta и используем те же UV-координаты + вешаем математику сверху.

Как мы делали красивую двумерную воду в Unity

После я создал URP Renderer и добавил в него фичу для подмены материалов.

Как мы делали красивую двумерную воду в Unity

Теперь остаётся только создать камеру, поменять ей Renderer и настроить слои, получаем две картинки, одна из которых выводится на экран.

Как мы делали красивую двумерную воду в Unity

Вуаля, карта высот готова.

Вода

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

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

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

Как мы делали красивую двумерную воду в Unity

Собираем это всё и смотрим на море.

До макета еще далековато
До макета еще далековато

Оживляем море

Для отрисовки пены изначально я взял карту высот, прошёлся по ней блюром и пастеризовал в цветах воды. Сразу заметил, что пенка появляется и сверху картинки рядом с колонами, а не под ними, потому что не понимает, что колоны над ней.

Как мы делали красивую двумерную воду в Unity

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

Как мы делали красивую двумерную воду в Unity

На практике это выглядело вот так.

Как мы делали красивую двумерную воду в Unity

Уже получше. Далее я быстренько накинул шум, чтобы было что-то двигающееся. Выглядело оно так себе.

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

Но пена нам всё-таки не понравилась, решили переделать.

Пена 2.0

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

Как мы делали красивую двумерную воду в Unity

Теперь добавляем новую пену и делаем так, чтобы волны бились по угасающей синусоиде.

Туман

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

Как мы делали красивую двумерную воду в Unity

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

Переписав всё это добро, мы поигрались с самыми разными параметрами и добавили коня-колосса.

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

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

7979 показов
9.7K9.7K открытий
88 репостов
37 комментариев

Водичка чисто партиклами поверх голубой плоскости.

Ответить

Интересно выглядит) А можно скрин редактора с Gizmos иконками или описание в двух словах как оно работает? Здесь несколько систем частиц, стандартный ли эмитер или вы кастомили создание частиц.

Ответить

Комментарий недоступен

Ответить

- Вы в воде купаете?
- Нет, просто показываем, как сделали.
- Красивое.

Ответить

На asset store продаете?

Ответить

Комментарий недоступен

Ответить

Я не умею пользоваться реддитом, а Юра говорит, чтобы я разбирался. Ну а дальше мне лениво и как-то вот!

Ответить