Пост

Как я планету в Unity генерировал

Исследование предметной области

Это вторая часть истории о том, как разрабатывалась игра «Rocket Science», в которой я оставлю счастливые озарения позади и поговорю о страданиях с Unity, которые незамедлительно появляются, когда ты хочешь создать на движке чуть больше, чем просто 2D платформер.

В одном шаге от No Man's Sky каким он был на релизе В одном шаге от No Man’s Sky каким он был на релизе

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

Как всегда, в Unity не было встроенных инструментов для решения этой задачи. Terrain — единственный инструмент, который похож на то, что мне нужно, но он способен генерировать только плоские поверхности без возможности поворота, безнадежно устарел (даже с учетом последних обновлений в версии 2018.3), никак не расширялся, и к его исходникам невозможно было бесплатно получить доступ. Поэтому нужно было срочно задействовать свои навыки, корнями уходящие в университетские годы.

Поиск решений

Одна из немногих вещей, которой учит тебя университет — это максимальное уменьшение объема затраченных усилий на единицу задания, путем основания своей работы на базе того, что было сделано до тебя. Иными словами, зачем писать записку к курсовой с нуля, если можно найти готовую у ребят старше курсом и переделать лишь отличающиеся части? Этот принцип в менее искаженном виде отлично работает для программирования. Для любой поставленной задачи есть 99%-я вероятность, что ее решили до тебя и более умные чем ты люди и 33%-я вероятность, что они рассказали об этом в блоге, на GDC или даже выложили исходники. С учетом количества подводных камней, которые каждая задача в себе таит, любой поиск информации о ней будет себя окупать.

Свое трехдневное путешествие в поисках информации о генерации планет в Unity я начал с попыток найти готовые, красивые решения, которые можно будет внедрить в свою игру в один клик и наслаждаться результатом. И чем глубже я спускался по страницам результатов поиска, тем быстрее таяли мои надежды. Результаты были, но не такие, как хотелось бы.

Первым стоит выделить Proland и его порт на Unity. Красиво, масштабно, с использованием физически корректных данных. Это казалось именно тем, что нужно, однако я наткнулся на две серьезные проблемы. Во-первых, лицензия (на момент моих поисков) не позволяла использовать Proland и все его производные в коммерческих продуктах без дополнительных согласований. Конечно, можно было пообщаться с французскими коллегами, продать свой холодильник и диван и оплатить стоимость неисключительной лицензии, если бы не вторая загвоздка. Она заключалась в том, что портирование исходников с C++, который я знал на уровне университетских лабораторных работ, заняло бы у меня больше времени, чем написание аналогичного проекта с нуля на C #.

Работы над библиотекой закончились в 2013 году, но ее картинка впечатляет до сих пор Работы над библиотекой закончились в 2013 году, но ее картинка впечатляет до сих пор

А готовый порт, к сожалению, базировался на одном огромном костыле. Проблема заключалась в том, что Proland основан на системе координат, в которой ось Z направлена вверх, а в Unity вверх направлена ось Y. И автор порта разумно упростил себе жизнь, сохранив оригинальное направление осей и просто заменив MVP матрицу у камеры. В последней версии Unity это ломалось и изображение рендерилось зеркально-перевернутым. Даже если на это закрыть глаза, такой костыль все равно неприемлем: работать, когда у тебя половина проекта основана на другой системе координат будет невозможно.

Просто возьми, поменяй оси и пересчитай все матрицы, делов-то.

читатель с научной степенью в линейной алгебре

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

Следующим я нашел SpaceW. Все еще красиво, с намеком на расширяемость в полноценную солнечную систему. Этот проект запустился и даже работал на последней версии Unity без нареканий, но автор признался, что некоторые компоненты все также используют инвертированные оси и куски Proland, другие взяты из Space Engine, в коде много черной магии, экспериментальных фич, и вообще всё это не готово для использования в играх. По моим ощущениям кода и функционала там было еще больше, чем в Proland. Жаль, что автор прекратил активную разработку в 2017 году.

В проекте даже работали солнечные затмения В проекте даже работали солнечные затмения

UnityProceduralPlanets был практически полной противоположностью первым двум проектам, реализовывал самый базовый функционал генерации и мог бы послужить неплохой отправной точкой к пониманию проблемы. Но проект не запустился, оказался в принципе заброшен автором, правильно строил планеты только радиусом меньше десяти километров (радиус Земли, для сравнения, 6371 км) и не был готов для использования в играх.

Выглядит в лучших традициях Unity, но главное ведь то, что внутри Выглядит в лучших традициях Unity, но главное ведь то, что внутри

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

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

Исследование предметной области

Информации о том, как генерировать планеты в интернете попадалось много, однако она была размазана тонким слоем между форумами-мамонтами вроде gamedev.ru, туториалами на Ютубе, статьями в личных блогах и неполными ответами на Stackoverflow. Всю информацию я фильтровал через свой набор требований, выжимал из нее воду и шутки авторов, а сухой остаток складывал в общую копилку до тех пор, пока масса знаний не достигла критической и позволила мне приступить к работе.

Весь «список литературы» приводить здесь нет смысла, но я остановлюсь на трех ссылках. Для начинающих свой путь по чудесной преисподней Unity советую серию видео туториалов Себастьяна Лаге. Он опустил некоторые сложные детали, вроде динамического LOD, однако базовое представление о процедурной генерации получите.

Любителям хардкора и тем, кто не воспринимает информацию в разжёванном виде, можно обратить внимание на «старую», но от этого не менее ценную статью «Планетарный ландшафт». Статья подкреплена формулами, примерами кода на C++ и шейдерами на HLSL (или GLSL? они все на одно лицо) и является наиболее полным руководством к действию из тех, что я видел. Однако здесь нужно включать голову и понимать, как подходить к материалу через призму имеющихся инструментов Unity. Если, к примеру, кинуться реализовывать отсечение по пирамиде видимости из статьи, то можно потратить большое количество времени впустую.

И, напоследок, классика жизни, хрестоматия космических полетов и Святой Грааль безупречной физической симуляции — выступление на GDC разработчиков Kerbal Space Program. Генерации планет там посвящена всего четверть видео, да и в целом описаны общие концепции без конкретики, но слушать интересно и можно избежать пары грабель. Рекомендую.

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

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

Перечитав список требований, я на секунду задумался, а не вернуться ли к разработке убийцы Масс Эффекта, но пути назад уже не было. Скрипя зубами, я выписал список задач, с которыми мне предстояло столкнуться, и он удивительным образом оказался не таким устрашающим. И мы пройдемся по каждой задаче и моим вариантом ее решения в следующей статье на DTF.

Напоследок еще раз оставлю вам страницу игры в Стиме и ссылки на каналы в Телеграме и Дискорде. До скорой встречи.

Авторский пост защищен лицензией CC BY 4.0 .

© unbeGames. Некоторые права защищены.

Популярные теги