Как сделать открытый мир в unreal engine 4
Джонатан Хемменс поделился тем, как создавалась сцена в UE4 , с использованием инструментов Substance и Maya , рассказал о мастер-материале, эффекте сияния, замке и много чём еще!
Введение
Меня зовут Джонатан (Jonjo) Хемменс , я художник окружения в The Creative Assembly . История, композиция и свет, это то с чем мне нравится работать. Мой недавний проект показывает закат проигравшей цивилизации. После долгой осады, Викинги наконец прорвались в соседнее королевство. Наступила ужасная зима, и были зажжены сигналы, направляющие тех, кто остался в вечной мерзлоте в сторону плодородных земель.
Я расскажу вам технические стороны создания замка, эффекта свечения, мастер-материала и персонажа. Также я коснусь проблем крупных проектов, важность отзывов, о том как фокусироваться на обучении и что делать, если кажется что сделать проект не получится.
Цели проекта и мотивация
Перед началом этого проекта я еще не экспериментировал с органическим окружением в Unreal Engine и подумал, что будет хороший идеей заполнить подобные пробелы знаний такого пайплайна. Целью этого проекта было изучение техник по созданию составных частей крупномасштабного окружения - травы, деревьев, пропов, чтобы с помощью этих элементов рассказать какую-нибудь интересную историю.
Пока я искал вдохновление, я нашел концепт-арт Сергея Забелина , под названием "Замок в заснеженном лесу". Этот арт стал основой всего настроения и сцены в целом. Я адаптировал многие вещи, добавил свою историю, полностью изменил дизайн замка, но при этом всё еще оставались некоторые элементы, которые сохранились в моей сцене.
Также примерно около этого времени я наткнулся на статью, написанную Леей Августин о ее проекте " Заснеженный лес ". Разбор работы позволил получить довольно много ресурсов, которые я использовал в своем проекте. Также я получил ответы на первоначальные вопросы, касающиеся технических проблем, связанных со снегом, так что эта статья позволила сделать отличный рывок в начале проекта.
Ландшафт
Создание ландшафта и материалов было моим первым шагом. Я увидел обучающие видео от Джейкоба Норриса о создании Forest Snow Ground в Substance Designer , а затем материала в UE4 . Также он рассматривал и другие полезные техники и переменные, которые нужно учитывать при создании материала. Курс сейчас бесплатен, так что можете спокойно его просмотреть.
Блокаут сцены
В качестве основы я взял концепт Сергея. После настройки камеры я начал скульптурировать формы ландшафта с помощью встроенных в UE4 инструментов для работы с террейном. Далее я сделал блокаут формы горы и набросал небольшую равнину на переднем плане, с парочкой скал на фоне.
Я использовал Gaea для создания гор, добавив материал эррозии и разместив с цене. Хоть они и не являлись центром сцены, они позволили мне заполнить фон и сделать локацию более приятной на вид.
Я слегка отошел от концепции, чтобы рассказать свою историю через эту сцену, и на этот счет у меня были довольно амбициозные идеи. Я хотел сделать огромный замок, со стенами, простирающимися вдоль гор. Замок осадили Северяне, так что я начал работать над их лагерем.
Как вы видите, я начал текстурировать ассеты и добавил парочку камней. Но вообще это была ошибка, так как я отвлекся на них вместо завершения блокаута, и позднее это вызвало некоторые проблемы. И в этот момент я не смог понять, что проект становится слишком большим для меня одного.
Мастер-материал
Создание сцены со снегом привнесло свои трудности. Одна из самых главных - это снег на объектах. Моделирование и текстурирование всего этого вручную мне явно не подходило, так что я решил сделать шейдер, чтобы делать всё это в динамике. И здесь мне пригодился обучающий курс от Mind Games Interactive , который я нашел в статье Леи. В видео они демонстрируют генерирование мха в зависимости от положения объекта в сцене. Все это было довольно легко адаптировать под снег, вместо мха.
В курсе рассказывается как создать шейдер, который динамически может применять снег на определенные части модели, и автоматически обновлять текстуру при ее вращении. Также он смешивается с картой нормалей и заполняет все углубления в меше. Я сделал небольшое превью с использованием бесплатных ассетов Quixel . Вы сможете видеть, как снег сам наслаивается на поверхность модели.
Вторая проблема, это швы при пересечении мешей с террейном. Чтобы это решить, я использовал бесплатный материал на Gumroad от " orikmcfly ", он позволил мне скрыть границы между мешем и текстурой террейна. Принцип работы прост, рассчитывается расстояние между мешем и ближайшей поверхностью, а затем происходит смешивание текстур.
Минусы этого всего в том, что нужно не давать ассетам таким же образом взаимодействовать с освещением. Так что используя этот процесс становится невозможным использование Distance Field .
Я объединил эту технику со смещением пикселей, это позволяет как бы размыть пиксели в месте пересечения ассетов в зависимости от их положения. Звучит сложно, но на самом деле просто.
Пример из документации по UE4 :
На мастер-материал я потратил всего день, включая дополнительные функции вроде деталей, смены оттенков, альф и масок с SSS (подповерхностное рассеяние). Все это можно включать и выключать в материале с помощью переключателей. Так очень легко контролировать каждый элемент в материале, и при этом не нужно создавать уникальный материал под каждый проп или текстуру.
Хоть граф и выглядит большем, как только вы поймете как использовать переключатели и Lerp 'ы, все становится супер простым. Это позволяет сэкономить кучу времени, так что я планирую и в дальнейшем использовать подобные материалы.
Примерно на половине проекта я понял, что будет очень сложно передать осаду без мертвых тел. До проекта я еще не пробовал создавать персонажей, так что это была довольно волнительная часть. Чтобы подойти к делу правильно, я создал список того, чего не смогу сделать для персонажа.
- Анатомия : Слишком долго изучать, никогда этого не делал.
- Реалистичная кожа : Даже хороший художник тратит на это очень много времени.
- Трата времени : Я уже потратил много времени на сцену, так что лишние траты были не очень хорошим вариантом.
- Поза : Я вообще не знаю как это делать.
Было важно не тратить много времени на персонажа. Скорость была предпочтительнее качества, особенно потому, что я знал, что персонаж будет покрыт снегом, кровью и стрелами. Я начал со шлема, это одна из самых сложных форм персонажа, но повторить форму меша в целом оказалось не такой сложной задачей. Такие небольшие победы дают уверенности, так что я знал, что легко справлюсь и с остальными частями тела. Моделированием брони я занимался в Maya с использованием SubDivision 'ов, ничего такого.
Чтобы создать кольчугу, я выдавил цилиндр из шеи с помощью live -геометрии в Maya . Этот инструмент позволит примагничивать новую геометрию к live -мешу. Это очень полезный инструмент в ретопологии. Я добавлял лупы на цилиндр, если это было необходимо. Этот же процесс я повторил и для рук. После чего сделал простую развертку, швы и накинул текстуру кольчуги. Чтобы не показалось, что в сцене куча клонов одного человека, я текстурировал его так, чтобы он ничем особым не выделялся.
Пока я искал альтернативы ZBrush Posing , я наткнулся на Quick Rig в Maya . Это позволило мне сделать риг примерно за 10 минут, причем с минимумом участия в процессе. Конечно, аниматоры бы не восприняли это серьезно, но процесс полностью соответствовал моим нуждам. Таким образом я смог быстро набросать нужные позы. Минусы этого в том, что для более продвинутых поз нужен правильный скиннинг.
Дальше оставалось добавить стрелы и кровь и разместить их в сцене. Персонажи сразу же ее оживили. С помощью разных поз и смешивания со снегом, было довольно сложно заметить клонирование одного персонажа.
Это один из основных обучающих моментов проекта, который позволил мне больше узнать о персонажах и их позах. Надеюсь я еще буду создавать простых персонажей для окружения, потому что они позволяют значительно приукрасить его внешний вид.
Если вам понравилось, ставьте лайк и подписывайтесь на канал, чтобы не пропустить что-нибудь интересное :)
Изучение Unreal Engine, документация на русском языке
Чтоб система ландшафтов заработала максимально эффективно, вы должны знать о некоторых определенных технических ограничениях, которые нужно брать в расчет. В данном документе прописаны все ограничения, на которые нужно обратить внимание, а также изложена ценная информация, которая поможет вам сохранить баланс между красотой и производительностью ваших ландшафтов.
Технические детали
Валидные размеры полей высот ландшафтов не всегда очевидны в самом начале. Чтоб иметь возможность определить размеры для полей высот, которые валидны и оптимальны, нужно понимать внутреннюю архитектуру Ландшафтов. Чтоб создать систему, позволяющую использовать большие ландшафты, которые эффективны с точки зрения используемой памяти и производительности, архитектура ограничивает размеры полей высот, а это означает, что есть определенные размеры, которые валидны, и прочие, не подходящие. В прежних системах ландшафтов в Unreal Engine либо вообще не было никаких ограничений (любые размеры были валидны и могли работать), либо ограничения были не строгие. Ограничения для полей высот ландшафтов гораздо более сложные и строгие.
Landscape Actor закодирован цветом, так что легко сказать, что именно делает каждая секция. Границы Landscape окрашены желтым, края каждого компонента подсвечены светло-зеленым, края секции (если секция размерами 2×2) окрашены зеленым, а отдельные Landscape-квадраты окрашены в темно-зеленый.
Color: | Landscape Component |
---|---|
Yellow: | Landscape Actor Edge |
Light Green: | Landscape Component Edge |
Medium Green: | Landscape Section Edge |
Dark Green: | Landscape Individual Quad |
Landscape-компоненты
Ландшафты разделены на множество компонентов, которые представляют собой базовый юнит Unreal в плане рендеринга, расчетов видимости и столкновения. Components в Landscape все одинакового размера и всегда квадратные. Размер Landscape component определяется при создании Landscape, и выбор зависит от размера и деталей Landscape, который вы хотите создать
Данные высоты каждого компонента хранятся в одной единственной текстуре. Поэтому ее размер должен быть числом вершин в квадрате. Общий ряд вершин по краям двух соседствующих компонентов дублируется и хранится в каждом компоненте. По этой причине вы должны подумать о количестве квадратов в каждом компоненте.
Ниже представлен очень простой Landscape (подсвечен зеленым), содержащий 4 компонента. Каждый компонент состоит из простого квадрата. Один компонент отделен, чтоб показать, как дублируются те вершины, где встречаются компоненты.
Секции компонента
Компоненты можно опционально разделить на 1 или 4 (2×2) подсекции. Эти секции служат базовым юнитом расчетов Landscape LOD.
Использование подсекции 4 (2×2) дает вам тот же размер поля высот, как если бы вы использовали в четыре раза больше компонентов всего лишь с одной подсекцией каждый, но использование нескольких компонентов обычно приводит к большей производительности.
Размер каждой секции (количество вершин) должен быть в квадрате (максимально 256×256). Таким образом разные уровни LOD могут хранится в мипмапе текстуры. Так мы получим число квадратов в компоненте, также это число в квадрате минус 1. (если 1 секция на компонент) или числов квадрате минус 2 (если 4 секции на компонент).
Отдельный компонент, который проиллюстрирован ниже, содержит 4 секции. Каждая секция состоит из 9 (3×3) квадратов. И опять, вы можете заметить, что вершины, где секции встречаются, дублируются.
Расчет размеров поля высот
Как вы можете видеть, размеры для Landscape вытекают из количества квадратов в каждой секции, количеста секций в каждом компоненте и количества компонентов, представленных в Landscape. Определив количество компонентов и, найдя решение для каждого из этих компонентов, вы можете подсчитать размеры Landscape.
Вот несколько примерных сценариев:
Пример 1
Если мы начинаем с компонента с одной единственной секцией, которая содержит 64×64 вершин, то размер такого компонента составляет 63×63 квадратов . Скажем у нас есть Landscape размером 10×10 этих компонентов, то есть у нас 630×630 квадратов в общем в нашем Landscape. Теперь, если мы хотим импортировать высоты для такого Landscape, то у нас появится поле высот размером 631×631 вершин, потому что вершин всегда на один ряд больше, чем квадратов. Так что 631×631 — это валидный размер Landscape.
Пример 2
Если у нас есть компонент, поделенный на 4 подсекции, каждая из которых собрана из 64×64 вершин, то это ведет к 63×63 квадратам на секцию, и 126×126 квадрат на компонент. Если у нас 32×32 этих компонентов, то мы получаем 126 * 32 = 4032 квадратов в общем в каждом направлении. Так что общий Landscape будет содержать 4033×4033 вершин.
Эти примеры фокусируются на квадратных ландшафтах. Но, как бы то ни было, Landscape не обязательно должен быть квадратным. Например, в первом примере 10×10 не обязательные размеры. Предлагая 63 квадрата на компонент, вы можете иметь любой Landscape из компонентов AxB с конечным размером в вершинах (A*63+1 , B*63+1).
Вопросы производительности
Выбор размера компонента, противопоставленный общему количеству компонентов – это компромисс производительности. Компоненты меньшего размера позволяют совершать более быстрый переход LOD, но меньший размер предполагают большее количество компонентов.
Каждый компонент нагружает центральный процессор и каждая секция посылает команду, так что попытайтесь минимизировать эту нагрузку и число команд. Для самых крупных ландшафтов рекомендуется использовать 1024 компонентов максимально.
Рекомендованные размеры ландшафтов
Чтоб облегчить дело, вот вам размеры, которые максимизируют область, но минимизируют количество компонентов Landscape.
Overall size (vertices) | Quads / section | Sections / component | Component size | Total Components |
---|---|---|---|---|
8129×8129 | 127 | 4 (2×2) | 254×254 | 1024 (32×32) |
4033×4033 | 63 | 4 (2×2) | 126×126 | 1024 (32×32) |
2017×2017 | 63 | 4 (2×2) | 126×126 | 256 (16×16) |
1009×1009 | 63 | 4 (2×2) | 126×126 | 64 (8×8) |
1009×1009 | 63 | 1 | 63×63 | 256 (16×16) |
505×505 | 63 | 4 (2×2) | 126×126 | 16 (4×4) |
505×505 | 63 | 1 | 63×63 | 64 (8×8) |
253×253 | 63 | 4 (2×2) | 126×126 | 4 (2×2) |
253×253 | 63 | 1 | 63×63 | 16 (4×4) |
127×127 | 63 | 4 (2×2) | 126×126 | 1 |
127×127 | 63 | 1 | 63×63 | 4 (2×2) |
Режим Layer Debug
Режим Layer Debug визуализирует влияние определенных уровней на Landscape в Viewport. Вы можете включить режим Layer Debug в меню View, который находится в Viewport, в Landscape Visualizers.
При включенном режиме Layer Debug кнопки-пульки, позволяют выбрать отдельные цветовые каналы, которые перечислены в списке целевого уровня.
Выбор уровня применит шейдер к Landscape, и он покажет область, которую покрывает канал выбранного целевого уровня.
Игровой процесс в наших головах и на практике — очень разные вещи. То, что нам кажется интересным, для других будет полным ужасом. Кроме того в проекте часто бывают спорные моменты — управление, правила игры, динамика игры и так далее. Поэтому, прежде чем врываться в разработку и осуществлять задуманное, надо сначала сделать прототип — сырой и быстрый продукт, который позволит попробовать основную механику и получить представление о геймплее.
Меня зовут Игорь Титаренко , я работаю Unreal Engine разработчиком в компании SolidCore Games . Свежий пример, который я хочу с вами рассмотреть — прототип раннера. По этой ссылке вы можете скачать файлы проекта и потестить его.
В готовом прототипе будет:
Персонаж бегущий вперед, на кнопки “A”, “D” меняем локейшн по оси “ X ”.
Уровень, по которому мы передвигаемся — Tile Map. При перемещении персонажа, пройденный тайл перемещается вперед.
Монеты, которые мы будем собирать, и подсчет очков.
Простой UI (Game Over, Score, Restart) и к онец игры при столкновении с препятствием.
Ассеты я подготовил заранее и буду подгружать из готового проекта. Логику напишу с нуля.
Создание проекта и настройка персонажа
Создадим проект на основе Third Person, в котором у нас по умолчанию будет персонаж и уровень.
Я убираю из уровня лишнюю геометрию и настраиваю персонажу управление. Изначально, при нажатии на “W” вызывается событие MoveForward и персонаж передвигается вперед. Мы будем вызывать логику движения вперед не нажатием кнопки, а на Event Tick, то есть на каждый кадр в игре, чтобы персонаж все время бежал вперед.
Затем настраиваем перемещение персонажа на кнопки “A”, “D” — меняем локейшн по оси X .
Создаем массив float переменных, в котором будем хранить значения локации по оси X каждой из трех “дорожек”, по которым бежит персонаж.
Далее проверяем по какой полосе мы бежим — 0, 1 или 2, затем на нажатие кнопок “A”, “D” добавляем или отнимаем индекс полосы, если он не выходит за минимальное и максимальное значение.
После этого, в зависимости от индекса полосы дороги, задаем координаты по оси Х для нашего персонажа.
Tile Map
Начнем с подготовки ассетов для генерации уровня. Нам понадобится:
- Машинки, которые мы будем расставлять по уровню.
- Монетки, которые мы будем собирать.
- Tile — blueprint actor с наполнением уровня. Из тайлов мы будем генерировать “коридор” нашего уровня.
BP_Car
Теперь сделаем машинки, которые будут спауниться на уровне. Чтобы разнообразить игру, будем генерировать случайную машину из массива возможных вариантов. Создаем новый blueprint actor, добавляем ему компонент Static Mesh. Создаем массив с вариантами геометрии для наших машин. Далее пишем логику, которая при создании машинки будет генерировать рандомное (в пределах массива) число — индекс, и по нему задавать нашему эктору геометрию из массива.
BP_Coin
У каждого отдельного тайла на каждой полосе дороги в случайном месте по оси Y спаунится машинка, и на случайной полосе спаунится группа монет.
Чтобы геометрия монет и машинок не пересекалась, мы будем спаунить монеты выше, чтобы они падали на карту. При столкновении с машинкой или дорогой отключим им физику. Таким образом монеты будут на одинаковой высоте и над асфальтом и над машинками, в тех местах где они есть. Здесь они у меня на неравном расстоянии друг от друга, но на то он и прототип, чтобы быстро передать принцип без длительной проработки.
Создаем blueprint actor, добавляем ему компонент геометрии и коллизию, которая будет отвечать за отключение физики при столкновении с поверхностью.
По умолчанию сделаем наш actor физическим объектом, чтобы включить гравитацию. Для этого поставим галочку physics enabled. Далее добавим логику отключения физики, когда она нам больше не нужна.
Сделаем так, чтобы монетка все время вращалась.
BP_Tile
Создаем тайл, из которого будет генерироваться уровень, по которому будет бежать персонаж. Я создаю новый Blueprint actor, добавляю ему нужные нам компоненты:
- StaticMesh — геометрию зданий и окружение.
- Box Collision “SpawnPoint Box” коллизию которая будет отрабатывать событие, когда персонаж пробежит данный тайл. Это необходимо, чтобы мы могли вызвать логику уничтожения данного тайла и спауна нового впереди.
- Spawn point — точку координат, в которой мы будем спаунить новый тайл.
Далее пишем функции генерации машин. Логика здесь такая — получаем локейшн тайла и в случайном месте из заданного диапазона по оси Y спауним BP_Car.
Тоже самое и для монет, только добавим цикл, чтобы генерировать сразу несколько штук.
На событие начала игры вызываем функции спауна машин, по одной для каждой полосы движения, и на случайной полосе спауним монеты.
Теперь в GameMode напишем логику генерации уровня. Класс GameMode отвечает за настройку правил игры. Правила могут включать в себя любое поведение, связанное с игрой. Например, условия выигрыша или, как в нашем случае, генерацию тайл мапа. Функция спауна тайлов будет выглядеть так:
Спауним первый тайл в нулевых координатах, которые записаны в переменную NextSpawnPoint. После этого вытаскиваем локейшн у его Spawn Point. Получаем координаты этой точки и записываем их в переменную NextSpawnPoint — эти координаты будут использованы для следующего тайла. Вызываем функцию еще раз, чтобы заспаунить следующий тайл. В Game Mode на Event Begin Play создадим цикл, который будет вызывать спаун тайлов нужное нам количество раз.
Начало игры запускает цикл. Он проходит от нуля до пяти. То есть функция Spawn Tile вызывается шесть раз. Соответственно, в начале игры спаунится шесть тайлов.
Если сейчас запустить игру, сгенерируется наш tile map, но мы можем пробежать его от начала до конца. Напишем логику для real time генерации тайлов при перемещении по уровню. В BP_Tile добавляем к SpawnPoint Box событие On Component Begin Overlap. Оно будет срабатывать, когда бокс компонент пересечется с другим объектом игрового мира, у которого есть коллизия. Событие проверяет, что столкнулось с SpawnPointBox. Если это character, которым мы управляем, то вызываем из Game Mode функцию спауна нового тайла и после задержки удаляем пройденный тайл.
UI, Подсчет очков
Создадим Widget Blueprint и назовем его WBP_Point.
Добавим в наш виджет следующие текстовые виджеты:
- Score
- GameOver
- Your Score
- Total Score
Сделаем наши текстовые виджеты переменными, чтобы задавать им значения.
Visibility всех элементов виджета кроме Score устанавливаем Hiden и д обавляем кнопку Restart, на нажатие которой заново будет открываться наш уровень.
В целом наш виджет должен выглядеть примерно так:
Перейдем в Graph и создадим переменную “Score” типа integer — целое число. Для текстов Score и Total Score привяжем созданную интовую переменную в качестве значения. Теперь из переменной зададим значение в текст, а переменную, в свою очередь, будем менять в персонаже.
Теперь добавим наш виджет во вьюпорт. Для этого в ThirdPersonCharacter на Event Begin Play создадим виджет WBP_Points, добавим его во вьюпорт и сохраним ссылку на него в переменную “Widget Score”.
Теперь у нас есть практически все для того, чтобы собирать монетки. Создадим в ThirdPersonCharacter событие PickupPoints. При вызове события получаем значение переменной Score из ссылки на виджет Widget Score, добавляем к нему 5 очков и обратно записываем в переменную Score.
PickupPoints будем вызывать из BP_Coin. Добавим событие On Component Begin Overlap для static mesh, в котором проверим с чем пересекается монетка. Если это ThirdPersonCharacter, вызываем у него PickupPoints и уничтожаем монетку.
Теперь, когда персонаж пересечется с монеткой, количество очков увеличится на 5, что сразу отобразится в виджете, а монетка исчезнет/подберется.
Далее создадим логику конца игры, которая будет вызываться на столкновение персонажа с машиной. Для этого создаем в WBP_Points функцию Game Over, в которой будем менять visibility текстовых виджетов Game Over, Total Score, Restart button.
Добавим отдельный Box Collision component в ThirdPersonCharacter.
Привяжем событие на столкновение с этим боксом, в котором мы проверим: если ThirdPersonCharacter сталкивается с BP_Car, то вызываем функцию Game Over из WBP_Points, которая отрисует нужный нам интерфейс. Далее отключаем движения персонажу и включаем отображение курсора мыши, чтобы иметь возможность нажать Restart.
Теперь, если врезаться в машинку, мы получим такой результат:
3D-художник Алиреза Хаджехали – настоящий мастер ландшафтного дизайна. Он создал бесчисленное количество виртуальных локаций, полностью играбельных в UE4. В этом интервью она описал свой рабочий процесс и рассказал о том, как WorldMachine и Megascans помогают ему конструировать большие и реалистичные цифровые миры.
Это не туториал, а интервью, которое поможет представить рабочий процесс. Обучающая статья заняла бы более десяти страниц.
С оригинальным материалом можно ознакомиться тут.
Из того, что я делал недавно, можно выделить LawBreakers, где я делал природные фоны для уровней. Работая над Chronicles of Elyria, я был в позиции универсала, то есть создавал и игровые уровни, и рекламные шоты. Кроме того, я делал ландшафт в Squad и сейчас работаю с друзьями над Our Ghosts of War, это личный проект.
Я думаю, каждый художник окружения мечтал заниматься этим с самого детства. К примеру, когда мне было 4-5 лет, то я всегда, смотря фильмы, думал о том, как бы я оформил декорации, доверь они это дело мне. Мне всегда нравилось комбинировать вещи таким образом, чтобы они отлично смотрелись друг с другом – именно это я и делал в CryENGINE 2 в свои моддеррские деньки.
Должен признаться, что когда вы, наконец, доделываете большую открытую локацию, где все сделано до последней песчинки правильно, чувство удовлетворения гораздо сильней, чем от создания маленькой изолированной сцены. И это именно тот наркотик, который заставляет меня двигаться дальше. Я всегда жду момента, когда закончу очередную работу и смогу насладиться тем, что создал.
Мне всегда лень делать закладку того, что я только что визуализировал в своей голове, поэтому как только у меня появляется идея желаемого, я начинаю работать над картой высот будущего ландшафта.
Как правило, для генерации карты высот я использую WM2 (World Machine 2). Далее беру карты высот и несколько масок, с их помощью делая карту веса (splat map). Использование карты веса для ландшафтов – это старый, но по-прежнему самый лучший метод. Я также экспортирую карту высот в сетку, а затем использую эту сетку для дизайна фонов локации. Для этого я сначала упрощаю сетку, а затем запекаю высокополигональную модель в низкополигональную, чтобы у меня был низкополигональный ландшафт и карта нормалей, которые можно разместить за пределами локации и тем самым создать видимость, что локация больше, чем на самом деле. Вот две картинки, показывающие разницу с фоновыми моделями и без них:
К слову, у меня есть одна специальная функция, которая позволяет использовать цветовую информацию определенной точки ландшафта на объектах, которые на этой точке находятся. Это позволяет делать более плавные переходы между землей и камнями.
Самое интересное начинается после того, как я импортирую в UE4 карту высот и начинаю играться с материалами, функциями, освещением, атмосферой и т.д. Я делаю кучу поправок, постоянно все меняя, пока не поймаю настроение локации.
Что касается тесселляции, меняющейся в зависимости от расстояния, то я создал библиотеку модульных функций, с помощью которых могу улучшить качество пейзажа, причем с очень небольшими затратами вычислительных ресурсов. Более того, эти функции универсальны, и я могу использовать их при работе с другими локациями, делая абсолютную красоту и очень быстро. Вот пара картинок, показывающих, как было до и стало после.
А вот еще одна функция, которая в качестве входной информации использует траву и на ее основе позволяет создавать бесконечное количество вариаций – не генерируя новые текстуры, а просто по-другому окрашивая траву. Впрочем, иной раз для того, чтобы пространство не выглядело однообразно, достаточно лишь одного типа травы, безо всяких вариаций.
Я генерирую много рельефа, пока не увижу тот, что соответствует моему видению прекрасного. Я пытаюсь визуализировать то, как люди будут ориентироваться по этому ландшафту – это и помогает мне найти наилучший рельеф.
Другая важная вещь – это масштаб, поскольку погружение сильно зависит от того, насколько велика, к примеру, вон та гора или вон та песчаная дюна. Нужно, чтобы все эти горы, холмы и прочее оставались одного масштаба, который не будет слишком большим или слишком маленьким, а также держать в уме геймплей. То есть локация должна быть не только красивой, но и подходящей для геймплея.
К сожалению, при создании карты высот в WM2 трудно уловить чувство масштаба, и эта программа больше не обновляется. Поэтому я просто импортирую карту высот в UE4 и немного бегаю туда-сюда, чтобы понять, правильный ли получился масштаб. Потом вы немного привыкаете к этому масштабу и далее просто доверяете своему выбору.
Megascans – это очень богатый источник материалов для художников окружения. Впрочем, этой библиотеке пока не достает вариативности материалов, поэтому я не полагаюсь лишь на нее, а использую также CGTextures и делаю собственные текстуры.
Теперь к важному. Вы об этом не спрашивали, но, как мне кажется, этим стоит поделиться. Неважно, Megascans это или нет, но когда вы импортируете текстуру в движок, она начинает выглядеть посредственно. В библиотеке Megascans поверхности отрендерены в миллионы полигонов. Мельчайшая детализация, все в 3D, поддержка теней и генерация AO. Но совсем другое дело, когда вы импортируете эти материалы в игровой движок. В игровых движках поверхности выполнены с небольшим количеством полигонов – как правило, 2 треугольника на один квадратный метр. Но есть способы это обойти. Среди художников окружения есть расхожее мнение, что на PBR-движке металлическим материалам не нужна карта отражений. Также многие ошибочно думают, что на карте альбедо не должно быть теней. Согласиться с этим категорически не могу.
Есть такая штука как микротени, и игровые движки их делать не умеют, поэтому эти микротени нужно добавлять на карту альбедо. Чтобы вы лучше понимали, что такое микротени, взгляните на картинку ниже:
Если удалить эти тени с карты альбедо, то игровой движок их реконструировать не сможет – независимо от того, используете ли вы отдельную карту для AO или нет. AO-карты никак не повлияют на текстуру, если поверхность находится под освещением, т.к. они работают, только если поверхность покрыта тенями. Так что эти микротени нужно добавлять на карты альбедо. Некоторые люди зачем-то удаляют эти тени, затем используют отдельную AO-карту, а затем объединяют ее с картой альбедо в редакторе материалов, но я не понимаю, зачем удалять тени, а затем снова их добавлять ценой дополнительной AO-карты.
Эти микротени представляют собой трещины и дыры в поверхности, и они, как правило, всегда темные, потому что свет от них почти не отражается. Но есть один момент. Если у вас за отражение отвечает одно и то же значение, это значит, что вся поверхность отражает свет одинаково, и это, если принять во внимание пример выше, неправильно, потому что от этих дыр и трещин света практически не отражается, поэтому значение отражения для этих дыр и трещин должно быть меньше, чем для плоской поверхности.
Ниже – пара фотографий, демонстрирующих разницу между обычной текстурой для камня и текстурой, куда я добавил изменения, о которых рассказал выше.
А вот то же самое, но если смотреть только через буфер отражений.
Что касается сеток для камней, то я, как правило, не экономлю треугольники, и стараюсь придерживаться уровня примерно в 30 тысяч треугольников на камень – это очень помогает погружению, если игрок вдруг окажется рядом с таким камнем. Кроме того, я использую, как правило, 4 или 5 уровней детализации – чтобы при перемещении игрока объект не дергался. Кроме того, я стараюсь максимально снизить количество треугольников на уровень детализации, при этом сохраняя форму, поэтому у меня не получается так, что на 0-ом уровне детализации я вижу камень, а на 5-ом – базуку.
Прощу прощения, но этот раздел обещает быть большим. Системам для работы с PBR-материалами нужно физическое освещение. Я имею в виду, что мы должны знать, сколько именно света мы проливаем на наши материалы, иначе смысл в использовании PBR для создания реалистичных ландшафтов, по сути, попросту теряется.
Кроме того, после создания карты высот и до перехода к текстурированию/освещению имеет смысл немного пробежаться уровню, чтобы проверить масштаб. Это очень сэкономит вам время.
Следите за тем, чтобы ваши материалы выглядели как надо. Не бойтесь менять материалы (особенно цвета), пока не достигнете полной гармонии.
Делая окружение для открытых локаций, станьте первым, кто по нему пройдется, станьте первым, кто будет судить, подходит ли эта локация хотя бы для 2-3 разных типов геймплея или нет. Будьте первым, кто позаботится о производительности и оптимизации. Упростите работу другим.
Обращайте внимание на мелкую детализацию, не делайте исключений. Камни, трава, галька, горы – не забывайте ни о чем. Не перескакивайте с одного объекта на другой, пока хорошенько его не доделаете. Один хорошо сделанный световой меч заслуживает больше уважения, чем 10 посредственных локаций.
Создавайте модульные функции, которые можно будет использовать повторно. Это здорово экономит время и усилия, попутно улучшая качество.
Не бойтесь делать по несколько проходов. Делайте одну версию, потом еще и еще, пока не поймете, что да – это оно! И учитесь у тех, кто критикует вашу работу.
Если у вас есть какие-то вопросы, можете смело писать мне. Но заранее извиняюсь, если с ответом будут задержки. Бывает, я работаю по 16 часов подряд, забывая даже почесать макушку.
Читайте также: