Как рендерится кадр в Shadow Fight 3



    Технический 3D-художник Banzai Games Роман Терский рассказал о том, как происходит отрисовка кадра и устроены материалы для персонажей в мобильной игре Shadow Fight 3, а также раскрыл небольшие хитрости в настройке окружения

    Shadow Fight 3 — игра в жанре файтинг/РПГ, разработанная на базе движка Unity3d. Релиз проекта состоялся на iOS/Android в ноябре 2017 года, и с тех пор суммарное количество установок игры превысило 80 млн. Для охвата столь широкой аудитории командой разработки была выполнена большая оптимизация игры, и в результате проект работает при 60 FPS на многих современных устройствах со средней производительностью.

    Критики и игроки часто отмечают визуальную составляющую Shadow Fight 3. В этой статье мы предлагаем вам заглянуть “под капот” игры и узнать, как нам удалось достичь такого качества.

    Рендер кадра


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

    Во время рендера кадра игры для каждой статической группы объектов, объединенных одним материалом, Unity запускает вызовы отрисовки (Draw Call) и накладывает их друг на друга. Каждый Draw Call требует затрат ресурсов CPU, поэтому важным этапом оптимизации является уменьшение количества этих вызовов. Нашей целью было минимизировать этот показатель до 100 вызовов на каждый кадр игры в среднем.


    Процесс рендера одного кадра

    Первым этапом рендеринга в Shadow Fight 3 является отрисовка динамических теней персонажей и Glow-эффектов для светящихся элементов на доспехах и оружии игроков.



    Оба этих процесса имеют свои особенности и их стоит разобрать подробней.

    Тени


    Помимо основной камеры, на которую рендерится основной кадр, на сцене установлена дополнительная ортографическая камера-проектор, призванная отрисовывать тени от персонажей на отдельную поверхность с названием ShadowReciever. Эта камера следует за средней точкой между оппонентами и каждый кадр создает их проекцию на плоскость с зависимостью от их текущего положения. Результат отрисовывается в виде альфа-текстуры, которая заменяет текстуру с рендером предыдущего кадра в динамическом материале объекта ShadowReciever. Такой подход позволяет избежать необходимости рассчитывать реальные тени и отрисовывать их на всех моделях локации, что заметно сказалось бы на общей производительности.


    Область ShadowReciever

    В рассматриваемом кадре на этот процесс ушло 20 вызовов отрисовки.

    Glow


    Процесс создания эффекта свечения на доспехах и оружии персонажей схож с процессом создания динамических теней. Вокруг модели со светящимися элементами создается куб BlurCube, на который каждый кадр проецируются Glow-эффекты, исходя из информации, хранящейся в синем канале RGB текстуры материала этого объекта (т.е. синий канал выступает в роли “маски” для проекции свечения — подробнее об этом ниже, в разделе про материалы). Затем применяется размытие и информация сохраняется в виде альфа-текстуры, которая заменяет текстуру с результатом рендера предыдущего кадра в динамическом материале BlurCube’а.


    BlurCube

    В нашем кадре на этот процесс ушло 15 вызовов отрисовки + еще 2 на размытие эффекта.

    Отрисовка мешей


    В первую очередь по отдельности отрисовываются части доспехов, оружие персонажей, далее части локации ближнего плана, затем дальнего, а также задний фон, представляющий из себя плоскость с текстурой 1024х512. Следом отрисовываются системы частиц, мелкие детали ближнего и дальнего плана и, наконец, модели с вертексной анимацией (об этом ниже). В конце за 2 вызова применяются рассчитанные и отрисованные ранее тени и эффекты свечения (Glow).

    UI


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


    Результат рендера основной камеры


    Результат рендера UI камеры


    Результат рендера финального кадра

    В сумме на рендер финального кадра игры потребовалось 92 вызова отрисовки.

    Как устроен материал доспеха персонажа


    Для создания материала доспеха персонажа используются текстуры с разрешением 512х512: Diffuse (1), RGB-маски (2), MatCap (3), дополнительная Diffuse карта для теневой формы (4), а также небольшая шумовая текстура MorphMask (5), используемая для создания эффекта перехода персонажа в теневую форму.



    И если с Diffuse-картой все стандартно (это просто текстура самого доспеха), на остальных остановимся поподробней:

    RGB-текстура масок


    Так как RGB-текстура условно состоит из трех цветовых каналов, заданных числами от 0 до 1 для каждого пикселя, её удобно использовать для хранения различных данных о материале в каждой конкретной точке UV-развёртки объекта.

    В нашем случае в каналах RGB-текстуры (маски) содержится информация для следующих процессов:

    • Red (красный канал) указывает на то, какие элементы материала будут менять свой цвет, в случае если в бою участвуют противники в одинаковых доспехах (мы пользуемся этой системой, чтобы игрок не путал своего персонажа с оппонентом; определенные части доспеха, заданные в канале Red, перекрашивается для оппонента в альтернативный цвет, который был задан художником отдельно);
    • Green (зеленый канал) призван указать, к каким элементам доспеха применяется текстура MatCap для придания эффекта металлической поверхности, а также силу воздействия этого эффекта (чем светлее, тем сильнее металлический блеск);
    • Blue (синий канал) содержит в себе информацию, к каким деталям будет применен Glow, создающий эффект светящейся поверхности.


    MatCap



    MatCap текстура                      Зеленый канал RGB текстуры


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

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


    До применения MatCap                 После применения MatCap


    Теневая форма


    При переходе персонажа в теневую форму Diffuse текстура материала заменяется дополнительной, созданной специально для теневой формы.

    Для плавного перехода от одной текстуры к другой используется шумовая Morph-маска, с помощью которой достигается эффект постепенного замещения:



    Освещение локаций


    Все освещение и тени на локации запечены в lightmap-текстуры с разрешением 2048х2048, что позволяет исключить необходимость рассчитывать освещение в реальном времени и существенно увеличивает производительность.



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

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


    Карта shadowing map


    Освещение персонажей в затененной части локации


    Освещение персонажей в открытой части локации

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



    Динамические эффекты арен


    Немаловажную роль в “оживлении” локаций Shadow Fight 3 играют FX-эффекты и динамические объекты, такие как флаги, шевелящаяся листва на деревьях, колышущаяся трава и т.д.



    FX


    Большая часть FX-эффектов (огонь, дождь, солнечные лучи и пр.) в SF3 выполнены по принципу применения анимированного материала к статическим низкополигональным моделям. Однако есть и эффекты, построенные на системе частиц.

    Динамические объекты


    На локациях SF3 есть два типа динамических объектов: физические — приводимые в движение посредством симуляции ткани и применения к ним импульса, имитирующего порывы ветра, а также 3d-модели с вертексной анимацией. Для таких объектов создается зацикленный анимационный трек, приводящий в движение вертексы 3d модели.


    Вертексная анимация листвы           Симуляция ткани на флагах


    Отражения


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

    Для решения вопросов отражения с максимальной производительностью на аренах, где есть отражающие поверхности (мраморный пол, вода и пр.), те элементы, которые должны отражаться, были продублированы, а их размер по оси Z выставлен в отрицательное значение. Позиция дубликата выставлена так, чтобы со стороны оба объекта выглядели как отражение друг друга. Материал отражающих поверхностей имеет полупрозрачность, сила которой зависит от характера поверхности. В случае если отражаемый объект находится на достаточном отдалении и детализация отходит на второй план, вместо дубликата устанавливается Plane с текстурой на основе отзеркалированного по оси Z скриншота отражаемой поверхности. Такой подход не только повышает производительность игры, но и дает очень реалистичный результат.


    Финальный результат                  Без пола


    Заключение


    Вопрос оптимизации рендера под мобильные устройства сейчас актуален как никогда. То, что вы увидели в данной статье, — это проработанные нами решения конкретно под проект Shadow Fight 3. В настоящее время компания Banzai Games начала разрабатывать две новых игры, в которых мы постараемся сделать графику еще лучше, применив как текущие наработки, так и добавив что-то новое.

    В команду Banzai Games требуется Graphics Developer. Подробнее о вакансии можно прочитать здесь.
    Banzai Games
    60,89
    Компания
    Поделиться публикацией

    Комментарии 4

      +1
      Было бы хорошо, если бы между раундами была какая-нибудь перебивка, перекрывающая камеру локации, потому что простое перемещение к центру локации с исчезновением и появлением персонажей оставляют опустошенное чувство, как-будто игру не доделали. А в остальном интересно наблюдать, как игра эволюционирует в графике и геймплее.
        0
        Такой подход позволяет избежать необходимости рассчитывать реальные тени и отрисовывать их на всех моделях локации, что заметно сказалось бы на общей производительности.
        Судя по картинке — лайтмапы сами по себе, а фейковая тень — сама по себе. А объединить их как-нибудь нельзя хотя бы только на полу? Тень в тени всегда немного странно смотрится.
          0
          Наверное, можно было бы хранить маску тени от солнца в альфа-канале лайтмапы и накладывать тени от персонажей в соответствии с ней. Еще лучше было бы сделать более размытую копию фейковой тени и накладывать её там, где на лайтмапе тень. Эдакая имитация АО.
            0
            Интересное замечание. Теоретически, элементы окружения, отбрасывающие тень на пол, можно сделать динамическими, но, в таком случае, тени станут менее детализированными, чем запеченные. Либо обрезать по лайтмапе область фейковых теней, либо блендить фейковую тень с запеченной… есть о чем подумать :)

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое