EN RU

Разброс растительности Megascans в Solaris

2026-10-27

Houdini Solaris Karma MaterialX USD

Разброс растительности Megascans в Solaris

Пошаговая техника: мультивариантные USD-компонент-ассеты, разбросанные по точкам на хайтфилде и отрендеренные в Karma. Написано для Houdini 22 (Solaris / MaterialX / Karma XPU).

0. Обзор

Техника состоит из четырёх независимых частей. Каждый тип растительности (трава, кусты и т.д.) получает свою копию этих частей, так что типы можно настраивать, отключать или рендерить по отдельности.

SOP  /obj/<terrain>                      LOP  /stage
-------------------                      ----------------------------------------
heightfield (слои: height, mask)         BUILD_<asset>  (subnet, пишет <asset>.usd)
  -> heightfield_scatter                 PROTO_<asset>  (subnet, 8 прототипов)
  -> patches (wrangle)                        |
  -> attribs (wrangle)                        | input 2
  -> POINTS_<asset> (null) ----- SOP Path --> <asset> (PointInstancer)
                                         ^ input 1
                     scene -> ... -> предыдущий instancer

1. Именование и пути

Плейсхолдер Значение Пример
<asset> Короткое имя ассета в snake_case wild_grass
<src_dir> Скачанная папка Megascans wild_grass_abc123_mid
<mesh_prefix> Имя FBX до _VarX_LODn Wild_Grass_abc123_Mid_abc123
<tex_prefix> Имя текстуры до суффикса карты Wild_Grass_abc123_Mid_2K
<terrain> SOP-объект с хайтфилдом /obj/terrain
Элемент Имя / путь
Исходные файлы $HIP/models/plants/<src_dir>/
Subnet сборки ассета (LOP) BUILD_<asset>
Экспортированный ассет $HIP/usd/assets/<asset>/<asset>.usd
Subnet прототипов (LOP) PROTO_<asset>
Выход разброса (SOP) /obj/<terrain>/POINTS_<asset>
Нода / прим инстансера <asset> / /vegetation/<asset>
Варианты геометрии VarA ... VarH (должны совпадать с именами вариантов Megascans)

Совет. Держи каждую сборку BUILD_ и PROTO_ внутри своего subnet. Имена нод должны быть уникальны в пределах сети, а VarA...VarH будут переиспользоваться для каждого ассета. Внутри subnet имена локальные, поэтому ничего не переименуется автоматически в VarA1.

2. Сборка USD-ассета (BUILD_)

В /stage создай Subnet с именем BUILD_<asset>, зайди внутрь (I) и брось Component Builder. Переименуй ноду Component Output в <asset> (её Root Prim равен /$OS, так что прим и файл получат имя ноды).

2.1 Геометрия: один Component Geometry на вариант

Переименуй ноду Component Geometry в VarA и зайди внутрь. Используй имя ноды в путях к файлам, чтобы дубликаты требовали только переименования. ../../.. разрешается как file -> geo -> sopnet -> VarA.

file1 -> выход default (рендер-геометрия):

$HIP/models/plants/<src_dir>/<mesh_prefix>_`opname("../../..")`_LOD1.fbx

file2 -> выход proxy (только вьюпорт, LOD3 у Megascans обычно биллборд):

$HIP/models/plants/<src_dir>/<mesh_prefix>_`opname("../../..")`_LOD3.fbx

2.2 Объединение вариантов

Подключи все восемь в Component Geometry Variants, а его выход — в input 1 ноды Component Material.

Внимание. Используй именно Component Geometry Variants, а не обычный Merge. Merge наслаивает все варианты на один и тот же прим, из-за чего у ассета не создаётся набор вариантов и все прототипы выглядят одинаково.

2.3 Материал (MaterialX, внутри Material Library)

Подключи Material Library в input 2 ноды Component Material. Внутри создай MtlX Standard Surface с именем <asset>_mtl и по одному MtlX Image на каждую карту. В каждое поле File впиши полный путь:

