Экспорт иерархии FBX (PIVOTS) из Houdini в Unity
Экспорт из Houdini в Unity с сохранением аккуратной иерархии и корректных пивотов — задача непростая. В этом гайде показано, как построить пути, создать явные pivot‑точки, «поригать» их и экспортировать через FBX Character Output так, чтобы каждый контрол в Unity оказался под своим собственным пивотом. Вы увидите полный сетап нод, частые ловушки и переиспользуемые Digital Assets, которые ускорят будущие экспорты.
Jul 21, 2024
Одна из особенностей работы в Houdini — сложные задачи делать легко, а простые могут оказаться неожиданно трудными. Я заметил, что многие в сети сталкивались с проблемами экспорта 3D‑объектов из Houdini в игровые движки с сохранением иерархии игровых объектов/трансформов и пивотов. У меня была та же история, и форум Houdini очень помог. Покажу свой сетап и поделюсь им! (Если знаете более удобную схему — будет круто, если поделитесь!)
Начнём со следующей сцены. У нас есть 3D‑модель: корпус небольшого устройства, в состав которого входят экран, ручка (knob) и кнопка. Все элементы размещены на корпусе с помощью нод MatchSize, которые обеспечивают точное позиционирование всех элементов на фронтальной панели устройства. Houdini позволяет создавать полностью параметрические объекты, но в этом материале мы сосредоточимся на переносе 3D‑модели в Unity и настройке пивотов.
Вот исходный сетап.
Одна из первых особенностей Houdini, к которой сложно привыкнуть после 3ds Max, Blender и других 3D‑редакторов: в таком сетапе нет привычных пивотов/трансформов и иерархии. Мы видим набор объектов, созданных с определёнными настройками и затем расположенных относительно друг друга, но это ещё не иерархия. Что будет, если экспортировать эту модель «как есть» в Unity? Вы получите один сплошной меш. (Для экспорта используем ноду ROP FBX OUTPUT.)
Очевидно, нас это не устраивает. А если нам нужно, чтобы органы управления были отдельными, физически раздельными объектами? Экспортировать объекты по отдельности тоже не выход — придётся вручную собирать всю иерархию уже в движке, чего хотелось бы избежать. Что делать? Если точное положение пивотов объектов нам не критично, можно воспользоваться опцией Build Hierarchy from Path Attribute.
Мы зададим эти пути для каждой части. Для этого можно добавить перед каждой моделью Attribute Create, выбрать тип данных string и указать пути следующим образом:
- для корпуса:
root/ - для кнопки:
root/button - для экрана:
root/screen - для ручки:
root/knob
Результатом экспорта такой иерархии будет корпус устройства как отдельный объект, к которому дочерними пойдут ручка, экран и кнопка. Уже лучше, но всё ещё не идеально. Пивоты объектов находятся в нуле. Первое, что приходит в голову, — использовать MergePacked или Pack и выбрать в них pivot как Centroid. Но что, если нам нужен полный контроль над сетапом?
Для этого сделаем следующее: создадим пивоты, подготовим риг и экспортируем всё это в Unity.
Начнём с пивотов. Мы создадим точки в местах, где хотим «подцепить» наши элементы. Точки будут размещены в центре оснований органов управления с помощью MatchSize. Затем объединим точки, которые будут служить нашими пивотами, с самими 3D‑объектами, но на этот раз через ноду mergePacked (не забудьте в настройках выбрать Pivot как Centroid). В итоге у нас есть корпус, 3 пивота и 3 элемента управления.
Это уже весьма неплохо — остаётся добавить иерархию и экспортировать всё. Подготовим риг:
Что здесь происходит:
С помощью RigDoctor и RigStashPose инициализируем матрицы трансформаций и записываем их в атрибуты точек.
Переносим имя «детали» как атрибут точки из названий моделей.
С помощью AttachCaptureGeo и CapturePackedGeo готовим джойнты и геометрию к ригу.
(Не переживайте, ниже я приложил файл с Digital Asset для удобства.)
Нам осталось настроить иерархию и всё экспортировать.
Добавьте ноду ParentJoints и задайте следующую иерархию:
- button — внутри пивота button
- knob — внутри пивота knob
- screen — внутри пивота screen
- все пивоты — внутри корпуса устройства
Далее добавьте ноду Blast, чтобы удалить лишнюю геометрию (пивоты — это точки, но они нам не нужны; нам нужен пустой transform).
А чтобы сохранить весь этот сетап, используем FBX Character Output.
Посмотрим, что получилось в Unity.
Теперь каждый объект находится внутри своего пивота, а пивот — внутри корневого объекта, которым является корпус устройства.
Сам конфиг выглядит довольно громоздко, не так ли? Это потому, что, в отличие от типичных 3D‑редакторов с заданной иерархией объектов, здесь каждый элемент — самостоятельный 3D‑объект, и иерархию нам приходится собирать самим. Но однажды настроив, мы можем сохранить соответствующий нод и переиспользовать его. Такой подход позволяет экспериментировать с иерархией сколько угодно, создавая разные конфиги под разные задачи.
Нужен цельный «болванчик»? Не создавайте иерархию вовсе. Нужно «вшить» экран в объект? Просто уберите часть иерархии. И всё это — полностью управляемо на каждом этапе, с возможностью иметь пресеты, которые можно экспортировать и в другие FBX‑файлы. Кроме того, если внезапно понадобятся меши для коллизий, их можно добавить в иерархию на любом этапе моделинга, а затем уже на стороне экспортера в Unity обработать соответствующие объекты и создать MeshCollider и т. п.
Давайте причешем конфиг, упакуем всё, что относится к FBX‑экспорту, в небольшой Digital Asset — и больше никогда не возвращаться к этой головной боли:
Таким образом, при экспорте в FBX для других движков мы можем полностью контролировать пивоты. И хотя это Character Exporter, бояться появления SkinnedMeshRenderer не нужно: если веса костей везде равны 1, Houdini оптимизирует результат и экспортирует обычный меш. То есть геометрии ничто не угрожает.
Ниже я прикладываю все тестовые ассеты и сцену (так как в примере использовались проприетарные модели, все 3D‑модели здесь заменены на упрощённые, но суть остаётся той же). В комплект входят 3 Digital Asset: для создания пивотов, подготовки к ригу и экспорта модели в FBX.
Спасибо за внимание — и пусть ваши пивоты всегда оказываются там, где вы их задумали!
https://drive.google.com/file/d/1dpCIN3VTlniNAPwFcS6dT5mdrKndfIe3/view?usp=sharing











