Загрузка мира генерация ландшафта

Загрузка реальных ландшафтов в Unity 3D

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

По этой теме тоже довольно много разного рода публикаций в сети. Однако, многие из них опираются на использование платных приложений или расширений для Unity. Существуют описания и «дешевых» методов, но основная масса их ориентирована на получение так называемых heightmap — черно-белых квадратных изображений местности, где градациями серого определяется относительных уровень высот в данной точке. Существует ряд способов генерации подобных карт высот с использованием например инструментария GDAL. И такой подход не лишен недостатков, связанных с достаточной громоздкостью процедуры создания карты высот и последующей привязкой к полученной местности. Поэтому, в данной статье будет изложен некий альтернативный подход и интересующиеся приглашаются под кат.

1. Добыча геоданных

Тут всё уже давно изобретено до нас, за что следует благодарить NASA, выполнивших в свое время программу SRTM (Shuttle Radar Topography Mission) по радиолокационному картонированию земной поверхности. Данные, полученные в ходе миссии находятся в открытом доступе вот здесь. Идем по этой ссылке и наблюдаем наш родной «шарик» поделенный на зоны.

Для демонстрации описываемой методики выберем район «крыши мира», гору Эверест. Для этого щелкаем по нужному куску карты и жмем кнопку «Download».

Распаковываем скачанный архив, и находим там среди прочего файл srtm_54_07.tif в формате GeoTIFF. GeoTIFF — открытый стандарт хранения картографической информации. Анализируя данный файл можно получить данные по высотам точек земной поверхности. Так как формат открытый, организовать непосредственную работу с ним, скажем из Unity будет несложно, но мы, пока, для упрощения, пойдем более коротким путем и воспользуемся маленькой но полезной программкой 3DEM. Это софтинка бесплатна и легко качается с официального сайта. Качаем её и открываем в ней добытый нами GeoTIFF района Эвереста. При открытии нас попросят выбрать формат геоданных, выбираем GeoTIFF:

После чего выбираем вышеупомянутый файл и видим такую картину:

Показанный район довольно велик. Прямоугольником по центру показан интересующий нас район горы Эверест. Чтобы вырезать нужный кусок жмем F8, выбираем интересующую нас область и жмем Enter. Нам предложат уточнить границы участка по широте и долготе.

Уточняем если нужно и нажав ОК получим интересующий нас район на экране:

Если надо, повторяем эту процедуру. В конце концов мы выберем нужный район, а затем идем в главное меню по пути File → Save Terrain Matrix. Нам предложат выбрать формат сохраняемых данных:

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

  • everest.hdr — текстовый файл с описанием сохраненного участка и формата хранения данных
  • everest.bin — сами данные, которые есть просто двухмерный массив высот в формате с плавающей запятой одинарной точности

3. Описание формата хранения геоданных

Его нетрудно получить из pdf-документа, идущего вместе с 3DEM. Главная информация находится в *.hdr-файле и выглядит она так

Опишу самые важные для нашей задачи поля

  • file_title — имя *.bin-файла с данными
  • data_format — формат представления данных
  • left_map_x, lower_map_y — долгота и широта левого нижнего угла участка (считаем что верх этого условного «прямоугольника» смотрит на север), в градусах
  • right_map_x, upper_map_y — долгота и широта правого верхнего угла участка, в градусах
  • number_of_rows — число строк в матрице данных. Каждая строка описывает высоты на фиксированной широте из указанного координатами углов диапазона с равным шагом.
  • number_of_columns — число столбцов в матрице данных
  • elev_m_unit — единицы измерения высот
  • elev_m_minimum — минимальная высота над уровнем референсного эллипсоида (для простоты — уровнем моря) на данном участке
  • elev_m_maximum — максимальная высота над уровнем референсного эллипсоида
Читайте также:  Комплексно тематическое планирование сад огород

Таким образом, становится понятно как читать бинарный файл — он просто поток float’ов, записанных в файл построчно. Эта матрица, в нашем случае хранит высоты в 177 х 188 = 33276 точках на выбранном участке, ограничения по долготе и широте для которого нам известны. Так же нам известен и диапазон высот на данном участке.

3. Хранение данных о высотах в Unity

Класс Terrain в Unity имеет публичное поле terrainData, через которое можно получить доступ к следующим полям

  • heightmapResolution — разрешение карты высот. Оно кратно степени двойки, выбирается из ряда 128, 256, 512… с добавлением единицы. По умолчанию оно равно 513 х 513
  • size — реальный размер террейна в условных единицах Unity. Это поле имеет тип Vector3, и задает размер террейна сразу по всем осям.
  • SetHeights(int xBase, int yBase, float[,] heights) — метод для загрузки данных карты высот. xBase, yBase — индексы, начиная с которых карта высот читается движком из массива heights.

Карта высот — квадратный массив вполне определенного размера. Матрица геоданных — массив прямоугольный. Вычитать её из файла дело техники, и подобный код настолько прост, что специально приводить его не имеет смысла. Главная сложность, преобразовать данные GeoTIFF к карте высот, удовлетворяющей следующим требованиям

  • квадратная матрица, размером кратным степени двойки + 1
  • высоты, хранимые в матрице, нормированы в диапазоне от 0.0 до 1.0

4. Преобразование геоданных в карту высот

Нормировать высоты достаточно просто:

