Учебник по процедурному размещению объектов в Unreal Engine 4.

Автор: Кристиан Спаркс

Основатель Smallheart Studios. Работаем над Woodbound.

Это руководство было написано для пользователей с начальным и средним уровнем знакомства со сценариями Blueprints в Unreal Engine 4 и создано в версии 4.16.

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

Актер использует логическую «кнопку» для процедурного появления в определенном количестве простых скальных ячеек в мире с определяемым максимальным расстоянием появления от позиции актера, а также значениями расстояния между камнями и минимальным / максимальным равномерным масштабированием каждого из них. пример. Есть еще одна логическая «кнопка» для очистки существующих экземпляров.

Я использовал серию компонентов Hierarchical Instanced Static Mesh для управления каталогизацией сеток (6 в моем случае, просто для разнообразия сеток, я добавил несколько процедурных камней из Blender, вы можете найти подробности об этом процессе здесь) и с несколько довольно незамысловатых проверок, актер работает неплохо.

Строительный сценарий

Итак, первое, что я сделал, - это настроил функциональность «кнопки» с помощью редактируемой логической переменной под названием «Clear Rocks». Его значение по умолчанию - false, и оно используется (как показано на изображении выше) для простого воссоздания сценария без вызова каких-либо функций создания HISM, эффективно «сбрасывая» актера, если уже были созданы какие-либо экземпляры.

Оттуда я добавил все свои компоненты HISM, которые я добавил и назвал в переменную массива, для более удобного использования в сценарии.

Затем мы проверяем, создаем ли мы какие-либо сетки, создав еще одну логическую «кнопку», используя редактируемую логическую переменную «Spawn Rocks.

Если Spawn Rocks истинно, он выполнит функциональность кнопки, а затем выполнит и запустит созданную мной пользовательскую функцию Spawn Rocks (подробно описанную ниже) с помощью узла For Loop для контроля количества вызовов этой функции. Как только этот цикл будет завершен, будет отправлено сообщение отладки, в котором вы узнаете, что он завершен.

Пользовательская функция Spawn Rocks (Часть 1)

Эта функция выполняет несколько шагов, чтобы добавить экземпляры к компонентам HISM, эффективно порождая их в мире. Первый шаг - это случайным образом выбрать из множества актеров HISM, чтобы решить, какая сетка появится в мире. (Каждый HISM содержит только один статический тип сетки, поэтому для разнообразия сеток было добавлено несколько компонентов HISM.) Я использовал простое случайное целое число в узле Range с минимальным значением 0 (минимальное значение в массиве HISM) и 5 ​​(максимальное значение в моем массиве HISM, ваше может отличаться в зависимости от того, сколько различных форм сетки вы хотите создать.) Затем я создал нередактируемую переменную для более удобного хранения случайного целочисленного значения, просто чтобы я не понял провода пересеклись позже, чтобы мне было легче разделить части этой функции для этого урока.

Оттуда нам нужно создать еще две функции. Начнем со случайного преобразования (редактируется).

Случайное преобразование (редактируется)

Я как бы работал в обратном направлении над этим: я добавил узел возврата с добавленным выводом переменного вывода Transform. Затем я отодвинул эту булавку Transform и добавил узел Make Transform. Таким образом, я мог показать расположение, поворот и масштаб экземпляров меша.

Для местоположения я использовал редактируемую переменную с плавающей запятой под названием Max Spawn Distance from Origin, используя это базовое значение в качестве минимального ввода для узла Random Float in Range, и его отрицательный аналог (полученный путем умножения числа с плавающей запятой на -1) в качестве максимального input. * Я использовал тот же подход 3 раза, по одному разу для каждого ввода в ноде Make Vector, который передает эту информацию о местоположении на входной контакт Location моего узла make transform.

* Примечание автора: когда я писал это руководство, я понял, что построил эту функцию задом наперед, хотя она отлично работает таким образом. Тем не менее, я вернусь и исправлю эту ошибку для ясности, когда вернусь к своему компьютеру разработки.

Для вращения я просто использовал узел Random Rotator, подключенный к входному контакту Rotation узла make transform, с Roll, отмеченным как True, чтобы вращение применялось ко всем осям.

Для шкалы я использовал узел Vector * Float, масштабируя плоскую шкалу 1x1x1 случайным поплавком в диапазоне, минимальный и максимальный диапазон которого определяется редактируемыми переменными Min Rock Scale и Max Rock Scale. Это масштабирует камни равномерно по всем осям.

После того, как ваш вывод Make Transform будет построен со всей необходимой информацией, вы можете перетащить вывод вывода во входной вывод T на узле Return этой функции, а затем убедиться, что в атрибутах функции эта конкретная функция отмечена как , «Pure», и мы можем сохранить нашу работу и перейти к написанию последней пользовательской функции, которая нам понадобится для этого актера, под названием «Rock-Rock Distance».

