Как сделать ландшафт в юнити
Перейти к содержимому

Как сделать ландшафт в юнити

  • автор:

Создание и редактирование terrain’ов

Вы можете добавить объект terrain’а в сцену, выбрав GameObject > Create Other > Terrain из меню (это также добавит соответствующий ассет terrain’а в окно Project). При этом, ландшафт изначально будет ничем иным, как просто большой, плоской равниной. Однако, если вы посмотрите на инспектор при выделенном объекте terrain’а, вы увидите, что там представлен ряд инструментов, которые вы можете использовать для создания любых нужных вам ландшафтов.

Инструменты редактирования terrainа, появившиеся в инспекторе

За исключением инструмента размещения деревьев и панели настроек, все остальные инструменты на панели инструментов обеспечивают набор “кистей” и настроек для размера и прозрачности кисти. То что, эти кисти похожи на кисти из графических редакторов — не совпадение, т.к. именно так создаются детали у terrain’а, с помощью их “рисования” на ландшафте. Если вы выберете первый слева инструмент на панели инструментов (Raise/Lower Terrain) и передвинете мышь над terrain’ом в окне Scene, вы увидите, что курсор напоминает прожектор на поверхности. Кликая кнопку мыши, вы можете нарисовать постепенные изменения в высоте ландшафта в точке расположения мышки. Вы можете менять форму кисти в панели Brushes. Опции Brush Size и Opacity влияют на область кисти и силу “нажима” соответственно.

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

Быстрые клавиши terrain’а

Вы можете использовать следующие сочетания клавиш в инспекторе terrain’а:-

  • Нажатия на клавиши от Q до Y с зажатой клавишей shift выбирают соответствующий инструмент (например, Shift-Q выбирает инструмент Raise/Lower).
  • Запятая (,) и точка (.) циклично переключают доступные кисти.
  • Shift-запятая (<) и Shift-точка (>) циклично переключают доступные объекты для деревьев, текстур и деталей.

Кроме того, стандартная клавиша F работает несколько иначе для terrain’ов. Обычно, она показывает в кадре окна Scene выбранный объект, если мышка располагается в окне Scene. Однако, так как terrain’ы обычно очень крупные объекты, нажатие F будет фокусировать вид окна Scene на области terrain’а, над которой в данный момент находится мышь/кисть. Это обеспечивает очень быстрый и интуитивный способ перепрыгивания к области terrain’а, которую вы желаете отредактировать. Если вы нажимаете F, когда мышка удалена от объекта terrain, клавиша работает в обычном режиме, как описано выше.

Создание террейна в Unity 3D

Отличительной чертой Unity является его гибкость, адаптивность к разработке как небольших 2D-паззлов или аркад, так и к разработке больших-серьезный стратегий, RPG или игр других жанров. В то же время, одной из парадигм Unity является простота освоения и удобство работы.

Создание ландшафта в Unity сравнимо с работой в редакторе ландшафта Warcraft 3. Немногим сложнее, зато предоставляются возможности по созданию действительной красивых ландшафтов.

Часть первая. С чего начать?

Начать следует, конечно, с установки и запуска редактора.
Процесс установки пропустим, так как он не вызовет затруднений ни у кого.
Итак, редактор запущен. Создаем или загружаем проект, в котором предстоит делать ландшафт. Если вы уверены, что не используете никаких ассетов с графикой, то следует выбрать ассет Environment из стандартной комплектации.
Следующее действие — добавить в проект этот самый «террейн», который будем создавать.
Для этого в верхнем (главном) меню выбираем GameObjects — > 3D Objects — > Terrain.

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

Эта панелька будет с нами до конца статьи

Часть вторая. И что это за кнопки?

Первый инструмент, на иконке которого изображены горы со стрелочкой вверх (и который выделен на рисунке бирюзовым)- это создание неровностей. Им можно создавать возвышения (кликнув на террейне в нужном месте) или впадины (то же самое, но с зажатым шифтом).
Обратите внимание , что для получения эффекта нужно настроить кисть — её форму, размер и «силу» (Opacity — непрозрачность).
Обратите внимание также, что для создания полноценных впадин террейн нужно сначала поднять. В противном случае ландшафт лишь выровняется до минимального уровня.
В этом уроке не будет рекомендаций по созданию красивого ландшафта. Не будет даже советов по использованию созданного ландшафта. Цель урока — помочь освоиться с базовыми функциями редактора и, может быть, помочь преодолеть так называемый «ступор незнакомого интерфейса», возникающий у многих людей при запуске незнакомой программы или знакомой с изменившимся интерфейсом.

