Инструкция по созданию демо-ландшафта в Unity за 24 часа

Рубрика «Рынок игр» публикует подробную инструкцию по созданию большого демо-ландшафта (terrain) на движке Unity за 24 часа от голландского игрового разработчика Натаниэля Долдерсама, который разработал инструменты TerrainComposer и WorldComposer.

Введение

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

Параметры ландшафтов:

  • разрешение карты высот — 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:

Начало работы с 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.

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

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

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

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

И наконец — то, что получилось, когда Питер подкорректировал цвета:

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

После этого мы нарезали 8k-изображение в Photoshop на 2x2 куска по 4k. Это дало нам возможность использовать изображения как карты цветов в RTP (Relief Terrain Pack) на участках ландшафта 2x2. Чтобы это сделать, мы нажали на кнопку 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

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

Затем мы нажали на кнопку 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, поскольку хотели, чтобы карта высот была распределена по сетке ландшафтов 2x2.

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

Мы выбрали вкладку 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 — разрешение, размеры и плотность участков травы можно менять прямо на ходу в режиме реального времени. Поэтому можно задать как минимальные, так и максимальные значения настроек ландшафта.

Слои травы

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

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

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

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

0
5 комментариев
Антон Петренко

Помню когда я мелким был, любил создавать карты в стратегиях всяких. Ну как любил: я создавал большую карту, делал стартовое (по моей задумке) место, убивал на него минут 40-50, все красиво расставлял, а потом меня все задалбливало, я рандомно пихал какие-то деревья, кусты, камни, воду и т.д.

В общем, я тогда и понял, что land-дизайн (или как там это пафосно называется) не мое. По крайней мере за бесплатно.

Ответить
Развернуть ветку
appl3w0rm

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

Ответить
Развернуть ветку
Антон Петренко

"Инструкция по созданию демо-ландшафта в Unity за 24 часа"

Заголовок ни о чем Вам не говорит?

Ответить
Развернуть ветку
Alexander Biragov

Весьма интересный кейс. А какие у этой технологии преимущества перед Lumion?

Ответить
Развернуть ветку
Слав Панкратов

А Lumion совместим с юнити?

Ответить
Развернуть ветку

Комментарий удален модератором

Развернуть ветку
2 комментария
Раскрывать всегда