$HIP/models/plants/<src_dir>/<tex_prefix>_<Map>.jpg
Карта Тип File Color Space Подключить к
BaseColor Color sRGB - Texture base_color
Roughness Float Raw specular_roughness
Normal Vector Raw MtlX Normal Map -> normal
Opacity Float Raw opacity
Translucency Color sRGB - Texture subsurface_color

Настройки Standard Surface:

Совет. Всегда задавай File Color Space явно. Пустое поле заставляет Houdini угадывать, что может затемнить цвета. Никогда не выбирай Display- или Output-трансформ для текстур.

2.4 Назначение и экспорт

3. Прототипы (PROTO_)

Создай Subnet PROTO_<asset>. Внутри собери по одной паре на вариант:

Reference LOP, нода с именем VarA:

Reference File : $HIP/usd/assets/<asset>/<asset>.usd
Primitive Path : /prototypes/$OS
Reference Prim : default (Component Output уже задал defaultPrim)

Set Variant LOP сразу за ней (вставь точно как есть, выражение читает имя входной ноды):

Primitives  : /prototypes/`opinput(".", 0)`
Variant Set : geo
Variant Name: `opinput(".", 0)`

4. Разброс точек (SOP, /obj/)

4.1 Маска (опционально): инвертировать и оставить только низины

Чтобы разместить второй тип растений там, где нет первого, и только на ровной земле, ответвись от размытой маски Volume Wrangle с именем mask_floor_inv и используй его как вход mask нового разброса. @mask и @height привязываются к слоям хайтфилда по имени.

// инвертируем существующую маску
float inv = 1.0 - @mask;
// 1 на ровной земле, затухает к 0 между h_min и h_max
float floor_mask = 1.0 - smooth(chf("h_min"), chf("h_max"), @height);
@mask = clamp(inv * floor_mask, 0, 1);

Подбирай h_min (верх ровной зоны) и h_max (где маска доходит до 0), отображая ноду: маска рисуется красным во вьюпорте. Больший зазор даёт более мягкий переход на склоны. Убери 1.0 - в первой строке, чтобы сохранить исходную маску вместо инвертирования.

4.2 HeightField Scatter

Параметр Значение Зачем
Scatter Method By Coverage using Mask Layer Разбрасывать только там, где есть маска
Coverage 1 Плотность дальше задаётся через Outer Radius
Outer Radius 0.15-0.3 трава, 0.3-1 кусты Меньше = плотнее
Relax Points выкл Relax + Self Overlap дают заметную ровную сетку
Keep Incoming Terrain выкл Иначе точки объёма хайтфилда (в 0,0,0) проходят дальше и получают инстансы

4.3 Patches wrangle (Attribute Wrangle, Points)

// крупные пятна растительности
float n = noise(@P * chf("freq") + chf("offset"));
n = fit(n, chf("lo"), chf("hi"), 0, 1);
// чем ниже шум, тем больше точек удаляется
if (rand(@ptnum + 77) > n * chf("density"))
    removepoint(0, @ptnum);
Параметр Старт Эффект
freq 0.005 Размер пятен. Ниже = крупнее пятна (0.005 ~ 200 м, 0.02 ~ 50 м, 0.1 = мелкая рябь).
offset 0 Сдвигает рисунок шума. Задавай разное значение для каждого типа растений, чтобы их пятна не совпадали.
lo / hi 0.35 / 0.65 Контраст пятен. Узкий диапазон = жёсткие края; широкий = мягкие. Оба вверх = больше голой земли; оба вниз = плотнее в целом.
density 1 Глобальный множитель выживания внутри пятен. 0.5 прореживает даже самые плотные зоны вдвое.

4.4 Attributes wrangle (Attribute Wrangle, Points)