Наверняка после недолгих экспериментов вы получили некие резкие перепады высот, которые смотрятся «не очень». Для их устранения нам поможет Smooth terrain, расположенный справа через одну. Выглядит он как всё та же горка с каплей воды рядом (На рисунке выделен желтым). Это отнюдь не создание воды, как может показаться. Это сглаживание.
Левее, кстати, расположен инструмент для создания плато ( выделен зеленым ) — он выравнивает высоту. Для захвата необходимой высоты зажимаем Shift, после чего «рисуем» плато без зажатого шифта.
Следующие инструменты позволяют наложить на ландшафт текстуры, расположить деревья и декорации. Последняя кнопка на этой панели — настройки.

Для добавления текстуры (иконка — кисть, выделена красным ), нужно сначала добавить тайлы. Ниже настроек кистей будет панель текстур. Нажимаем Edit textures — > Add texture и подбираем нужную (и как Normal, и как Smoothness) из списка предложенных (к слову, их можно добавлять самостоятельно, но об этом в другой раз). Для наглядности можно создать первой текстурой GrassRockyAlbedo, а второй — GrassHillAlbedo, после чего поэкспериментировать с настройками кисти и текстуры, порисовав травой.
Преимуществом Unity является обилие кистей и довольно высокая гибкость их настроек, что после небольшой практике позволяет с легкостью создавать интересные ландшафты с минимумом усилий.

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

Также, на панельке можно найти кнопку «Mass Place Trees«, которая позволяет заполнить весь террейн указанным количеством деревьев.
Последний инструмент ( выделен синей рамкой) — расположение деталей, то есть всяческих украшений, вроде травы. Опять же, в изначальной поставке их не то, чтобы много.
К примеру, выбираем Edit Details -> Add Grass Texture и выбираем текстуру GrassFrond01AlbedoAlpha после чего испытываем её кистью.

Заключение

Создание ландшафта в Unity3D — это не трудно. Конечно, использование Unity не гарантирует запредельный уровень графики без приложения каких-либо усилий, да и модели и текстуры, вероятно, придется делать самостоятельно или с привлечением художников и 3D-артистов, искать в сети, либо покупать. Охватить все тонкости в рамках одной статьи решительно невозможно. Более того, статья рассматривает лишь одну грань работы с Unity.

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

Создание ландшафта на Unity за 24 часа

Обложка поста Создание ландшафта на Unity за 24 часа

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Скриншоты и ссылки на скачивание демо-ландшафта расположены по этой ссылке.

Введение

В этой статье я расскажу о том, как мы с Питером за 24 часа собрали крутую демку с большим открытым миром. Надеюсь, это руководство поможет вам создавать более красивые ландшафты (terrain) в Unity. Для демонстрации мы использовали 2 x 2 ландшафта Unity (суммарно — четыре ландшафта) с параметрами, указанными ниже, и общим для всех ландшафтов разрешением.

Находим N’е число Фибоначчи тремя способами за приемлемое время: основы динамического программирования

  • разрешение карты высот — 4097 пикселей (рекомендованный максимум для игр — 2048 пикселей);
  • разрешение сплат-карты (splatmap) — 1024 пикселя;
  • разрешение базовой карты ландшафта (basemap resolution) — 256 пикселя;
  • разрешение карты расстановки травы — 8192 пикселя (рекомендованный максимум для игр — 2048 пикселей);
  • параметр grass per patch — 8.

Разрешение текстур для RTP:

  • карта цвета (colormap) — 8192 пикселя;
  • карта нормалей — 4096 пикселей;
  • карты распределения — 4096 пикселей.

Следует понимать, что эти настройки — для высокопроизводительного железа. В TerrainComposer вы можете менять разрешение ландшафтов на лету, это позволяет подобрать настройки и для более слабого железа. Мы не сделали этого во второй версии проекта, но планируем сделать в третьей.

