Пришло время для MonoGame

Очень долгое время MonoGame был не вполне комфортным для использования. Отсутствие собственного Content Pipeline вынуждало устанавливать XNA и Visual Studio 2010, плясать с бубном, а в итоге единственным надёжно рабочим решением было добавление в проект уже скомпилированных файлов ресурсов *.xnb. Кроме того, многие возможности XNA оставались нереализованными. Но теперь всё изменилось…

Начать проще простого. Идём на официальный сайт и загружаем версию для Visual Studio. Сразу после установки появляются шаблоны проектов MonoGame.

Шаблоны MonoGameИли не появляются… В этом случае проблема может быть в том, что в настройках Visual Studio был изменён путь к каталогу с шаблонами и придётся скопировать их вручную из каталога где обычно находятся шаблоны проектов C:\Documents and Settings\UserName\Documents\Visual Studio 2013\Templates\ProjectTemplates\Visual C#.

Выбираем проект для той платформы, которая нам нужна и вперёд. Я выбираю Windows Project, т.е. проект для ОС Windows использующий DirectX в качестве графического API. Естественно, вновь созданный пустой проект тут же можно скомпилировать, запустить и узреть пустой экран закрашенный цветом васильков, он же CornflowerBlue.

В последних версиях MonoGame работа с контентом стала наконец такой же удобной как и при использовании XNA. И даже лучше. Больше не нужно никаких Content Project! Прямо в основном проекте теперь есть файл Content.mgcb, при попытке редактирования которого открывается новая утилита MonoGame Pipeline, предназначенная для добавления ресурсов в наше приложение.

Monogame PipelineДобавим какую-нибудь модель в формате .fbx и текстуру для неё. Выполним билд (F6). Утилита должна рапортовать об успехе. Радует, что запускать её придётся только для добавления новых ресурсов. При редактировании ранее добавленных их перекомпиляция выполняется автоматически при построении проекта в Visual Studio, а в случае неудачи причины сразу видны в окне Error List.

Теперь попробуем отрисовать нашу модель. Для этого нам понадобится объявить несколько переменных для модели, текстуры и эффекта.

Далее в метод LoadContent добавляем код для загрузки необходимых ресурсов. Для эффекта указываем в качестве параметров матрицы мира, вида и проекции, а также текстуру.

В метод Draw добавим код для отрисовки модели с нашим кастомным эффектом.

Далее переходим к коду шейдера на языке HLSL. В нём нам понадобятся переменные для ранее заданных матриц и текстуры.

Фильтры для текстур установленные непосредственно в коде шейдера не всегда корректно работают, поэтому лучше устанавливать их в коде программы.

Далее структуры для входа и выхода вершинного шейдера.

Вершинный шейдер лишь трансформирует координаты вершин и нормали в соответствии с указанными матрицами.

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

В самом конце создаём однопроходную технику использующую вершинный и пиксельный шейдеры.

Данный шейдер расcчитан на использование DirectX 11. В дополнение можно прикрутить примитивное освещение от одного источника и увидеть результат.

monogamesample1Проект для Visual Studio доступен здесь.

Портирование готового проекта с XNA на MonoGame в текущих реалиях является относительно несложной задачей. Потребности править код скорее всего не будет. Единственное несоответствие API XNA, с которым я столкнулся это отсутствие метода Transform у структуры Matrix. Если сложности и возникнут, то они будут связаны с шейдерами. Самое большое неудобство — крайне агрессивная оптимизация вне зависимости от того выполняется построение DEBUG или RELEASE версии проекта. Как следствие, стоит только в шейдере не воспользоваться текстурой, как переменная для неё исчезает и получаем ошибку исполнения при попытке установить соответствующий параметр шейдера. Раздражает…

Для Windows мы можем выбирать между двумя графическими API: OpenGL и DirectX. Выбирая первое, как и в XNA мы будем ограничены возможностями шейдеров модели 3.0. При этом код на HLSL будет при компиляции транслироваться в GLSL. Выбирая DirectX, мы теоретически можем пользоваться возможностями шейдеров вплоть до модели 5.0, но только теоретически. Пока что MonoGame поддерживает только вершинные и пиксельные шейдеры, а значит самые интересные возможности DirectX 10 и 11 остаются недоступными. Многие относительно простые вещи, которых по понятным причинам не могло быть в XNA, отсутствуют и в MonoGame. Метода для генерации mipmap нет, возможности прочитать hardware-глубину нет и т.д. Разумеется всё решаемо. Исходный код MonoGame доступен и при желании всё необходимое можно доделать. Что-то делается совсем просто, что-то сложнее…

Утилита для компиляции ресурсов также не лишена проблем. Они часто возникают при обработке .fbx моделей. Иногда проблема — лишь следствие устаревшего формата входного файла и решается повторным экспортом из blender в новый формат. Иногда это не помогает. Обработка текстур с неполным набором каналов также может быть неудачной.

Поводя итог… Использование MonoGame никогда не было совсем безболезненным процессом и сейчас таковым не является. Но теперь настал тот момент, когда можно говорить о достаточной зрелости проекта, чтобы те кто до сих пор не отказался от XNA наконец сделали это. Хотя бы по той причине, что MonoGame продолжает развиваться. Пусть и не так быстро как хотелось бы…