Создание анимации воды в игре Vikings: War of Clans

В студиях компании Plarium существует негласное правило: каждый следующий проект должен быть лучше предыдущего. Оно мотивирует нас на постоянное развитие и стремление выйти за рамки своих возможностей, совершенствуя графику, геймплей и внедряя новые технологии в производство игр. Еще на ранних этапах разработки Vikings: War of Clans мы поставили себе высокую планку в работе над всеми элементами проекта, включая внутреннюю карту города, которая была детально прорисована и дополнена яркой анимацией. При дизайне карты мы вдохновлялись красотой скандинавского побережья и невообразимым количеством водопадов Норвегии, так как должны были передать атмосферу эпохи викингов в игре. Именно благодаря чудесным пейзажам этого уголка планеты на карте появились морской залив с лазурной водой и каскад бурлящих водопадов. Однако мы не хотели довольствоваться лишь статичной картинкой водных пространств, а желали сделать ее живой и динамичной, добавив анимацию. В рамках мобильной разработки при ограниченных технических возможностях это было непросто, но нам удалось справиться. В статье мы расскажем о методах создания анимации, которые помогли воплотить наши идеи в жизнь.



Анимация морского залива

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

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

Мы решили пойти другим путем и сделать анимацию на плоском, простом меше с движением текстур по UV-координатам. С точки зрения производительности метод оказался эффективным, но по визуальной части оставлял желать лучшего. Тогда возникла идея использовать карты normal, что позволило получить объемные блики на воде. Этот результат нам понравился гораздо больше предыдущего: мы получили материал, с которым можно было продолжить работу, и приступили к детальной прорисовке моря в статичном виде, а также к описанию его динамического варианта. На данном этапе мы также определились с главным визуальным эффектом для создания реалистичного моря, который подсмотрели у природы. Внимательно понаблюдав за морским побережьем, можно заметить, что “глубокая” вода имеет темный насыщенный цвет, глядя в нее, видишь плотную синеву и ничего больше. “Мелкая” же вода прозрачна, сквозь нее можно различить дно водоема и береговую линию, поэтому мелководье несет в себе их цветовой оттенок. Эти особенности мы и хотели передать на карте, решив разделить залив на глубину и мелководье.

Для получения задуманного эффекта были настроены блики через карту normal, а также написан шейдер с двумя масками для “глубокой” и “мелкой” воды. Далее мы прошли через долгий процесс оптимизации шейдера и тестирования на мобильных девайсах, чтобы убедиться в корректном отображении анимации. Финальный результат превзошел все наши ожидания: морской залив с небольшой рябью, словно от дуновения легкого бриза, получился по-настоящему реалистичным.


Анимация рек и водопадов

Помимо морского залива на карте следовало расположить реки с водопадами, которые также нужно было оживить. Для их анимации мы использовали шейдер с движением текстуры по UV-координатам с режимом наложения additiv. Речной поток был прорисован на статичной подложке, а эффект струящейся воды получился за счет движения текстуры воды в шейдере.

Описание работы шейдера

Движение текстуры осуществляется по направлению V-координаты от 1 до 0, поэтому вся развертка меша лежит так, чтобы вода текла в одном направлении. Для изменения движения потока воды в реке в соответствии с положением на карте мы двигали точки самого меша, задавая им нужное направление. Однако нам нужно было реализовать плавный переход реки в водопад, ведь в реальной жизни это единая водная масса, которая течет с разной скоростью. Этот процесс мы решили обыграть по схожему принципу. По сути, это тот же самый шейдер, а в некоторых случаях — тот же меш, только в раскладке UV-координат поток реки выполнен более растянутым маппингом, а для водопада — более сжатым. В итоге при одной скорости движения текстуры по UV-координатам у нас получилась разная скорость движения текстуры по мешу. Визуально на водопадах текстура более растянута, но и этот эффект выглядит интересно, так как напоминает стремящийся вниз поток воды.


Три способа скрыть края меша

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

Скрыть края меша можно тремя способами:

- Использовать альфа-канал, записанный в точках меша (alpha vertex). Этот способ не совсем удобен из-за того, что пришлось бы делать более тяжелый меш с большим количеством дополнительных точек.

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

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

Принцип создания процедурной маски в нашем шейдере отображен в формуле

saturate(2 - U)*saturate(1 + U)*saturate(2 - V)*saturate(1 + V)где:

saturate(2 - U) — градиент справа (значения больше 1 по U);

saturate(1 + U) — градиент слева (значения меньше 0 по U);

saturate(2 - V) — градиент сверху (значения больше 1 по V);

saturate(1 + V) — градиент снизу (значения меньше 0 по V).




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

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


821 0 850 47
0
RENDER.RU