Чтобы наши деревья выглядели красивее, мы применили пакет Advanced Foliage Shader от Forst. Преимущество пакета состоит в том, что с ним билборды деревьев могут отбрасывать тени и сам переход от билборда в 3D-дерево выглядит намного лучше, чем при использовании стандартного шейдера Unity, что обеспечивает отсутствие скачков при движении камеры (в тех местах, где дерево заменяется на билборд).

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

Мы использовали следующие ассеты Unity:

  • Relief Terrain Pack;
  • Advanced Foliage Shader;
  • TerrainComposer;
  • WorldComposer.

Начало работы с WorldComposer

Сначала мы выбрали в WorldComposer область размером 30,107 x 30,107 км вокруг горы MountRanier. Мы установили значение Image Zoom равное 17, что обеспечило суммарное разрешение 36x36K (36000 х 36000 пикселей) для фото со спутника. 36K — слишком высокое разрешение для непосредственного использования в Unity, поэтому позднее мы уменьшили изображение в Photoshop до 8K.

После выбора области мы нажали на Export Heightmap, а затем на Export Images. Для экспорта изображения был выбран формат Raw, чтобы можно было удалить тени. После экспорта на выходе мы получили карту высот размером 4K и 9 x 9 изображений с разрешением 4K.

Удаление теней в WorldComposer

Возможность удаления теней делает WorldComposer (WC) уникальным по сравнению с другими программами и существенно улучшает качество изображений, полученных со спутника. Я потратил много дней, создавая алгоритм удаления теней, а также работая над стримингом, так как в Unity (по-крайней мере, в Unity 4.x) есть ограничения по количеству и размеру изображений, которые мы одновременно можем загрузить в память.

Удалять тени в WC можно при любом разрешении изображения в формате RAW. Удаление теней даёт нам возможность ввести в ландшафт дневные и ночные циклы — это очень круто, так как иначе пришлось бы фиксировать положение солнца в проекте так, чтобы оно соответствовало бы теням на снимке со спутника.

После экспорта изображений мы кликнули кнопку Combine Images. Она собирает все изображения в формате RAW выделенной области в одно большое изображение, сохраняя его под именем area_name+_combined.raw в папке для экспортируемых изображений. После этого мы выбрали вкладку Image Editor в верхней части окна WorldComposer.

В данном режиме мы можем видеть одновременно два изображения. Левое изображение представляет собой оригинальный спутниковый снимок текущего участка на карте WorldComposer, а правое — превью изображения после удаления теней. В настройках вкладки Image Editor есть два цвета. Эти цвета определяют диапазон, в котором будет работать алгоритм работы с тенями.

Мы задали радиус, равный 1500, и число повторов (параметр Repeat), равное 4. Алгоритм удаления теней просматривает все теневые пиксели и находит ближайший пиксель без тени, а затем переносит его в какой-то из теневых пикселей в пределах заданного радиуса. Если значение параметра с радиусом слишком мало, вы можете увидеть повторяющиеся участки. Это происходит потому, что алгоритм делает несколько проходов по изображению, чтобы обработать все теневые пиксели.

После выбора настроек мы нажали кнопку Apply во вкладке Image Editor. Обработка занимает много времени ввиду большого размера изображения, но это во много раз быстрее, чем если бы мы делали то же самое в Photoshop. К тому же, Photoshop имеет ограничение по памяти, так как в нём нет стриминга. Мы сохранили полученное изображение в папке экспортируемых изображений под именем Combined2.raw.

Уменьшение размера изображения в Photoshop

Мы открыли MountRanier_Combined2.raw в Photoshop со следующими настройками:

Затем выбрали в меню Photoshop → Image → Image Size.

И уменьшили изображение до 8192×8192 пикселей и, чтобы получить максимальное качество, выбрали при этом режим Bicubic Sharper.

Затем я передал спутниковое изображение Питеру, и он немного подкорректировал цвета в Photoshop.

Вот оригинальное спутниковое изображение, экспортированное из WorldComposer:

Это — изображение после работы алгоритма по удалению теней в WorldComposer и корректировки цветов:

Нарезка спутникового изображения в Photoshop

После этого мы нарезали 8k-изображение в Photoshop на 2×2 куска по 4k. Это дало нам возможность использовать изображения как карты цветов в RTP (Relief Terrain Pack) на участках ландшафта 2×2. Чтобы это сделать, мы нажали на кнопку Slice и, удерживая её, выбрали Slice Select Tool. Затем кликнули на спутниковое изображение и выбрали Divide Slice. В результате появилось окно Divide Slice, где мы настроили два сегмента по горизонтали и два по вертикали.