где level[i,j] — нормированная высота; h[i,j] — высота в точке (i,j); h_min, h_max — минимальная и максимальная высота на участке. Для приведения размера матрицы к выставленным требованиям нужна аппроксимация высоты в зависимости от координаты. Воспользуемся простейшей линейной аппроксимацией. Пусть высота есть функция координат точки на участке . Тогда, выберем базовую точку , совпадающую с одним из узлом заданной координатной сетки и разложим эту функцию в ряд Тейлора

При кажущейся сложности, формула легко реализуется кодом на C#

Пользуясь этой функцией легко формируем матрицу для карты высот

5. Плагин для редактора Unity

Чтобы облегчить жизнь мной был написан небольшой плагин для редактора движка UnityGeoDataLoader, позволяющий решать поставленную задачу. Этот продукт и его исходный код распространяются по лицензии GNU GPL v2.0. По указанной ссылке можно получить и то и другое. Там же есть и инструкция по использованию данного инструмента.

Плагин встраивается в редактор и добавляем в главное меню пункт «Tools -> Load GeoData». Выбрав террейн в инспекторе, жмем этот пункт меню, указываем путь к файлу *.hdr (рядом с которым лежит и файл *.bin с данными) и вуаля — лицезреем гору Эверест в редакторе Unity

Дальше с этим террейном делаем всё что душе угодно — текстурируем, применяем шейдеры, расставляем другие объекты. Это уж на ваше усмотрение.

Заключение

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

Источник статьи: http://habr.com/ru/post/329246/

Генерация ландшафта как в MineCraft

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

Читайте также:  Петергофские террасы гостилицкое шоссе

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

И так собственно о том, как я делал. Сначала я попробовал делать на основе шума Перлина (строил карту высот и по ней уже создавал 3д ландшафт), получилось достаточно интересно, но как видно не очень-то и похоже на Minecraft.

В 2д варианте это выглядело вот так.
Упрощенный пример кода для шума Кена Перлина.

for x:=-20 to 20 do
for y:=-20 to 20 do begin
n := x + y * 57;
n := (n shl 13) xor n;
ObjectCount:=ObjectCount+1;
Engine.AddProxy(PerlinCube,RootCube,’Cube’+IntToStr(ObjectCount),FileListBox1.FileName,x,2*(1 — ((n * (n * n * 15731 + 789221) + 1376312589) and $7fffffff) / 1073741824),y,0,1,0,1,1,1);
Map2[x,y]:=’Cube’+IntToStr(ObjectCount);
end;

В 3д смотрится лучше, да и то из за добавленного уровня воды.

После прочтения статьи модифицировал, так как примерно было раньше в самой игре. Для каждого столба блоков высота равнялась (общ_высота + (шероховатость*детали))*64+64. От себя я добавил простое сглаживание. Получилось гораздо лучше.

Вот упрощенная часть кода для небольшого куска:

for x:=-20 to 20 do
for y:=-20 to 20 do begin
nerov:=Random(3);
melk:=Random(2);
Map1[x,y]:=((pod+(nerov+melk))*5+5)-25;
end;

Engine.AddUCube(RootCube,’PerlinCube’,FileListBox1.FileName,x,(1 — ((n * (n * n * 15731 + 789221) + 1376312589) and $7fffffff) / 1073741824),y,0,1,0,1,1,1);

for x:=-20 to 20 do
for y:=-20 to 20 do begin
ObjectCount:=ObjectCount+1;
Engine.AddProxy(PerlinCube,RootCube,’Cube’+IntToStr(ObjectCount),FileListBox1.FileName,x,map1[x,y],y,0,1,0,1,1,1);
Map2[x,y]:=’Cube’+IntToStr(ObjectCount);
end;

Я заснял поэтапно.

1. Построен кусочек карты.

2. Добавлен шум Перлина.

3. Первый цикл сглаживания.

4. Второй цикл сглаживания.

5. В конце немного деревьев что было не так уныло.

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

Ссылки.
Кому интересно вот ссылка на перевод статьи о ландшафте Minecarft.
Очень понравилась статья о шуме Перлина ссылка.
Так же напомнили про очень интересную статью по генерации ландшафтов ссылка.

Источник статьи: http://habr.com/ru/post/128368/

Как генерируются миры — описание подходов для создания процедурных локаций в играх Статьи редакции

Краткое знакомство с алгоритмом планирования, а также с симуляционным и функциональным подходами.

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

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

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

Читайте также:  Длинная беседка вдоль забора

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

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

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

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

Для игр с псевдо-бесконечным миром, таких как Minecraft и No Man’s Sky, важно отсутствие зависимостей от соседних точек — по крайней мере, для генерации ландшафта. Поскольку мир генерируется кусками на лету, у конкретной точки может не быть нужных соседей, так как они ещё не сгенерированы.

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

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

В Minecraft, например, рельеф вычисляется при помощи функционального метода. А освещение затем симулируется в соответствии с имеющейся контекстной информацией о геометрии мира.

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

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

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

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

Подход планирования часто используется в роуглайках — несколько комнат с разными условиями размещаются на локации, а игра связывает их проходами.

Чаще всего алгоритм планирования применяется для подземелий, а не для игр с псевдо-бесконечными мирами. Но и это возможно: для этого потребуется алгоритм планирования, который умеет работать с большими масштабами — он нужен для создания общего дизайна мира. Затем остальные алгоритмы создадут отдельные части окружения, которые соединятся вместе.

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

И только доминирующий подход должен влиять на игровой процесс и определять, как пользователь передвигается по пространству и достигает целей.

Источник статьи: http://dtf.ru/gamedev/640820-kak-generiruyutsya-miry-opisanie-podhodov-dlya-sozdaniya-procedurnyh-lokaciy-v-igrah

Оцените статью