GameDev 3.0. Этап 3.2. Ассеты. Урок 14. PCG, ч.2
Стартовая страница
- Демонстрация первой системы
- Настройка ландшафта для корректной работы системы
- Point Filter и как получать данные ландшафта
- Transform Points и Density Filter для доработки объектов
- Нода Bounds Modifier
- Нода Self Pruning
- Доработка системы и второй ветви системы
- Финальная доработка системы
- Второй плагин, создание ВР, работа с PCG
- Mesh Sampler и Get Actor Property
- Подключение Density Filter к нашему ВР
- Как поставить лимит значений в нашем ВР
- Доработка системы
- Трава не принимает размер объекта адаптируется под его размер. Как сделать, чтобы объекты росли вверх, а не в стороны
- Заключение
Демонстрация первой системы
В данном уроке создадим несколько систем на основе PCG. И первое из них - это то, что на картинке:
Как мы видим, есть 2 ассета точек, которые мы потом можем заменить на статик мэши. Более мелкие точки спамятся на 2 областях, кроме впадины, и они никак не могут спавниться на дне реки/ущелья. А большие точки начинают спавниться на определенной высоте. Так что сейчас будем создавать PCG систему, в которой большие точки будут спавниться на определенной высоте, а ниже - мелкие объекты.
↑ Вверх
Настройка ландшафта для корректной работы системы
Для начала очень важно, чтобы у нашего ландшафта Component Subsections был равен 1 х 1:
Если это будет 2 х 2, то это не будет работать корректно, поэтому, когда заходим в режим Landscape при создании ландшафта обязательно выбираем 1 х 1, чтобы все работало корректно:
↑ Вверх
Point Filter и как получать данные ландшафта
Создадим в папке PCG новый PCG-граф, назовем ее PCG_SpawnByHeight. Откроем ее. Как и ранее, уже есть ноды Input и Output, последняя нам не нужна, мы ее отодвинем.
В первую очередь создадим ноду Surface Sampler, с которой мы уже знакомы, подключим ее к Input -> Landscape:
Далее добавим новую ноду Point Filter, которая будет фильтровать информацию точек относительно какого-то из значений с ландшафта:
К примеру, если мы выберем ноду Surface Sampler и нажмем на клавишу А, либо ПКМ -> Inspect, предварительно закинув PCG_SpawnByHeight в уровень и нажав в Details справа кнопку Generate, выбрать PCG_SpawnByHeight (selected) / PCG component:
Это позиции всех точек, нас интересует Position Z, у Point Filter в Target Attribute по умолчанию стоит Density:
И вместо него нам надо вписать Position.Z (т.к. это векторное значение, поэтому пишем через точку), поставим галочку на Use Constant Threshold, Type выберем Float, Float Value напишем 25 (зависит от конкретного случая, ландшафта, ставим то, что больше подходит):
И после этого, выбрав ноду Surface Sampler, нажмем на клавишу А, чтобы выключить эту информацию. Соединим ноду Surface Sampler с Point Filter:
Мы видим, что у Point Filter есть два выхода: InsideFilter и OutsideFilter. В InsideFilter будет происходить в рамках того, что написали, то есть если эти точки находятся выше, чем 25 юнитов, то это идет по этой ветке. OutsideFilter это то, что происходит вне наших рамок, то есть то, что ниже 25.
↑ Вверх
Transform Points и Density Filter для доработки объектов
Для начала пропишем верхнюю ветку. Первая нода, которую добавим, это Transform Points, подключим его к Point Filter -> InsideFilter и включим на ней Debug, Rotation Max по осям X и Y поставим по 5, а по оси Z - 360, Scale Min запишем 0,4, а Scale Max - 1,2:
И мы видим, что у нас появились точки, которые спавнятся выше 25 юнитов:
Вернемся к Surface Sampler и изменим значения:
Теперь у нас больше точек, с которыми мы можем работать:
Далее вызовем ноду Density Filter со значениями 0,7 и 1, и включим на ней Debug:
И теперь точек стало намного меньше:
↑ Вверх
Нода Bounds Modifier
Теперь исключим случаи пересечения этих точек, например, деревьев, чтобы не пересекались друг с другом.
Для этого добавим ноду Bounds Modifier, она дает нам возможность менять коллизию точек, не изменяя их размер. То есть размеры статик мэша будут относительно равны тому, что мы задали в Transform Points, и подключим ноду Bounds Modifier к Density Filter, включим на ней Debug, Bounds Min и Bounds Max поставим по 2, кроме оси Z, там поставим 10, чтобы они были немного продолговаты:
Мы видим, что точки стали длиннее, но они входят друг в друга, также видим, что они растут относительно их поворота к ландшафту, так не должно быть:
Чтобы это исправить, вернемся к Transform Points, поставим галочку на (включим) Absolute Rotation:
Теперь видим, что точки выровнились:
↑ Вверх
Нода Self Pruning
Чтобы исправить пересечение точек, добавим ноду Self Pruning, она вычитает разницу между 2 точками и их зонами пересечения и удаляет те, что пересекаются друг с другом. Включим Debug:
Теперь видим, что лишние точки удалились:
И если мы добавим мэш деревьев, это будет выглядеть натурально.
↑ Вверх
Доработка системы и второй ветви системы
Вернемся к PCG_SpawnByHeight и напишем вторую ветку, для начала прокопируем Point Filter и запишем в Float Value значение меньше, например 5 (зависит от локации):
Еще раз прокопируем Point Filter и в Float Value значение оставим 25, как у самого первого Point Filter, но Operator укажем меньше:
Как это работает? Верхний Point Filter отфильтровал точки выше 25, а то, что ниже их не трогал, теперь нам надо с ними взаимодействовать, поэтому вызываем точки меньше 25, но больше 5.
Далее подключим ноду Transform Points, ставим значения как на картинке снизу, включим Debug:
Видим, что появились новые точки:
Добавим ноду Self Pruning, но если планируется добавить траву, а не кустарники, то это можно пропустить, так как, как уже говорилось выше, эта нода удаляет пересекающиеся точки:
Далее добавим ноду Density Filter со значениями 0,6 и 1,0:
Включим Debug и видим, что точек стало меньше:
Если еще хотим отфильтровать, то можем еще добавить ноду Density Noise, но в данном случае мы ее пропустим.
Обе ветки готовы, далее мы можем кастомизировать и дорабатывать так, как нам удобно.
Но еще на всякий случай добавим ноды Projection, чтобы обезопасить себя, чтобы мэши потом были ровно на ландшафте, не ниже и не выше, и включим на них Debug:
Видим, что "деревья" снова растут криво:
↑ Вверх
Финальная доработка системы
Чтобы это исправить, в Projection, которая отвечает за "деревья", уберем галочку на Project Rotations:
И в конце подключим ноды Static Mesh Spawner:
Хотелось бы уточнить: вся работа с точками должна проходить до Static Mesh Spawner, т.к. эта нода берет все данные до нее и вставляет туда статик мэш. Если после этой ноды мы как-то доработаем точки, то мэши не возьмут оттуда данные.
На этом по первой системе все, переходим ко второй.
↑ Вверх
Второй плагин, создание ВР, работа с PCG
Для создания 2 системы нам надо включить еще одну функцию PCG, для этого включаем еще 1 плагин - Procedural Content Generation Framework Geometry Script Interop и перезагружаем UE:
В нашей папке PCG создаем Blueprint Class -> Actor и назовем BP_SpawnOnMesh. Откроем его и добавим компонент Scene:
Перетащим этот компонент вместо DefaultSceneRoot:
Далее добавим Static Mesh и нажимаем Compile, Save:
Затем заходим в Construction Script и вытащим Static Mesh:
Из Static Mesh вызовем Set Static Mesh, соединим его с Construction Script, на New Mesh нажимаем ПКМ -> Promote to Variable и переменную назовем Mesh, нажмем глазик, чтобы можно было менять мэш извне:
Создадим новую переменную, назовем ее Falloff, тип укажем Float:
Добавим еще одну переменную, назовем ее Prune, тип так же Float, и нажмем глазики на обеих переменных:
Теперь в мэш по умолчанию поставим сферу Sphere:
Далее в папке PCG создаем новый PCG Graph и назовем ее PCG_Grass.
Вернемся обратно в блюпринт BP_SpawnOnMesh, добавим с помощью кнопки Add компонент PCG:
И в нем выберем наш PCG_Grass:
↑ Вверх
Mesh Sampler и Get Actor Property
Идем обратно в папку PCG, откроем наш PCG_Grass, и добавим ноду Mesh Sampler. Раньше у нас этой ноды не было, т.к. она появляется только тогда, когда мы включим 2 плагин:
Нам она нужна, так как здесь имеется значение Static Mesh, которую мы можем менять динамично:
Для этого вызовем ноду Get Actor Property, подключим ее к Mesh Sampler -> Static Mesh, в настройках поменяем имя на Mesh и включим Debug:
↑ Вверх
Подключение Density Filter к нашему ВР
Закинем наш блюпринт BP_SpawnOnMesh в уровень и видим, сфера не привязана к точкам:
Исправим это. Переходим в PCG_Grass. Вызовем ноду Copy Points и подключим ее с Mesh Sampler:
Добавим еще ноду Get Actor Data, подключим ее к Copy Points -> Target, включим Debug на Copy Points:
Для Get Actor Data переключим режим Mode на Get Single Point:
Сохраним, и теперь видим, что точки находятся на поверхности сферы и они следуют за нашей сферой:
Но теперь видим, что у точек одинаковый размер плотности, сейчас исправим, вернувшись в PCG_Grass и здесь добавим ноды Density Noise и Density Filter, значения пока оставим по умолчанию, переключим Debug и сохраним:
Теперь видим, что точки вразброс:
Но мы хотим контролировать это значение через блюпринт, для этого в PCG_Grass мы берем ноду Get Actor Property и в Property Name напишем Prune, точно так же, как и назвали переменную выше, соединим эту ноду с Density Filter -> Lower Bound:
И мы видим, что все наши точки вернулись:
Но если в Prune мы поставим значение, например, 0,8 - точек станет меньше, тем самым мы контролируем эффект прямо с вьюпорта:
Но мы хотим контролировать этот эффект сверху вниз, например, это будет камень, на которой сверху трава/мох, а снизу нет. Для того, чтобы добиться этого эффекта мы вернемся в PCG_Grass и добавим ноду Normal To Density, подключаем его и переключим к ней Debug:
И теперь мы видим, что точки внизу стали темнее, чем те точки, что вверху:
И если мы добавим Density Filter, подключим ее к Normal To Density, переключим на нее Debug:
То мы увидим, что темные точки исчезли:
Для того, чтобы контролировать это с вьюпорта, добавим еще один Get Actor Property и в Property Name напишем Falloff, точно так же, как и назвали переменную выше, соединим эту ноду с Density Filter -> Lower Bound:
Теперь можем настраивать прямо с вьюпорта, где 0 - все точки на месте, а 1 - нет ни одной точки:
↑ Вверх
Как поставить лимит значений в нашем ВР
Теперь сделаем так, чтобы значения были ровно между 0 и 1, чтобы не превышало и нельзя было бы уходить в минусовые значения.
Вернемся в BP_SpawnOnMesh, выберем переменную Falloff и в Details в Slider Range и Value Range поставим значения от 0 к 1, по умолчанию поставим значение 0,5:
Теперь то же самое сделаем с Prune, в Details в Slider Range и Value Range поставим значения от 0 к 1, по умолчанию поставим значение 0,5:
↑ Вверх
Доработка системы
Теперь зайдем в наш PCG_Grass. Добавим ноду Transform Points, подключим ее к Density Filter, поставим значения Rotation Min по осям X и Y -3, Rotation Max по осям X и Y = 3, а Z поставим 360. Scale Min укажем 0.4, Scale Max поставим 1:
Значения конечно же могут варьироваться.
Теперь вызовем ноду Static Mesh Spawner, который будет спавнить траву или мох, который нам нужен поверх объекта, отключим Debug, нажмем Force Regen, сохранимся:
Выберем для примера какой-нибудь камень:
И в PCG_Grass в Static Mesh Spawner выберем какую-нибудь траву:
И увидим, что камень покрылся травой, с помощью переменных можем регулировать густоту, частоту травы:
↑ Вверх
Трава не принимает размер объекта адаптируется под его размер. Как сделать, чтобы объекты росли вверх, а не в стороны
Но, допустим, что у нас объект мелкий, и мы хотим его сделать больше, мы можем заскейлить, но при этом трава будет скейлиться тоже, что создаст неестественный эффект, т.к. трава будет огромная:
Для того, чтобы это исправить, в PCG_Grass в Transform Points поставим галочку на Absolute Scale:
И теперь при увеличении объекта трава остается своих размеров:
Также можем исправить, чтобы трава росла только вверх, для этого поставим галочку на Absolute Rotation:
↑ Вверх
Заключение
У нас есть несколько PCG и несколько блюпринтов:
Используя их, можем построить свои локации