Затем мы перешли в меню Photoshop и выбрали → File → Save for Web.

Чтобы сохранить каждый участок как JPG-файл, я выбрал Quality на уровне 75% и кликнул Save.

WorldMachine для большей детализации

Питер импортировал карту высот из WorldComposer в WorldMachine (WM), создал там новый проект и добавил к карте высот эрозию, чтобы ландшафт выглядел более детально. После WC карта высот в принципе и так смотрится достаточно хорошо, но с помощью WM вы можете добавить дополнительные детали. Из полученной карты высот Питер создал карту нормалей.

Карты нормалей можно создавать и в самом TerrainComposer, если у вас нет WorldMachine:

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Питер также создал в WM карту распределения деревьев и травы, которую мы впоследствии использовали в TerrainComposer для размещения растительности. WorldMachine хорошо дополняет TerrainComposer. TerrainComposer может импортировать из WM карты высот, сплат-карты и карты распределения.

Создание ландшафтов в TerrainComposer

Мы начали с создания четырёх ландшафтов (2×2) со следующими настройками:

Затем мы нажали на кнопку Create Terrains.

В рамках этого проекта мы постарались выжать максимум возможностей из Unity, поэтому поставили разрешение текстур повыше. Использовалась карта высот размером 4k, но для игр я бы рекомендовал использовать текстуры размером максимум 2k. В демке есть возможность устанавливать более высокую пиксельную погрешность (параметр Pixel error), чтобы Unity отрисовывала меньше вершин на ландшафте.

Если вы используете RTP с глобальной картой нормалей, ландшафт будет отлично выглядеть и с максимальной пиксельной погрешностью. Высокое значение параметра Pixel error даст лучшую производительность, но может вызывать скачки частей ландшафта при движении камеры. Мы брали очень высокое разрешение для карты травы — 8192, и это единственный способ получить такую плотность, которая бы действительно хорошо выглядела.

В Unity трава рендерится не очень эффективно, поэтому в демке частота кадров тоже не особенно хороша. Как вариант, можно было бы использовать объёмную траву от Тома (разработчика RTP) вместе с травой ландшафта Unity. Кликните VolumeGrass, чтобы убедиться в этом.

Импортирование карты высот

Сначала мы нажали кнопку Height в верхнем левом углу окна TerrainComposer. Затем добавили слой карты высот, развернули фильтр Height Select0 и нажали Input → Raw Heightmap. Затем загрузили карту высот, которую Питер получил в WorldMachine после добавления эрозии. Для Stretch Mode мы выбрали MultiTerrain, поскольку хотели, чтобы карта высот была распределена по сетке ландшафтов 2×2.

Работа со сплат-текстурами

Мы выбрали вкладку Splat в верхней части окна TerrainComposer. Зашли в первый ландшафт в списке ландшафтов TerrainComposer и кликнули на вкладку Splat Textures. Сначала мы добавили четыре сплат-текстуры, нажав одновременно Shift и Set All, а затем Shift и RTP, чтобы применить скрипт RTP к каждому ландшафту.

Здесь показаны слоты с картой цветов и картой нормалей, а также дополнительные слоты Splat, Normal и Height. Мы использовали кнопку Select, чтобы быстро назначить карту цветов и карту нормалей в RTP для каждого ландшафта. В текущем подходе мы использовались полутоновые изображения, так как они перемножаются с картой цветов в RTP. Таким образом сплат-карты не будут влиять на карту цветов, а только сделают её темнее или ярче.

Настройка RTP

Настройка _RTP_LODmanager

Если в TerrainComposer одновременно с Shift нажать RTP под кнопкой Splat Textures, к каждому ландшафту добавится RTP-скрипт. RTP автоматически добавляет в сцену обьект _RTP_LODmanager. Теперь вы можете настроить RTP-шейдер. Мы использовали следующие настройки:

  • RTP на ландшафте — первый проход (мы используем только четыре сплат-текстуры);
  • d3d9 (PC) (для Windows);
  • opengl (Mac);
  • UV blend (это скроет тайлинг сплат-текстуры);
  • Global color blend multiplicative (мы используем полутоновые сплаткарты, которые при данных настройках будут перемножаться с картой цветов);
  • Global normal map (это позволит визуально увеличить разрешение карты высот, а также улучшить то, насколько детально терейн воспринимается на дальней дистанции);
  • LOD Level → POM with RTP_Shadows и RTP_Soft_Shadows (это даёт детальный вид на ближней дистанции, когда текстуры ландшафта выглядит так, словно имеют перепады высоты).
