Всем привет! Я не писал на Хабре целых 4 года.
Мой последний серия постов речь шла о различных инструментах и методах, которые мы использовали в нашей последней игре (разрабатывая ее в Unity).
С тех пор мы успешно выпустили эту игру, а также выпустили новую.
Так что теперь вы можете немного перевести дух и написать несколько новых статей, которые могут быть кому-то полезны.
Сегодня я хочу поговорить о графических приемах и приемах, которые мы использовали для создания картинки, которую вы видите на гифке выше.
Мы очень трепетно относимся к визуальной части наших игр и поэтому вложили довольно много времени и сил в различные эффекты и другие вкусности, которые сделали бы нашу пиксельную графику максимально привлекательной.
Возможно, кто-то найдет для себя что-то полезное.
Для начала кратко перечислю, из чего сделана картинка в нашей игре:
- Переменный рассеянный свет — банальное изменение освещенности в зависимости от времени суток.
- Цветокоррекция LUT – отвечает за изменение тона картинки в зависимости от времени суток (или типа зоны).
- Динамические источники света – факелы, печи, лампы.
- Карты нормалей отвечают за добавление объема объектам, особенно при движении источников света.
- Математика 3D светораспределения – отвечает за то, чтобы источник света в центре экрана правильно освещал объект, который находится вверху, но не освещал объект, который находится внизу (то есть неосвещенная сторона повернута к камере) .
- Тени — созданы спрайтами, вращаются и реагируют на положение источников света.
- Имитация высоты объекта — для корректного отображения тумана.
- Прочие декорации: дождь, ветер, анимации (в том числе шейдерная анимация листвы и травы) и т.д.
Изменяемое окружающее освещение
В принципе, ничего особенного здесь нет. Ночью темнее, днем светлее.Цвет света задается градиентом в зависимости от времени суток.
Ночью источник света не только темнеет, но и приобретает синий оттенок.
Это выглядит так:
ЛУТ-коррекция цвета
LUT (Look-up table) — таблицы замены цветов.Грубо говоря, это трехмерный RGB-массив, где каждый узел содержит значение цвета, на которое следует заменить соответствующее.
То есть, если в координатах (1, 1, 1) стоит красная точка, это означает, что весь белый цвет на картинке будет заменен красным.
Если координаты (1, 1, 1) содержат белый цвет (R=1, G=1, B=1), то никаких изменений не происходит. Соответственно, ЛУТ без изменений имеет цвет для каждой координаты, соответствующий этим самым координатам.
Те.
в точке (0,4, 0,5, 0,8) есть цвет (R=0,4, G=0,5, B=0,8).
Ну и стоит отметить, что для удобства 3D-текстура представлена как двухмерная.
Например, так выглядит «дефолтный» LUT (который никак не меняет цветопередачу):
Реализуется просто, работает быстро и удобно.
Настройка тоже очень простая — вы даете художнику любую картинку из игры и говорите «настройте цвета так, чтобы было похоже на вечер».
После этого вы применяете все слои цветокоррекции к LUT по умолчанию и получаете вечерний LUT. В нашем случае художник немного свихнулся и создал целых 10 разных LUT для разного времени суток (ночь, сумерки, вечер и т. д.).
Вот как выглядит их установка:
В результате в зависимости от времени суток одна и та же локация выглядит по-разному:
Здесь прозрачность спрайтов света из окон тоже меняется в зависимости от времени суток.
Динамическое освещение и карты нормалей
Источники света использованы абсолютно обычные, от Unity. Кроме того, для каждого спрайта рисуются карты нормалей, что позволяет получить ощущение объёма.
Рисуются такие нормали достаточно просто.
Художник примерно рисует кистью свет с 4-х сторон:
А затем скрипт собирает это в нормальную карту:
Если вы ищете шейдер (и программное обеспечение), который делает это, вы можете обратить внимание на Sprite Lamp.
3D-симуляция света
Здесь немного сложнее.Вы не можете просто подсветить спрайты.
Нам нужно учитывать, находится ли спрайт «за» источником света или «перед».
Обратите внимание на эту картинку:
Оба дерева находятся на одинаковом расстоянии от источника света, но самое дальнее дерево освещено, а ближайшее — нет (поскольку его неосвещенная часть повернута к камере).
Я решил эту проблему достаточно просто.
Шейдер вычисляет расстояние по вертикальной оси Y между источником света и спрайтом.
И если оно положительное (источник света находится перед спрайтом), то мы освещаем спрайт как обычно, а если отрицательное (спрайт перекрывает источник света), то интенсивность освещения очень сильно затухает с расстояния с помощью очень большой коэффициент. Коэффициент был сделан, а не просто «не освещать», чтобы при движении источника света и внезапном появлении за спрайтом спрайт не сразу становился черным, а постепенно.
Но все равно довольно быстро.
Тени
Тени создаются спрайтами, вращающимися вокруг точки.Я попробовал добавить к ним больше сжатия (перекоса), но это оказалось излишним.
Всего у каждого объекта может быть максимум 4 тени.
Один — от Солнца, а три — от динамических источников света.
На рисунке ниже показан принцип:
Задачу «найти ближайшие 3 источника света и рассчитать расстояние/угол теней до них» решает скрипт, запускаемый в Update. Да, очень быстро это не получится, потому что… приходится много заниматься математикой.
Если бы я писал сейчас, я бы использовал новомодную систему параллельных заданий в Unity. Но тогда этого еще не было, поэтому я просто максимально оптимизировал обычные скрипты.
Единственное, что важно, это то, что я вращал спрайты не с помощью трансформации, а внутри вершинного шейдера.
Те.
вращение не влияет. В спрайте просто задается параметр (я для этого использовал цвет, потому что все тени все равно черные), а за вращение спрайта отвечает шейдер.
Так получается быстрее, потому что… не нужно возиться с геометрией в Unity. Еще одним недостатком этого подхода является то, что тени приходится настраивать (а иногда и рисовать) индивидуально для каждого объекта.
Правда, мы обошлись, наверное, десятком разных более-менее универсальных спрайтов (тонких, толстых, овальных и т. д.).
Второй недостаток заключается в том, что иногда сложно создать тень для объекта, пятно контакта которого с землей очень вытянуто.
Например, посмотрите на тень забора:
Не идеально.
Вот как это будет выглядеть, если сделать сам спрайт забора полупрозрачным:
Здесь, однако, стоит отметить, что спрайт по-прежнему сильно деформируется по вертикали (исходный теневой спрайт выглядит почти как круг).
Именно поэтому его поворот выглядит не столько как поворот, сколько как искажение.
Моделирование тумана и высоты
Также в игре присутствует туман.Выглядит это так (вверху — обычный вариант, внизу — экстремальный 100% туман, для демонстрации эффекта).
Как видите, из тумана торчат верхушки домов и деревьев.
На самом деле добиться такого эффекта было довольно просто.
Туман состоит из множества горизонтальных облаков, которые распределены по всей глубине сцены.
В результате верхняя часть всех спрайтов покрыта меньшим количеством туманных спрайтов:
Ветер
Ветер в пиксельной графике — это совсем другая история.Здесь не так много вариантов.
Либо анимировать вручную (что практически невозможно, учитывая количество имеющегося у нас арта), либо писать деформирующий шейдер, но тогда придется терпеть порой некрасивые искажения.
Можно, конечно, вообще не анимировать, но тогда картинка будет выглядеть безжизненной.
Мы выбрали вариант искажения с помощью шейдера.
Это выглядит так:
Если вы примените этот шейдер к клетчатой текстуре, вы увидите, что происходит:
Также стоит отметить, что мы анимируем не всю крону, а только отдельные листья:
Еще у нас есть пшеница, колышущаяся на ветру, но здесь все просто — вершинный шейдер деформирует координаты x с учетом y-компоненты.
Чем выше точка, тем больше она колеблется.
Это делается для того, чтобы шаталась только верхушка, а корень – нет. Плюс — фаза покачивания меняется от координат x/y, так что разные спрайты на экране покачиваются в разное время.
Тот же шейдер также используется для создания эффекта покачивания пшеницы и травы, когда игрок проходит через них.
Пожалуй, это пока все.
Я намеренно не затронул вопрос построения сцены и ее геометрии, потому что.
Это материал для отдельной статьи.
В остальном он рассказал об основных решениях, которые использовались при разработке.
ПС: Если кого-то интересуют какие-либо технические аспекты, пишите в комментариях.
Возможно, я расскажу вам в отдельной статье.
Если, конечно, это необходимо.
ППС: Пользуясь случаем, скажу, что сейчас мы хотим найти в команду несколько компетентных людей (программист, ПМ, СМ, художник).
Подробности на сайте студии.
Надеюсь, этой фразой я не нарушил правила.
Теги: #Разработка игр #unity #шейдеры # картографирование нормалей #graveyard keeper
-
Вышла Новая Версия Ietester V0.4
19 Oct, 24 -
Intel Nuc 11 Extreme — Микро-Пк На Стероидах
19 Oct, 24 -
Drupal И Альфа-Банк Вместе
19 Oct, 24 -
Sprint Driver - Почувствуй Силу Скорости
19 Oct, 24