Рок-Рок Расстояние

Первое, что мы собираемся сделать в этой функции, - это добавить узел возврата, а затем добавить выводы переменных T In и T Out Transform к узлам ввода и возврата, соответственно, этой функции.

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

Следующее делегирование события в этом сценарии - это узел ветвления, но еще многое предстоит определить в том, что определяет значение «да / нет» для ветки, поэтому я начну слева и буду двигаться вправо. Первое, что мы хотим сделать, это получить нашу переменную HISM Array, которую мы заполнили в сценарии построения. Нам нужно использовать узел Get (A Copy), чтобы получить ранее использованный компонент HISM в нашем цикле, чтобы найти информацию о преобразовании его самой последней записи. Итак, в вашем узле Get (A Copy) во входных данных индекса используйте нередактируемую целочисленную переменную и назовите ее как-то вроде «Last Used HISM». Эта переменная на самом деле еще не была установлена, и по умолчанию она будет равна 0, что нормально, поскольку первый экземпляр порождения будет использовать этот 0 для поиска преобразования для сравнения, чтобы убедиться, что там ничего нет, а затем продолжить создание , так как ему не нужно беспокоиться о нересте слишком близко к другому экземпляру.

В случае экземпляров, порождаемых после первого актера, нам нужно получить преобразование последнего экземпляра порождения для сравнения местоположения, поэтому мы перетащим вывод вывода нашего узла Get (A Copy) и создадим Получить узел преобразования экземпляра. Убедитесь, что установлен флажок "Мировое пространство", поскольку мы сравниваем глобальные местоположения, а не относительные. Поскольку нам нужно определить, с каким экземпляром мы сравниваем информацию преобразования, нам также необходимо создать узел Get Instance Count из нашего узла Get (A Copy), который будет возвращать максимальное значение (или самый последний экземпляр) данного HISM. компонент, который был активен последним.

Теперь, когда у нас есть, с каким экземпляром мы собираемся взвесить нашу дифференциальную проверку расстояния появления, пришло время извлечь местоположение экземпляра из его преобразования, а также местоположение нашего последнего случайно сгенерированного преобразования, сохраненного ранее в этом в переменной Comparative Transform. Итак, мы собираемся разбить преобразования, получить местоположения, вычесть их друг из друга (местоположение преобразования предыдущего экземпляра - местоположение сравнительного преобразования) и получить длину вектора. Затем нам нужно сравнить это значение длины с редактируемой плавающей переменной Min Spawn Distance Between Instances и проверить, больше ли оно или равно этому определяемому значению. Если это так, узел ветвления, который возвращает возвращаемое значение для узла ≥, будет двигаться вперед с созданием экземпляра, поскольку определено, что последнее место появления находится достаточно далеко от последнего созданного места появления. Если это не так, ветвь запустится в узел Set для редактируемой целочисленной переменной # of Rocks to Spawn, где значение - это количество камней для создания, вычтенное на 1, чтобы сценарий знал, что он не создал успешно mesh в этом цикле, и что ему нужно вернуться и попробовать еще раз с другим случайным преобразованием.

Пользовательская функция Spawn Rocks (Часть 2)

Хорошо, теперь, когда мы создали другие наши пользовательские функции, пора все подключить и протестировать. Вы захотите снова использовать узел Get (A Copy), чтобы выяснить, какой компонент HISM (или форма сетки) будет использоваться, используя значение случайного целого числа Spawn Rocks, которое мы сохранили пару шагов назад в качестве значения индекса, и затем из этого узла Get мы создадим узел Add Instance World Space, используя значение T Out из нашей функции Rock-Rock Distance в качестве значения World Transform для создаваемого экземпляра. После этого нам просто нужно снова установить целочисленное значение Last Used HISM, полученное из значения Spawn Rocks Random Integer, чтобы в следующем цикле скрипт знал, с каким компонентом HISM сравнивать для проверки расстояния.

Вывод

И это все! Сохраните свою работу и протестируйте актера в своем редакторе. Будьте осторожны, сколько экземпляров вы создаете, и обратите внимание, что на моей машине, на которой работают i5 4670k и 980ti, загрузка всего после 20k экземпляров займет пару секунд. Однако после загрузки экземпляров я все еще получаю постоянные 120 кадров в секунду благодаря отличной пакетной обработке и уменьшению количества вызовов отрисовки актором HISM.

Я повторно добавлю изображения из этого руководства в том порядке, в котором они должны быть выполнены (по крайней мере, на мой взгляд, если вы хотите попробовать его в другом порядке, я не вижу никакого вреда), чтобы вы могли просмотреть свои функций и макетов и убедитесь, что все совпадает. Если вы просмотрели свои сценарии и что-то по-прежнему не работает, напишите мне на [email protected] и дайте мне знать, и я вместе с вами посмотрю.

Спасибо за чтение и удачной разработки!