Настройки в скрипте RTP для ландшафта

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

Том объясняет эти настройки в своём видеоруководстве по RTP3:

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Сплат-слои

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

Во втором сплат-слое мы использовали вторую сплат текстуру — для травы. Затем, поставив фильтр Output на Change (Overlay) и параметр Layer в значение Layer, мы добились того чтобы этот слой рисовался поверх предыдущего.

Потом мы применили маску, чтобы красить поверх грязи только в тех местах, где на карте цвета нарисован цвет травы. Для этого в маске мы установили Input в значение Image, а затем добавили первую карту цвета, установили опцию Auto Search (автопоиск) и включили Load on generate, чтобы загрузить каждую цветовую карту в каждый ландшафт в маске. Мы выбрали цвета от тёмно-зелёного до ярко-зелёного, чтобы TC рисовал сплат-текстуру травы, используя все цвета из этого диапазона цветовой карты.

Мы сделали то же самое для третьей сплат-текстуры — с травой и камнями, задав точно такие же настройки слоя и фильтра, как и для слоя травы. Чтобы продублировать слой травы, мы нажали одновременно Shift и +, а затем скорректировали его для нашей текстуры с травой и камнями. В данном случае использовались цвета от тёмно-коричневого до ярко-коричневого.

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

Размещение деревьев

Мы использовали 16 разных видов деревьев: задали их для первого ландшафта в списке ландшафтов TerrainComposer, а затем нажали одновременно Shift и Set All, чтобы применить их ко всем четырём ландшафтам.

После этого мы нажали кнопку Tree в верхней части окна TerrainComposer и добавили один слой деревьев — и все 16 деревьев в этот слой. Для каждого дерева можно задать множество параметров, включая масштаб, который мы дополнительно настроили для некоторых деревьев поменьше.

С помощью фильтров в TerrainComposer можно выбрать объекты для размещения и маски для плотности (которые отвечают за то, нужно ли размещать объекты в этом месте или нет, и если да, то насколько плотно). Мы использовали настройку Random Input в фильтре, чтобы разместить типы деревьев случайным образом, кроме этого мы применили две кривых Перлина с разными уровнями приближения. Нам хотелось избежать совершенно случайного размещения, сделать так, чтобы некоторые типы деревьев росли группами.

О шумовой функции в TC можно можно думать как об изображении облаков (низкое значение приближения даст очень маленькие облака, высокое — очень большие). Деревья в слое имеют значения от 0 до 1, и если результат фильтра равен 0, будет выбрано дерево tree0, а если фильтр даст 1, то будет выбрано дерево tree16.

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

Мы сделали это с помощью кривой, которая шла от 1 (слева) до 0 (справа). В левой части кривой высота нулевая, а в правой — максимальная. Выходом маски является вертикаль (плотность). Чтобы исключить размещение деревьев на очень крутых склонах, мы использовали вторую маску, параметром которой была крутизна поверхности.

В третьей маске мы использовали текстуру распределения деревьев из WorldMachine. Деревья могут размещаться на белом и не могут — на чёрном. Эффект такой же, как с высотой и крутизной в предыдущих масках, но в данном случае мы ещё и не хотели размещать деревья в местах, которые подверглись эрозии. В четвёртой маске мы использовали шум Перлина, чтобы создать группы деревьев, а не просто размещать их равномерно.

Размещение травы

Мы перешли во вкладку Grass, нажав на соответствующую кнопку в верхней части TerrainComposer. Чтобы получить хорошую траву без заметных повторений, мы использовали 10 разных текстур. Задав текстуры травы для первого ландшафта в TC Terrain List, мы одновременно кликнули на Shift и Set All и применили их ко всем четырём ландшафтам.