float seed = chf("seed");
// вариант как СТРОКА, совпадающая с именами прототипов
string vars[] = {"VarA","VarB","VarC","VarD","VarE","VarF","VarG","VarH"};
s@variant = vars[int(rand(@ptnum + seed) * len(vars))];
// масштаб
f@pscale = fit01(rand(@ptnum + seed + 1), chf("scale_min"), chf("scale_max"));
// случайный поворот по Y + лёгкий наклон
float yaw = rand(@ptnum + seed + 2) * 2 * PI;
float tilt = radians(fit01(rand(@ptnum + seed + 3), -chf("max_tilt"), chf("max_tilt")));
p@orient = qmultiply(quaternion(yaw, {0,1,0}), quaternion(tilt, {1,0,0}));

Нажми кнопку Create spare parameters. Стартовые значения: scale_min 0.4-0.5, scale_max 1.4-1.6, max_tilt 5 (кусты) до 10 (трава). Опционально, более крупные растения внутри плотных пятен (добавь после строки с pscale):

f@pscale *= fit(noise(@P * chf("freq")), 0.35, 0.65, 0.6, 1.3);

Заверши цепочку нодой Null с именем POINTS_<asset>.

Совет. Если у самого разброса есть Variability (диапазон масштаба), pscale из wrangle перезапишет его. Используй что-то одно.

5. PointInstancer (LOP)

Один PointInstancer на каждый тип растений, соединённые цепочкой друг за другом в основном потоке.

Параметр Значение
Имя ноды <asset>
Input 1 Основная сцена (террейн, камни, предыдущий инстансер)
Input 2 PROTO_<asset>
Primitive Path /vegetation/<asset> (держит всю растительность под одной веткой)
Prototype Source Second Input
Primitives /prototypes/* (надёжнее дефолтного lopinputprims через subnet)
Import SOP Points > SOP Source External SOP
SOP Path /obj/<terrain>/POINTS_<asset> (без слеша в конце)
Prototype Assignment > Prototype Index String Attribute, атрибут variant

Ориентация (orient) и масштаб (pscale) подхватываются автоматически. Предупреждения (!) на скопированных прототипах в Scene Graph Tree — это уведомления об иерархии kind, на рендер они не влияют.

6. Свет и заметки по рендеру

7. Траблшутинг

Симптом Причина / решение
Unable to find SOP attribute: variant Нет s@variant на точках, или он int. Используй строковую версию wrangle.
Все инстансы выглядят одинаково Варианты объединены через Merge вместо Component Geometry Variants; или прототипы не перезагружены после Save to Disk.
Кластер инстансов в начале координат Включён Keep Incoming Terrain в HeightField Scatter.
Растения выстроены сеткой Включён Relax Points.
Слишком редко / слишком густо Outer Radius в разбросе, затем density в patches wrangle.
Листья полупрозрачные Карта Opacity не задана как Float, или рендер не сошёлся. Опционально отсеки opacity через MtlX Range (0.45-0.55, clamp).
Растения лежат или гигантские Поправь Transform внутри Component Geometry (scale 0.01, rotate X -90), пересохрани.
Приходит только один прототип output0 subnet PROTO_ подключён к одной ноде Set Variant вместо Merge.
Нода переименована в VarA1 Конфликт имён в одной сети. Собирай внутри subnet BUILD_ / PROTO_.
Цвета слишком тёмные / выцветшие File Color Space пустой или неверный: цветовые карты sRGB - Texture, карты данных Raw.

8. Чек-лист для нового типа растений

  1. Скачай набор Megascans в $HIP/models/plants/<src_dir>/.
  2. BUILD_<asset>: Component Builder, VarA с путями через opname, проверь масштаб/оси, продублируй до VarH, Component Geometry Variants.
  3. Материал: 5 MtlX Image с явными цветовыми пространствами, Opacity как Float, Thin Walled, Subsurface.
  4. Переименуй выход в <asset>, Save to Disk, проверь набор вариантов geo.
  5. PROTO_<asset>: Reference + Set Variant x8, Merge, подключи к output0.
  6. SOP: маска (опционально инверт/низины), разброс (Relax выкл, Keep Terrain выкл), patches wrangle с новым offset, attributes wrangle, POINTS_<asset>.
  7. PointInstancer <asset> в цепочке за предыдущим, String Attribute variant.
  8. Проверка рендера в Karma; настрой плотность, пятна и просвечивание.