TOTAL RELOAD : процедурная генерация проводов. (часть 1)

TOTAL RELOAD : процедурная генерация проводов. (часть 1)

Готовы рассказать о процедурной генерации проводов и о том как она устроена в TOTAL RELOAD. Всего проводам будет посвящено 2 статьи (2 части). Выше приведен скриншот из игры на котором представлены финальные провода.

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

Предупреждение: эта статья не является инструкцией, также, скорее всего, она не будет полезна профессиональным программистам, которые имеют опыт работы с процедурной генерацией мешей. Статья содержит картинки, видео и обобщенные объяснения разработанной нами системы генерации проводов и обобщенный ответ на вопрос «что же такое меш (mesh)?» Итак, поехали!

Часть 1. Процедурная генерация проводов

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

Версия провода № 1

В самом начале разработки игры было принято решение не пытаться вытянуть качество графики до уровня ААА – проекта. Причины такого решения просты:

  • команда состояла (и состоит) из 2-х человек, которым задач и так хватало
  • не было уверенности, что все окупится

Итак, в первое время мы разработали «2D» систему проводов, которые были плоскими. Я думал, плоская – это хорошо в плане того, что меньше полигонов и объем проводам можно картами нормалей придать (если потребуется). Ниже представлен первый вариант системы проводов:

Как работала система проводов:

  • имеется набор вложенных gameObjects – узлы проводов
  • родительский объект создает процедурный mesh с UV. Mesh и UV создаются в зависимости от позиции узлов проводов.

Система позволяла выполнять поставленные задачи:

  • отображала соединения объектов
  • относительно гибко настраивалась
  • генерируемый провод соответствовал первому минималистичному стилю

Меш провода генерировался процедурно по точкам. Здесь видно конечный результат (вариант провода №1):

Провод менял свою геометрию тогда, когда одна из точек меняла свою позицию. Провод мог гнуться на углы +/-90 градусов относительно родительского объекта. Еще одно видео:

Так планировалось прокладывать провод в уровне:

Технически, провод имеет начало и конец, он автоматически должен соединять разные элементы уровня. Это было реализовано процедурно. Имитация соединения элементов по какому-то событию показана на видео:

И вроде как все были довольны этой системой проводов, но…

Но тут, по мере анализа уровней, быстро пришло понимание: «это не то, чего мы хотели добиться». Конечно, смотрится неплохо, лучше чем ничего и даже лучше чем некоторые дизайнерские решения. Но минималистичный стиль присутствует повсеместно и в очень многих инди-проектах. В общем, в очередной раз понесли мы свои результаты к эффективному менеджеру Сове. Сова к этому времени была порядочно раздражена нашими глупыми решениями, но приняла нас. Вот что мы принесли ей напоказ:

Конец провода
Конец провода
Подключение проводов к двери
Подключение проводов к двери
Подключение проводов к двери
Подключение проводов к двери
Соединение проводов с элементами
Соединение проводов с элементами

У Совы, насколько мы знаем, брови изначально (наверно с рождения) повернуты под 90 градусов. А после всего того, что мы показали, они у нее просто вывернулись на все 360.

Что не устроило Сову:

- Обыденность и минималистичность: где-то она уже видела этот провод;

- Скрытность: он плоский, сбоку его вообще не видно;

- Повороты кратны 90 градусам: уровень будет иметь углы только кратные 90 градусам, это снижает возможности разработчика уровней до… лучше не думать, даже некоторые первые в мире игры имели стены, которые располагались под произвольными углами.

По проводу все осталось в общем по-старому, только в ТЗ добавилось 4 требования:

- провод должен гнуться не только на 90 градусов;

- провод должен быть объемным, так как плоский визуально сливается с полом;

- текстура должна тайлиться, а не растягиваться;

- уникальность проводу нужно придать моделью + материалом.

Пара слов о генерации меша

Хотелось бы чтобы статья содержала больше полезной информации чем просто результаты нашей работы.

Немного глубже затронем тему процедурной генерации мешей.

Что такое меш (mesh)?

Меш – это, условно, модель, которая крепится к компоненту «MeshFilter», который, в свою очередь, принадлежит «GameObject». MeshFilter берет меш из ассетов и передает его в MeshRenderer, последний участвует в рендере меша на экране.

Способы создания моделей для игр:

- в редакторах моделей (например: Blender, Maya, 3ds Max и другие);

- процедурно

- редактирование существующего меша (в общем-то это процедурная генерация меша)

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

О том как создавать меши уже написано столько всего, что мне остается дать одну из ссылок на материалы и обьяснить, в общем виде, как все работает. Ссылка на то как сгенерировать меш в Unity3D: martin-ritter.com

При создании меша, во-первых, относительно локального (0,0,0) создается геометрия. Геометрия – это набор вершин (точек), которые соединены между собой. Потом идет массив «triangles». Этот массив содержит порядок точек. Тут стоит совсем немного пояснить:

- видеокарте нельзя просто дать точки на отрисовку треугольника без указания порядка. Почему? В основном потому, что есть оптимизация. Треугольник имеет две стороны и если бы видеокарта всегда бы рендерила его две стороны, то она бы неоправданно расходовала ресурс. Порядок передачи точек связан с тем куда нужно направить нормаль полигона.

- видеокарта может рисовать только несколько примитивов: точку, прямую и треугольник. Все остальное создается из примитивов.

Итак, этого в общем-то достаточно для рендера геометрии, но недостаточно для наложения текстур на геометрию. Для наложения текстур нужно создать массив UV – координат. Эти координаты показывают в какую область текстуры проецируется каждая вершина геометрии/модели. Обычно UV принимают значения из диапазона [0,1]. Где (0,0) – нижний левый угол текстуры, (1,1) – правый верхний. В некоторых случаях UV могут принимать значения больше 1 и меньше 0. Это зависит от задачи, которую поставили перед «shader-artist» и его конкретной реализации шейдера.

Кроме vertex и uv, меш может содержать и другие данные:- uv2, uv3…, uv9 (не знаю чем определяется предел uv[i], наверно платформой)

- tangents

- normal

- color

И да, чуть не забыл, нужно создать AABB. AABB – это axis-aligned bounding box. То есть это «коробка», которая позволяет движку быстро исключать игровые объекты из процесса отрисовки на основе попадания их AABB в область видимости камеры.

Зачем? Это сделано для того, чтобы быстро отбрасывать объекты, которые за спиной игрока, чтобы они даже не пытались подаваться на графический конвейер. Оптимизация! :)

Версия провода 2

В основу этой версии легли сплайновые кривые, а вернее, деформация модели вдоль сплайновой кривой. Что такое сплайн и как он работает? Это достаточно базовая математика, в сети есть даже готовые примеры проектов со сплайнами, детальный разбор того как все работает (не буду повторять то, что замечательно расписано здесь: catlikecoding.com), не будем на них останавливаться.

Вот как выглядит настройка провода:

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

Провод с тесселяцией (сверху) и без тесселяции
Провод с тесселяцией (сверху) и без тесселяции

Все провода имеют один общий материал, особенности всех проводов закодированы в вершинах мешей.

Здесь версия проводов ближе к финальной (на концах установлены вилки, заданы текстуры, доработаны модели):

TOTAL RELOAD : процедурная генерация проводов. (часть 1)
TOTAL RELOAD : процедурная генерация проводов. (часть 1)

Ссылки на нас:

33
Начать дискуссию