Использование десяти текстур травы с картой распределения травы разрешением 8К — не лучшая идея, поскольку для каждой текстуры травы Unity использует двумерный массив, размер которого зависит от разрешения травы. Игра с такими настройками будет работать только на мощном железе.

С другой стороны, так как TerrainComposer работает и в самой игре, а не только в редакторе Unity — разрешение, размеры и плотность участков травы можно менять прямо на ходу в режиме реального времени. Поэтому можно задать как минимальные, так и максимальные значения настроек ландшафта.

Слои травы

Мы использовали четыре слоя травы. В первом слое мы разместили все текстуры травы, а каждый из остальных трёх слоёв содержал одну текстуру цветка.

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

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

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

Перевод статьи «24 Hour Demo: How We Made It…»

Материал взят с сайта Цукерберг Позвонит

Следите за новыми постами по любимым темам

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

Генерация ландшафтов в Unity3d

Думаю все заметили, что сейчас стало появляться множество всяких бродилок с выживанием в стиле Minecraft. Сделать такую решился и я. Начало было лёгким — Unity3d имеет огромный функционал для сознания простеньких игр (и не только). Персонаж, игровые объекты, в общем основу сделать быстро. Но какой minecraft без рандомно генерируемого мира? Это стало первой трудной задачей. И думаю не только для меня. Просмотрев весь гугл и потратив кучу времени на эту бесполезную вещь я решил написать эту статью дабы сократить страдания других.

Дальше вас ждёт описание алгоритмов (и код) создания более менее реалистичных ландшафтов. Уточню, что все примеры на C#.

План действия

Для начала хорошо бы было разобраться, что подразумевается под генерацией ландшафта:

  1. Генерация карты высот. Это самая главная часть, по карте высот строится terrain (или mesh). Её можно также использовать для окрашивания terrain в зависимости от высоты
    и для расстановки игровых объектов.
  2. Построение ландшафта. Есть два способа выполнения этого пункта, в зависимости от того не хотите ли вы сложностей и используете ли вы unity3d, или же вам плевать на производительность, но вам важно, чтоб было красиво. В первом случае советую использовать встроенный в unity3d редактор ландшафта (terrain).
    Простенький код для этого:

 Terrain terrain = FindObjectOfType (); // Находи наш terrain float[,] heights = new float[resolution,resolution]; // Создаём массив вершин // . // Делаем с heights всё, что хотим // . terrain.terrainData.size = new Vector3(width,height,length); // Устанавливаем размер нашей карты terrain.terrainData.heightmapResolution = resolution; // Задаём разрешение (кол-во высот) terrain.terrainData.SetHeights(0, 0, heights); // И, наконец, применяем нашу карту высот (heights) 
Shader "Custom/TerrainShader" < Properties < _HTex ("heightMap texture", 2D) = "white" <>_GTex ("grass texture", 2D) = "white" <> _RTex ("rock texture", 2D) = "white" <> > SubShader < Tags < "RenderType"="Opaque" >LOD 2048 CGPROGRAM #pragma surface surf Lambert sampler2D _GrassTex; sampler2D _RockTex; sampler2D _HeightTex; struct Input < float2 uv_GTex; float2 uv_RTex; float2 uv_HTex; >; void surf (Input IN, inout SurfaceOutput o) < float4 grass = tex2D(_GTex, IN.uv_GTex); float4 rock = tex2D(_RTex, IN.uv_RTex); float4 height = tex2D(_HTex, IN.uv_HTex); o.Albedo = lerp(grass, rock, height); >ENDCG > FallBack "Diffuse" > 

Итак, поняв общий план действий, надо приступать к делу.

Частые ошибки

С самого начала я думал, что всё будет очень просто и для рандомной генерации ландшафта можно обойтись обычной функцией Random(). Но это самый неправильный способ. Его результат это вовсе не красивая карта, а расчёска в приближении.

Шум Перлина

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

Perlin noise (Шум Перлина, также иногда Классический шум Перлина) — математический алгоритм по генерированию процедурной текстуры псевдо-случайным методом. Используется в компьютерной графике для увеличения реализма или графической сложности поверхности геометрических объектов. Также может использоваться для генерации эффектов дыма, тумана и т.д.

