Тестирование игрового движка Amazon Lumberyard. Подходы и инструменты
Amazon. Игры. Звучит необычно? Как тестировать продукт и для разработчиков, и для геймеров? Под катом — тестирование игрового движка Amazon Lumberyard, подходы как в ручном тестировании, так и в автоматизации, а также используемые на проекте инструменты.
Lumberyard — это кроссплатформенный игровой движок, на котором можно бесплатно создавать игры для большинства современных платформ: PC, Mac, iOS/Android, все приставки, в том числе очки виртуальной реальности. Он также довольно глубоко интегрирован с Amazon Web Services и сервисом игровых трансляций Twitch.
Под катом — видео и расшифровка доклада Артема Несиоловского с конференции Heisenbug 2019 Moscow.
О спикере: окончил МИФИ, факультет Кибернетики, более 8 лет в разработке и тестировании. Поработал как на десктопных проектах, вроде GeForce Experience, онлайновой MMORPG Lineage II, так и в мобильных — игра Cut the Rope, а также в веб-проекте Yandex.Images. В данный момент является инженером по автоматизации в компании Amazon на проекте Amazon Lumberyard.
Структура поста
- Игровой движок: особенности, а также отличия тестирования движка от тестирования игр.
- Ручное тестирование: как мы пытались выяснить покрытие фичей проекта функциональными тестами.
- Автоматизация: ошибки и шишки, которые мы набили и лечили впоследствии.
- Инструменты, при помощи которых мы автоматизируем наш движок.
- Интересные баги с нашего проекта, которые вы наверняка встречали, когда сами играли в игры.
Далее повествование от лица спикера.
Почему вообще Amazon занимается играми? В 2014 году Amazon, как и многие технические гиганты, замечает, что игры становятся вторым по популярности видом развлечения у человечества. Первый, как ни странно, — это телевидение, а точнее, всё, что касается видеостриминга (YouTube, Netflix и всё остальное). Также игростроители начинают активнее пользоваться сервисами AWS для своих онлайн-игр.
Amazon решает построить экосистему на трех китах: открыть свою игровую студию для создания игр, которые люди потом будут стримить и смотреть на Twitch. Также эти игры будут показывать, какие интересные геймплейные идеи можно воплотить, используя клауд AWS.
С чего все начиналось?
В 2004 году немецкая компания Crytek выпускает игру под названием «FarCry». Через какое-то время Crytek начинает лицензировать свой движок, на котором была построена игра, чтобы сторонние компании могли взять готовый движок и начать создавать игру, геймплей, наполнить её контентом без больших инвестиций в технологию. Когда Amazon начал заниматься играми, он также сразу открыл несколько студий и стал разрабатывать несколько игр.
Чтобы каждая студия не изобретала велосипед — свой рендер-движок, свою анимационную систему, физику и так далее, Amazon лицензирует «CryEngine» версии 3 и запускает разработку сразу нескольких игр. Игра «The Grand Tour» уже вышла на приставках Xbox и PlayStation. Ещё две находятся в разработке: MMORPG «New World» и онлайновый шутер «Crucible». После того как запустилась разработка этих игр, Amazon начинает бесплатно предоставлять движок, на котором эти игры разрабатываются. Поскольку он сильно интегрирован с облачными сервисами Amazon, можно привлечь больше людей использовать AWS.
Игровой движок — это набор API, игровой двигатель для построения будущей игры. Чтобы разработчикам не нужно было писать свои игровые системы, можно просто взять набор API, т.е. движок, и начать писать свою игровую логику, добавлять туда контент и заниматься творчеством, вместо того чтобы разрабатывать технологию с нуля. Также у некоторых движков есть редактор. Это десктопная программа, в которой можно создавать уровни, то есть открывать свой левел и добавлять туда контент и игровую логику.
Вместо того чтобы долго рассказывать, иногда проще показать одно видео:
Ссылка на видео 8:33–9:53
Здесь показан наш редактор и его интерфейс. Внутри него запущена игра, которую мы предоставляем вместе с движком. «Starter Game» существует для того, чтобы люди могли зайти, поиграть, что-то поменять и разобраться, как это работает.
В целом 3D игры можно себе представить как набор трехмерных объектов, которые перемещаются в трехмерном мире и как-то взаимодействуют между собой. В данном видео можно увидеть:
- статическую геометрию с текстурами: земля, камни, трава, деревья;
- динамическую геометрию — персонаж анимирован, реагирует на действия игрока;
- пользовательский интерфейс: в верхнем левом углу виды задачи.
Игрок может встретиться с враждебными персонажами, проявится игровая логика, можно будет пострелять — роботы стреляют в ответ. О физике: персонаж начнет стрелять по бочкам, они будут перемещаться от столкновения с выстрелами и от взаимодействия с персонажем. В редакторе в любой момент можно выйти из игрового режима и попасть обратно в режим редактирования, в котором можно сразу же изменить свойства объектов, переместить их, и это сразу же отобразится на игровом процессе. Представили себе примерное количество мест, где что-то может пойти не так, сломаться и перестать правильно работать?
Как тестировать движок?
Тестирование движка строится на трех основных пунктах. Первое — это тестирование редактора и инструментов: корректная работа, инструменты должны открываться, ничего не крашиться, всё должно правильно отображаться, пользовательские сценарии должны выполняться без ошибок, процесс создания игры без сопутствующих багов. Редактором будут пользоваться только создатели игр. Второе — это тестирование самого двигателя или API движка. Игровой движок в свою очередь это та часть кода, которая будет работать в том числе и на компьютерах игроков. Данная часть проекта тестируется через заблаговременное создание уровней и игр. Впоследствии созданные уровни можно тестировать на каждом новом билде движка, чтобы удостовериться, что все игровые элементы использованные на том или ином уровне работают как надо. И третья составляющая — это тестирование инфраструктуры и совместимости: движок можно сконфигурировать и сделать build с разными параметрами, игру можно задеплоить на различные девайсы, и она везде будет выглядеть и работать примерно одинаково.
Особенности проекта
Первая особенность — мы поддерживаем большинство существующих игровых платформ. Несмотря на то что редактор сам работает только на PC, runtime, т.е. игру можно сбилдить на Mac, смартфоны, консоли и даже очки виртуальной реальности.
Вторая особенность — наши пользователи — это два типа людей с абсолютно разными запросами. С одной стороны, это разработчики, программисты, художники и дизайнеры, которые будут работать над созданием игры. А с другой стороны, это геймеры, на машинах которых игра потом будет работать. Требования у этих двух групп совершенно разные.
Третья особенность — в таких программах, позволяющих создавать что-то новое, заранее подразумевается максимально широкий спектр возможных продуктов этого приложения. На нашем движке можно построить абсолютно любую игру, начиная от чего-то простого, вроде тетриса, и заканчивая сложным онлайновым проектом, в который играет тысячи людей одновременно.
Все эти три особенности очень сильно влияют на количество пользовательских сценарием, каждый из которых необходимо тестировать.
Посмотрите на этот скриншот и представьте, сколько тест-кейсов вы могли бы написать просто на данную часть функционала? Всего у нас на проекте больше 11 тысяч тест-кейсов и эта база данных растет примерно на 3–4 тысячи тест-кейсов каждый год.
Ссылка на видео 13:20–13:54
Большинство багов мы находим во время взаимодействия нескольких компонентов между собой. На этом видео снег в нормальном состоянии отображается на кубике как положено, но стоит только персонажу начать с ним взаимодействовать, снег начинает пропадать. Большинство багов мы находим именно в таких местах сочленения нескольких компонентов.
Ссылка на видео 14:08–14:41
Однако баги не всегда проявляются, когда условий только два. Часто бывает так, что баги проявляются, когда сходятся сразу несколько компонентов. В данном случае мы рассматриваем баг, в котором в нормальной ситуации персонаж просто стоит на земле. Стоит добавить ещё одну степень свободы — поднять персонажа над землей: когда он упадет, начнет проигрываться анимация и приближаться/удаляться камера — текстура начинает пропадать. Здесь взаимодействуют сразу три компонента: высота, анимация персонажа и расстояние камеры. Продумать все эти варианты заранее невозможно, и часто такие баги мы находим только во время ad-hoc тестирования.
Ссылка на видео 15:02–15:49
Есть еще одна особенность — у нас много недетерминированных систем. Это системы, в которых, при одинаковых входных данных, итоговый результат может отличаться. Простой пример — в системе есть случайные переменные. В нашем случае это системы физики, в которых много вычислений с числами с плавающей точкой. Floating point operations на разных процессорах или компиляторах могут выполняться немного по-разному. Из-за этого результирующая функциональность будет всегда немного отличаться. В итоге такие системы довольно сложно автоматизировать, потому что сложно объяснить машине, в каком случае это баг, а в каком случае это приемлемые отличия.
Ссылка на видео 16:03–17:14
В движке и в самом редакторе довольно много нетривиальных взаимодействий. Пользователи часто взаимодействуют внутри трехмерного пространства при помощи мышки и клавиатуры. На данном видео будет изображена фича под названием Simulated object. Вещи, одетые на персонажа должны двигаться согласно законам физики при движении персонажа, на которые эти предметы надеты. Например, одежда или портфель. В качестве такого элемента на видео — рука персонажа. Когда персонаж двигается, рука тоже начинает реагировать. Зачастую, чтобы протестировать такой функционал, нужно делать нетривиальные действия: переключать что-то в UI, двигать объекты в трехмерном пространстве, делать drag-and-drop, также смотреть на анимационные графы, которые расположены снизу, и делать всё в режиме реального времени. Эта особенность влияет на сложность автоматизации.
Как определить покрытие?
В какой-то момент мы поняли, что мы написали очень много тест-кейсов, но определить, какое у нас покрытие, было сложно. Мы находили большинство критических багов не во время нашего полного регрессионного теста, а во время ad-hoc тестирования, которое проводилось в конце релизного цикла. Мы начали думать: у нас есть движок с великим множеством функционала, есть репозиторий, в котором 12 000 кейсов — как понять, в каких местах покрытие достаточно, а в каких стоило бы добавить тест-кейсов?
Мы обратились к теории тестирования, стали читать про то, как люди определяют тестовое покрытие. Один из способов — это определение через исходный код. В нашем случае сделать это сложно. У нас несколько миллионов строк кода и выполнить данную проверку в сжатые сроки оказалось невозможным. Второй метод — оценить покрытие через оценку требований. В agile-процессах требования зачастую хранятся только в голове у людей, а не в документации, поэтому через требования сделать оценку покрытия тоже оказалось не реалистично. В итоге мы обратились к единственному для нас возможному способу — это определение покрытия через написание модели.
Мы выбрали модель под названием ACC — Attribute, Component, Capability. АСС это одна из самых простых моделей, которая довольно распространена в Amazon для моделирования работы софта. Модель строится на трех основных столпах. Во-первых, это компоненты, существительные — основные рабочие части системы. Для нас это viewport, текстура, игровая сущность. Далее следуют capabilities — глаголы — то, что эти компоненты умеют делать. Например, они умеют отображаться на экране, что-то вычислять, что-то двигать и так далее. И третья часть — это атрибуты — прилагательные или наречия, относящиеся как к компонентам, так и к их возможностям. Атрибуты описывают параметры возможностей: быстрый, секьюрный, скалирующийся, безопасный и так далее. Всё это можно свести к трем вопросам: кто? что делает? и как?
Разберем данную модель на небольшом примере. Ниже демка небольшой части функциональности:
Ccылка на видео 19:59–21:02
Viewport — часть редактора, в которой виден уровень. На видео продемонстрировано, что в нем можно вращать камеру, перемещаться по уровню, есть возможность добавить персонажа из местного проводника игровых объектов. Персонажа можно подвигать, или создать новую игровую сущность через правый клик, можно выделить все текущие сущности на уровне и передвинуть их все вместе. Также можно добавить другой геометрический элемент и (как во всех трехмерных редакторах) поменять не только его положение в пространстве, но также менять угол наклона его и изменить размер. У окошка под названием «Viewport» есть разные режимы рендеринга. Например, отключаются тени, или отключаются какие-то графические эффекты пост-процессинга. Можно войти в игровой режим, чтобы сразу же протестировать только что сделанные изменения.
Посмотрим на саму ACC модель. Мы быстро поняли, что эти модели очень удобно делать при помощи Mindmaps, а потом уже транслировать либо в таблички, либо прямо в структуру в TestRail или в любой другой репозиторий для тест-кейсов. На диаграмме в центре виден сам основной компонент — Viewport — и дальше сверху красная ветка — возможность Viewport, позволяющая перемещаться по уровню: можно вращать камеру, можно летать при помощи кнопок «W», «A», «S», «D».
Вторая его возможность (оранжевая ветка) — создавать игровые сущности либо через Viewport, либо через drag-n-drop из игрового проводника.
И третья — игровыми сущностями можно манипулировать: их можно выделять, менять их местоположение, вращать и так далее. Зеленая ветка слева — это конфигурация Viewport при переключении режимов рендеринга. Синей веткой выделен атрибут, который говорит о том, что Viewport также должен отвечать определенным параметрам по производительности. Если он будет тормозить, то разработчикам будет сложно что-либо сделать.
Вся древовидная структура потом перекладывается в TestRail. Когда мы перевели тест-кейсы из нашей предыдущей системы в новую структуру, сразу стало понятно, где не хватает тест-кейсов — в некоторых местах появились пустые папки.
Ссылка на видео 23:01–24:10
Эти структуры довольно быстро разрастаются. Viewport на самом деле относится к редактору, который является лишь частью движка. Две основные части: сам редактор и сам игровой движок. Справа на картинке выше можно увидеть несколько компонентов, которые не относятся к дереву. Например, система рендеринга или скриптинга, анимации стоят отдельно, потому что относятся сразу одновременно и к редактору, и к движку. То есть система рендеринга будет работать в runtime на конечных девайсах, но в самом редакторе можно будет изменять некоторые параметры: время дня и ночи, редактирование материалов, система частиц.
Результаты и выводы
ACC моделирование помогло выделить области, в которых страдало покрытые тестами. Заполнив пробелы в покрытии, примерно на 70% сократилось количество багов, находимых после нашего полного регрессионного пасса. Легкие в построении ACC модели, оказались также хорошим источником документации. Новые люди, которые приходили на проект, изучали их и быстро могли получить некоторое представление о движке. Создание/обновление ACC моделей плотно вошло в наш процесс разработки новых фич.
Мы начали автоматизировать движок через автоматизацию пользовательского интерфейса. Интерфейс редактора написан на библиотеке QT. Это библиотека для написания кроссплатформенного UI для десктопных приложений, который может работать и на Mac, и на Windows. Мы использовали инструмент под названием Squish от компании Froglogic, который работает по схожей системе с WebDriver, с поправкой на десктопное окружение. В данном инструменте, используется подход, похожий на Page Object (из мира WebDriver), называется по-другому — Composite Elements Architecture. На основные компоненты (вроде «окошко» или «кнопочка») делаются селекторы и прописываются функции, которые можно выполнять с этими элементами. Например, «нажать правой кнопкой», «левой кнопкой», «сохранить», «закрыть», «выйти». Затем эти элементы складываются в единую структуру, к ним можно обращаться внутри своего скрипта, использовать их, снимать скриншот и сравнивать.
Проблемы и решения
Первая проблема — стабильность. Мы писали тесты, которые тестируют бизнес-логику через пользовательский интерфейс — в чем проблема? Когда бизнес-логика не меняется, а меняется интерфейс — тесты падают, нужно заливать новые скриншоты.
Следующая проблема — отсутствие функциональности. Многие юзкейсы заключаются не просто в нажатии какой-то кнопки, а во взаимодействии с трехмерным миром. Данная библиотека делать этого не позволяла, нужны были новые решения.
Третья проблема — скорость работы. Для любых UI-тестов нужно полноценно рендерить весь движок. Это занимает время, машины для этих тестов должны быть достаточно мощные.
Решение пришло в виде библиотеки Shiboken. Эта библиотека предоставляет биндинги из C++ кода в Python, что дает возможность прямую без рендеринга UI редактора вызывать функции, предоставляемые редактором или движком. Аналог из мира web — Headless automation (что-то похожее на PhantomJS) — можно автоматизировать веб-приложение, не запуская браузер. В данном случае похожая система, только для десктопного приложения, написанного на С++.
Начав вкладываться в данный фреймворк, мы поняли, что его можно использовать не только для автоматизации тестирования, а ещё для автоматизации каких-либо процессов внутри движка. Например, дизайнеру нужно проставить в ряд 100 источников освещения (например, он делает дорогу и нужно поставить фонари). Вместо того, чтобы вручную представлять все эти источники света, просто пишется скрипт, который создает игровую сущность, добавляет туда источник света point light и прописывает, что каждые 10 метров нужно скопировать ранее созданный point light. Бонус для наших пользователей в виде инструмента для автоматизации рутинных задач.
Вторая часть решения проблемы. Мы очень быстро поняли, что для автоматизации различных частей нашего движка, — например, графики и сетевой части — нужны абсолютно разные фреймворки. Невозможно создать единственный, монструозный фреймворк, который поможет автоматизировать сразу всё. Поэтому мы начали разрабатывать фреймворк под названием Lumberyard Test Tools (сокращенно — LyTestTools). Он основывается на Pytest (в движке довольно много всего написано на Python). Мы решили применить так называемый Plug-and-play архитектуру — центральная группа автоматизаторов пишет основную часть фреймворка, который сможет скачивать, конфигурировать движок, деплоить его на различные платформы, запускать тесты и собирать логи, выгружать отчеты в нашу базу данных или на S3 и рисовать графики в Quicksight. Plug-and-play достигается через Test Helper-ы, которые будет писать команды на местах, которые занимается разработкой фич.
То есть команда разработки графики будет тестировать скриншотами, а команда сетевого взаимодействия будет заниматься проверкой пересылаемых пакеты. Все они при этом будут подключаться к нашему единому фреймворку (т.к. обе команды разрабатывают и тестирую модули единого движка), чтобы у всех были одинаковые интерфейсы запуска тестов и генерации отчетов, чтобы всё было более-менее стандартно и корректно работало с нашим CI/CD.
Взаимодействие с Lumberyard
Какие могут быть способы взаимодействия/автоматизации десктопного приложения? Первый тип взаимодействия фреймворка с движком — напрямую из Python процесс запускается при помощи функции Subprocess, если приложение подразумевает запуск через командную строку. Вы можете считывать ввод/вывод из стандартного input/output вывода и таким образом делать ассерты. Следующий тип — это взаимодействие через анализ логов — можно считывать и анализировать логи, оставляемых приложением. Третий — через сеть. В игровых лаунчерах существует модуль, который называется Remote console. Когда на девайсе открыт определенный порт, наш фреймворк может посылать пакеты/определенные команды. Например, взять скриншот или открыть какой-то определенный уровень. Еще один метод — это взаимодействие через сравнение визуальной информации, т.е. скриншотов. Также ранее упоминался метод вызовов функционала приложения напрямую через API продукта (в нашем случае это вызов через Python-bindings к C++ функционалу редактора/движка).
Перейдем к примерам использования нашего фреймворка для автоматизации движка.
Посмотрите на данный скриншот.
Детализация на этом участке довольно высока — большое количество растительности. В современных играх уровни могут занимать до нескольких десятков и сотен игровых километров. Естественно, каждый из этих игровых кустиков не проставляется вручную, иначе разработчики просто сошли бы с ума. Для них в нашем движке есть специальные инструменты.
Один из них называется Vegetation Tool. Небольшое демо:
Ccылка на видео 32:18–34:06
Мы видим стандартное начало уровня. Есть террейн и можно очень быстро сделать рельеф: на заднем плане сделать горы, в центральной части тоже выделить небольшую возвышенность. Можно покрасить саму землю зеленым цветом с текстурой травы. Дальше продемонстрирован процесс добавления растительности, в данном случае — деревьев. В инструмент добавляется геометрия — деревья, — выделяется их подмножество, и можно рисовать этими деревьями любой необходимый рисунок. Это довольно простенький пример, у данного инструмента много настраиваемых параметров. Например, можно выделить не одно дерево, а сразу несколько и задать для них параметр, стоять друг от друга на каком-то определенном расстоянии, или задать случайные параметры для размеров или вращения этих деревьев. Можно добавить игрового персонажа и сразу же побегать в уровне, протестировать, что же вы только что вырастили в вашем собственном игровом саду.
Давайте теперь посмотрим, как мы автоматизировали эту фичу нашим фреймворком на примере пары тестов.
Ссылка на видео 34:20–34:58
Есть стандартный террейн и на нём выращено очень много однотипной травы. Такой тип рендеринга очень сильно нагружает процессор. Если таких элементов очень много, можно сделать нагрузочный тест. Здесь добавлен игровой скрипт, который при запуске игрового режима просто будет делать пролет через данный уровень. Задача — протестировать эту функциональность и проверить, что игровой лаунчер стабилен и не будет крашиться.
Это пример того, как команда, которая разработала фичу для выращивания растительности, написала Test Helper, который позволяет работать с этими функционалом. Это пример использования нашего фреймворка. Зеленым выделен класс launcher. Когда запускается тест, лаунчер деплоится, запускается с параметрами тайм-аута, и мы делаем assert на том, чтобы проверить, что краш лаунчера не происходит через какое-то время. Затем мы его выключаем.
На коде параметризации выше видно, что мы можем один и тот же код переиспользовать на разных платформах. Более того, мы можем переиспользовать один и тот же код на разных уровнях или проектах. Например, красным выделены платформы: в одном случае это Windows, в другом случае это Mac; желтым цветом выделен проект; светло-желтым выделено название уровень.
Ссылка на видео 36:07–36:47
Теперь о работе теста — в данном случае запускаем его через командную строку. Открывается программа под названием Asset Processor, одна из основных частей движка. Данная программа перерабатывает исходные ассеты (к примеру — созданные художниками модели и текстуры) в понятные для движка форматы и записывает все в базу данных (SQLite), чтобы движок мог быстро ориентироваться и подгружать необходимые данные во время игры. Далее запускается сам лаунчер, стартует игровой режим, камера несколько секунд летит над уровнем и тест завершается. Мы видим, что один тест был выполнен успешно и два теста были пропущены. Так произошло потому что во время записи видео тест гонялся на Windows, а в параметризации есть еще две платформы, которые соответственно были пропущены при данном запуске.
Есть более сложный вариант. Мы не просто запускаем лаунчер с готовым уровень, но скрипт взаимодействует напрямую с редактором. Синим выделено название отдельного скрипта, который будет работать с редактором и дергать различные команды через API.
Выше представлен тестовый уровень. В данном случае на стандартном террейне нарисована улыбка при помощи заранее подготовленной текстуры (маски). Нужно проверить, что при использовании маски закрашивание будет осуществляться только по заранее выделенному контуру и не будет заходить за его пределы.
Команда работы с игровым миром написала своё расширение для работы с террейном, которое потом вставляется в наш фреймворк. Создается новая кисть, которая будет рисовать по маске «Cobblestones», кисти выставляется красный цвет и выбранный layer закрашивается.
В продолжении создается новая кисть, ей выставляется другая интенсивность. Маска уже не используется, а в цикле, уже в другой части уровня рисуется новый элемент.
Посмотрим, как работает этот скрипт.
Ссылка на видео 38:42–39:35
Сначала запустится Asset Processor, который проверит состояния базы данных ассетов и переработает вновь добавленные элементы в случае необходимости. Далее запустится редактор. Откроется уровень с улыбкой, и начнет выполняться скрипт, который работает с редактором. Он закрасит layer по маске, далее создаст синий круг и начнет делать скриншоты. Впоследствии скриншоты сравнятся с эталонными, и, если все в порядке, тест завершится.
Такие скриншоты тест берет для сравнения с эталонами. Здесь видно, что рисовка прошла четко по границе.
Графика
Также мы используем наш фреймворк для тестирования графики.
Ссылка на видео 40:04–40:56
Графика — одна из самых сложных частей движка, которая занимает большую часть кода. Проверять можно и нужно все — начиная с простых вещей, вроде геометрии и текстур, так и более комплексных фич — динамических теней, освещения, эффектов пост-процессинга. На видео в правом углу можно видеть отражение в луже — это всё работает в реалтайме на нашем движке. Когда камера залетает внутрь, можно увидеть более продвинутые элементы рендеринга, например, блики, прозрачные элементы, вроде стекла, а также отображение таких элементов как металлические поверхности. Как же данный функционал тестируется скриншотами?
Это наш персонаж, Rin. При помощи неё мы часто тестируем пайплайны художников. Художники что-то создают в своем редакторе (например, персонажа), а потом рисуют на нём текстуры. Asset Processor перерабатывает исходные данные, чтобы задеплоить на различные платформы, а графический движок будет заниматься отображением.
Наверняка вы часто сталкивались с багом, когда «текстуры не подгрузились». На самом деле проблем когда что-то случилось с отображением текстур очень много.
Но все их хорошо отлавливать при помощи сравнения скриншотов. На первом скриншоте можно увидеть баг — некоторые материалы плохо подгрузились. На данных скриншотах тот же самый уровень, где стоял мотоцикл и камера залетела внутрь кафе, который был продемонстрирован на видео ранее. Почему здесь всё выглядит гораздо скучнее? Потому что скриншоты берутся не на самом последнем этапе рендеринга, когда графический движок выложил все свои эффекты, а поэтапно. Сначала берется только рендеринг простой геометрии и текстур: убираются тени, убираются сложные элементы освещения. Если тестировать всё уже на самом последнем этапе и смотреть на Diff Image, то будет сложно сказать, что конкретно сломалось.
Если делать это поэтапно, можно примерно понять, в какой части графического движка что-то пошло не так. Здесь показан алгоритм, которым мы сравниваем скриншоты.
При помощи сравнения скриншотов можно тестировать графику, отображение элементов, текстуры, материалы, шейдеры.
Приведу пример одного бага из старой версии нашего движка, когда у нас не было этого фреймворка.
Ссылка на видео 43:10–43:44
Он касается системы Vegetation. После добавления деревьев графическая часть начинает рисовать тени под ними. Стоит нажать «Ctrl + Z» («Отмена»), деревья пропадают, а тени остаются. Если взять скриншот в начале, когда дерево стоит и после нажатия «Отмена», то такой баг легко поймать в автоматическом режиме после сравнения с эталонными скриншотами До и После.
При помощи сравнения скриншотов также очень хорошо тестируется Asset pipeline. Когда художники что-то создали в 3д редакторах (Maya, 3dsMax), нужно проверить, что в игре всё отображается точно так же, и ничего не пропало: у курицы есть перья, у всех животных — мех, у людей корректно отображается текстура кожи и прочее.
Ссылка на видео 44:16–44:52
В правой части программы — Asset Processor, который следит как раз за отображением в игре всего того, что нарисовал художник. Он скажет нам, что с этими ассетами всё в порядке — они должны работать. На видео можно заметить, что некоторые деревья окрасились в черный цвет. Некоторые отображаются нормально, а некоторые зеленые текстуры просто пропали. Естественно, в таком виде нельзя выпускать движок или ассеты.
Не все можно поймать
Ссылка на видео 45:03–45:17
Какие-то баги начинают образовываться только тогда, когда несколько элементов взаимодействуют между собой. Две модельки Rin отображаются нормально, если их удалить друг от друга, но если их приблизить, начинаются проблемы с геометрией. Такие баги, к сожалению, даже автоматизацией сложно поймать заранее. Зачастую их можно заметить, только когда тестировщики начинают что-то делать в режиме exploratory testing или когда движок уже попадает в руки клиентов.
Сравнением скриншотов можно тестировать интерфейс самого редактора.
Игровые компоненты
Также скриншотами можно тестировать какие-то простые игровые компоненты. Пример — простой уровень, на котором есть дверь и скрипт, который при нажатии на пробел начинает дверь открывать и закрывать.
Можно брать скриншот в начале и в конце. Если всё совпадает, значит скрипт, который меняет местоположение элемента, работает корректно.
WARP
Мы быстро поняли, что скриншоты одной и той же функциональности очень сильно отличаются на различных платформах, в некоторых случаях на одной и той же платформе могут быть различия в зависимости от типа видеокарты. Как с этим бороться, чтобы не хранить по 100500 скриншотов? Есть инструмент, Windows Advanced Rasterization Platform — это программный рендерер, который позволяет делать всю графику без обращения к драйверу и к видеокарте. Используя данный инструмент можно гонять большую часть функциональных графических тестов без зависимости от драйверов и от железяк.
Производительность
Игровой движок не в последнюю очередь должен быть производительным! GPU можно тестировать при помощи различных графических профайлеров, вроде PIX. Оперативную память можно тестировать в самой Visual Studio. Далее подробнее о том, как тестируется производительность процессора при помощи инструмента RADTelemetry.
Знаете, что такое Input Lag?
Ccылка на видео 47:29–48:21
Input Lag — это задержка между нажатием клавиши контроллера/клавиатуры игроком и моментом, когда игра начинает реагировать на нажатие. Input Lag бывает из-за передачи данных по сети, когда пакеты долго идут или сервер долго отвечает, а также в движках и без использования нетворкинга. Когда кто-то накосячил в коде, который отвечает за анимацию, Input lag может стать таким высоким, что персонаж начинает реагировать слишком поздно. В простом приближении это тестируется довольно легко: открывается виртуальная клавиатура и снимается видео, на котором фиксируется момент нажатия на пробел и момент начала анимации.
Смотрим, сколько в данный момент кадров в секунду выдает движок. Можно посчитать, сколько занял каждый кадр в миллисекундах (1000/FPS). Если видео проиграть покадрово, можно посчитать, сколько кадров прошло с момента клика до того, как персонаж начинает двигаться. Зная, сколько миллисекунд занимает каждый кадр, можно посчита