Как мы делаем World of Warships: автоматизация экспорта и верификация контента
После премьерных закрытых показов World of Warships на gamescom и «ИгроМире» официальный запуск игры все ближе и ближе. Сейчас в разгаре закрытое альфа-тестирование, и нам, разработчикам Lesta Studio, питерского подразделения Wargaming, еще предстоит решить целую кучу вопросов. При этом немало препятствий все-таки удалось оставить позади. Ниже — рассказ о том, как мы адаптировали экспортер нашего движка под нужды «Кораблей» и выстраивали процесс верификации контента.
Стандартная поставка движкаЛюбой движок включает в комплект поставки инструментарий для экспортера 3D-моделей из 3D-редакторов в свой собственный формат данных. Наш Bigworld, на основе которого сделан и World of Tanks, не является исключением. Он поддерживает экспорт из 3D-Max и Maya. Практически любой игровой проект требует адаптации стандартных экспортеров под специфику проекта. В нашем проекте спецификой являются модели кораблей.Первая версия адаптированного экспортера из Maya просто «дообучила» его распознавать более сложную структуру сцены кораблей. К существовавшему C++ коду добавилось немного управляющего кода на Python, а также плагин для Maya с UI на wxWidget. Выглядело это примерно так:
UI адаптированного экспортера
Получившийся инструмент обладал массой недостатков.
Экспорт можно было осуществлять только с участием пользователя, который должен был «сказать» экспортеру, что содержит сцена. Об использовании данного инструмента в автоматизации различных процессов, например, автоматической верификации контента на этапе сборки дистрибутива, не могло быть и речи.
Экспортер требовал от пользователя знаний о далеко не очевидных параметрах, медленно работал, практически не поддерживал верификацию сцены, а также требовал огромное количество ресурсов на поддержку.
Архитектура являлась основной проблемой для расширения функциональности в будущем. Экспорт являлся фактически атомарной операцией (набор спагетти-функций), которая транслировала данные из одной структуры (загруженной сцены Maya) в другую структуру (Bigworld) напрямую в физические файлы. Когда сериализаторы и бизнес-логика реализованы «в монолите», а модель данных просто отсутствует, то невозможно добавлять обработку данных (pre/post-processing), а также повторно использовать (code reuse) сериализаторы и модель данных в других инструментах, реализующих собственную бизнес-логику. Строить более сложные процессы производства контента было невозможно.
Со временем наращивать новую функциональность в существующем коде стало практически невозможно. Было принято решение переписать экспортер «с нуля», заложив в него новую архитектуру.
Суровые будни Уровень нашего проекта повысил требования к качеству, сложности и объему контента. За последние пару лет наша студия сильно выросла. У нас появились возможность выделять достаточное количество ресурсов на задачи, связанные с производством контента. К нам пришли профессионалы, имеющие большой бэкграунд в разработке архитектуры, технологиях на C++/C#. При этом для разработчиков экспортера это был первый опыт использования Python и Maya API. Это внесло дополнительные риски, которые требовалось учитывать.Рефакторинг экспортера мы оценили в два-три человеко-месяца. Без оптимизма в геймдеве никак нельзя.
К рискам мы отнесли:
• отсутствие формальных требований• уровень владения Python• сложность Maya API• рефакторинг алгоритмов обработки примитивов
Много фактического времени ушло на сбор требований из неформализованных источников, таких как разработчики, ставшие менеджерами, «старожилы», торсионные поля и код существовавшего экспортера. Эти крупицы знаний были формализированы и записаны в виде требований, спецификаций и UML-диаграмм в Confluence.
Первые прототипы показали необходимость использования концепции namespaces и модулей Python (__init__.py). Также был проработан механизм, позволяющий «прозрачно» использовать функциональность из C++ библиотек (.pyd).
О сложности и запутанности Maya API можно написать отдельную книгу. Любая функциональность требовала прототипирования, консультаций с 3D-художниками и с разработчиками движка (rendering).
В стандартном экспортере была собственная реализация большого количества алгоритмов, например, триангуляция полигонов, расчет матриц трансформаций вложенных узлов и т.д. Мы отказались от них в пользу использования Maya API, что сильно повысило производительность экспортера.
К законам Мерфи давно пора дописать правило, что любой задуманный вами проект обязательно будет реализован за время не более чем «x3» от запланированного, если вы его не бросите.
Результат стоил приложенных нами усилий. В конце концов, даже наш главный художник, отвечающий за экспорт моделей, после пары месяцев эксплуатации нашел наш экспортер «почти идеальным».
Заглянем под капот В нашей студии активно используются скрипты на Python. Мы пытались реализовать на нем и весь экспортер. Естественно, Python не подходит для обработки больших бинарных данных — таких, как контейнеры вершин (vertex buffer), контейнеры индексов вершин (index buffer) и т.д. Модель данных и сериализаторы подобных контейнеров были реализованы на C++ в виде библиотеки (.pyd), которая естественным образом «вписались» в модель данных на Python. Вся бизнес-логика была реализована на Python.Фреймворк экспортера планировалось применять не только для задачи «ручного» экспорта из Maya, но и для любых задач, где его функциональность можно было бы повторно использовать, например, для автоматизации верификации контента. От любого разрабатываемого инструментария мы требуем наличие интерфейсов (API) для Python, командной строки (command line) и UI инструментов.
Архитектура Архитектура фреймворка экспортера модульная, послойная. Существуют физический и логический слои, а также слой предметной области. Каждый слой содержит отдельные модули: модель данных, бизнес-логика, сериализаторы, а также конверторы, умеющие преобразовывать модель данных одного слоя в модель данных другого слоя. Физический и логический слои фактически реализуют аналог ORM-архитектуры.Архитектура слоя предметной области спроектирована для удобной обработки модели данных бизнес-логикой. Она полностью изолирована и не содержит никаких предположений о том, каким образом она будет сериализована в физическое хранилище.
Послойная архитектура экспортера
Процесс экспорта Послойная архитектура вносит определенные особенности процесса экспорта. Фактически мы десериализуем две (или более) моделей из различных источников (Maya и BigWorld Engine). После этого происходит объединение (merge) этих моделей в одну новую. Далее новая модель сериализуется в BigWorld-Engine-формат.Процесс экспорта
Гибкость процесса производства контента Реализованная архитектура позволяет достаточно просто выстраивать сложные процессы производства контента. Например, первичная модель корабля у нас технологически состоит из трех отдельных сцен Maya, каждую из которых одновременно разрабатывают разные отделы: • Первая сцена содержит визуальную модель (visual model) и модель коллизий (collision model).• Вторая сцена содержит баллистическую модель (ballistic model).• Третья содержит порты эффектов (effects ports).
Вдобавок к этому инструментарий движка (редакторы) добавляет (редактирует) собственные данные в производной модели формата движка (четвертая сцена).
Экспортер с легкостью решает нетривиальную задачу объединения всех четыре сцен в одну результирующую модель корабля.
Верификация контента Система верификации контента позволяет нам искать ошибки контента как в каждом слое (источнике) по-отдельности, так и в результирующем контенте. Число верификаторов сейчас достигает нескольких десятков. Автоматическая верификация контента встроена в процесс сборки дистрибутива (build), что позволяет максимально исключить человеческий фактор и гарантировать целостность и техническую чистоту контента.Пример верификации модели корабля в Maya
Бюджеты контента и уточка в ванной Важной составляющей процесса верификации контента является проверка бюджетов, например, верификация полигонажных бюджетов. На рисунке ниже отображена, в частности, информация о количестве треугольников для визуальной модели по каждому лоду: UI-плагина Maya
Яркой иллюстрацией необходимости такой верификации служит байка, рассказанная мне коллегами об одном из предыдущих проектов. На карте был участок, застроенный не разрушаемыми домиками. Как только камера обращала свой взор на этот участок, то FPS сразу же дико падал. После изучения проблемы выяснилось, что внутри одного из домиков стояла ванна, в которой плавала маленькая «пластиковая» уточка. Все это выглядело бы забавной шалостью художников, если бы не то обстоятельство, что модель уточки содержала около миллиона полигонов.
На практике очень трудно соблюдать бюджетное значение. Множество моделей объективно являются исключениями. Задание бюджетного значения в виде диапазона также не решает проблему, так как со временем полигонаж моделей просто начинает стремиться к верхнему значению диапазона. В нашем случае, мы планируем изменять персональные бюджеты тех моделей, которые не соответствуют стандартному бюджету данного типа моделей.
Обработка контента На каждом этапе экспорта требуется производить обработку (pre/post-processing). Например, перед конвертацией логической модели данных слоя Maya в модель данных предметной области для пушек ПВО требуется предварительное вращение скелета пушки на 45 градусов по оси Y и удаление скелета. Наша архитектура позволила прозрачно встраивать различные обработки на любом этапе экспорта.Пример модели до и после pre-processing
Поддержка x64 Достаточно недавно наши художники в массовом порядке перешли с 32-битной Maya 2012 на 64-битную Maya 2014. Так как экспортер почти полностью написан на Python, у нас практически не возникло проблем с поддержкой x64. Лишь библиотека (.pyd), реализованная на C++, потребовала небольшого «шаманства».Сейчас экспортер можно легко использовать как в x32, так и в x64 процессах, поскольку он сам определяет и подгружает требуемую сборку C++ библиотеки (.pyd)
Верификация карт Разрабатывая архитектуру экспортера, мы не могли предположить заранее, в каких еще инструментах и автоматизациях удастся его повторно использовать. Автоматизация верификации карт является примером того, как «правильная» архитектура экспортера нашла свое применение в другом инструменте.Верификация карт строит и верифицирует граф зависимостей карты от других объектов, расположенных на ней. В частности, на карте используются визуальные модели ландшафта (камни, айсберги), строений (домики, ангары, пристани), техники (самолеты, лодки) и т.д.
Особенность верификатора карт заключается в том, что он может верифицировать не просто наличие файлов этих визуальных моделей, но и сами модели, используя фреймворк экспортера. Это позволило исключить человеческий фактор, когда отделу разработки карт (LA) приходится «верить на слово» отделу разработки 3D-моделей (3D-Art), что используются технически корректные модели.
Сборка дистрибутива Фреймворк экспортера нашел свое применение и в процессе подготовки пакета контента (content pack) для дистрибутива. В дистрибутив не должны попасть модели, которые: • уже не используются; • находятся еще на стадии разработки; • предназначены для последующих версий продукта.
По базовому списку игровых объектов (root game objects) требуется построить граф зависимостей, по которому будет сформирован полный список требуемого контента. Нет ничего проще, чем десериализовать модель при помощи фреймворка экспортера и «узнать», какие еще модели потребуются (content references).
Итоги История разработки нашего экспортера показала, как из простого узкоспециализированного инструмента он эволюционировал в мощную систему, решающую свои непосредственные задачи, а также нашел применение в других процессах производства контента. Основой его успешного развития и повторного использования является модульная архитектура, позволяющая использовать его отдельные «кубики» для построения других систем.В ближайшем будущем экспортеру предстоит еще одно испытание, связанное со сменой формата файлов Bigworld Engine. Мы уверены, что заложенная архитектура не испытает никаких трудностей и сможет поддерживать работу как с существующим, так и с новым форматом файлов.