Думаю многих испугала приставка псевдо, но от неё легко избавиться. Далее представлен способ реализации шума в Unity3d:

 using UnityEngine; using System.Collections; public class PerlinNoisePlane : MonoBehaviour < public float power = 3.0f; public float scale = 1.0f; private Vector2 startPoint = new Vector2(0f, 0f); void Start () < MakeNoise (); >void MakeNoise() < MeshFilter mf = GetComponent(); // Ищем mesh Vector3[] vertices = mf.mesh.vertices; // Получаем его вершины for (int i = 0; i < vertices.Length; i++) < float x = startPoint.x + vertices[i].x * scale; // X координата вершины float z = startPoint.y + vertices[i].z * scale; // Z координата вершины vertices[i].y = (Mathf.PerlinNoise (x, z) - 0.5f) * power; // Задаём высоту для точки с вышеуказанными координатами >mf.mesh.vertices = vertices; // Присваиваем вершины mf.mesh.RecalculateBounds(); // Обновляем вершины mf.mesh.RecalculateNormals(); // Обновляем нормали > > 

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

Алгоритм diamond-square

После долгих часов скитаний по интернету наткнулся на этот алгоритм, и он оправдал все мои ожидания. Он даёт прекрасные результаты. Для расчитывания вершин есть очень простая формула.
Представим себе плоскость, её 4 вершины и точку по центру. Её высота будет равна сумме высот 4 вершин, делённая на их кол-во и некого случайного числа с коэффициентом. Вот код для unity3d (халява копи-пастерам):

using UnityEngine; using System.Collections; public class TerrainGenerator : MonoBehaviour < public float R; // Коэффициент скалистости public int GRAIN=8; // Коэффициент зернистости public bool FLAT = false; // Делать ли равнины public Material material; private int width=2048; private int height=2048; private float WH; private Color32[] cols; private Texture2D texture; void Start () < int resolution = width; WH = (float)width+height; // Задаём карту высот Terrain terrain = FindObjectOfType(); float[,] heights = new float[resolution,resolution]; // Создаём карту высот texture = new Texture2D(width, height); cols = new Color32[width*height]; drawPlasma(width, height); texture.SetPixels32(cols); texture.Apply(); // Используем шейдер (смотри пункт 3 во 2 части) material.SetTexture ("_HeightTex", texture); // Задаём высоту вершинам по карте высот for (int i=0; i > // Применяем изменения terrain.terrainData.size = new Vector3(width, width, height); terrain.terrainData.heightmapResolution = resolution; terrain.terrainData.SetHeights(0, 0, heights); > // Считаем рандомный коэффициент смещения для высоты float displace(float num) < float max = num / WH * GRAIN; return Random.Range(-0.5f, 0.5f)* max; >// Вызов функции отрисовки с параметрами void drawPlasma(float w, float h) < float c1, c2, c3, c4; c1 = Random.value; c2 = Random.value; c3 = Random.value; c4 = Random.value; divide(0.0f, 0.0f, w , h , c1, c2, c3, c4); >// Сама рекурсивная функция отрисовки void divide(float x, float y, float w, float h, float c1, float c2, float c3, float c4) < float newWidth = w * 0.5f; float newHeight = h * 0.5f; if (if (w < 1.0f && h < 1.0f)) < float c = (c1 + c2 + c3 + c4) * 0.25f; cols[(int)x+(int)y*width] = new Color(c, c, c); >else < float middle =(c1 + c2 + c3 + c4) * 0.25f + displace(newWidth + newHeight); float edge1 = (c1 + c2) * 0.5f; float edge2 = (c2 + c3) * 0.5f; float edge3 = (c3 + c4) * 0.5f; float edge4 = (c4 + c1) * 0.5f; if(!FLAT)< if (middle else if (middle > 1.0f) < middle = 1.0f; >> divide(x, y, newWidth, newHeight, c1, edge1, middle, edge4); divide(x + newWidth, y, newWidth, newHeight, edge1, c2, edge2, middle); divide(x + newWidth, y + newHeight, newWidth, newHeight, middle, edge2, c3, edge3); divide(x, y + newHeight, newWidth, newHeight, edge4, middle, edge3, c4); > > > 

Материалы по теме
  • Realtime Procedural Terrain Generation (PDF). Очень ценный документ, где рассказано всё про генерацию ландшафтов. Единственный минус — на английском
  • Статья про фрактальные ландшафты
  • Отличная статья про шум Перлина
  • Вики про diamond-square

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *