GLB или FBX: какой формат отдавать игровому движку

Что на самом деле переносят glTF/GLB и FBX, где каждый тихо теряет данные и какой формат отдавать Unity, Unreal, Godot, Blender и вебу.

Вид с высоты на целый квартал с домами и дорогами, построенный агентом в Cuberta

Оба формата дотащат меш из редактора в движок. Спор идёт про всё, что к мешу прикреплено: модель материала, способ ссылаться на текстуры, единицы измерения, направление «вверх» и то, переживёт ли риг переезд. Эти различия конкретны и по большей части задокументированы — значит, у вопроса есть ответ, а не предпочтение.

Что это за форматы на самом деле

glTF 2.0 и GLB

glTF 2.0 — открытая безроялтийная спецификация Khronos Group, той же организации, что стоит за Vulkan и OpenGL. Формат задумывался как runtime-формат доставки: данные в файле уже близки к тому, чего хочет GPU, поэтому загрузчик в основном заливает буферы, а не конвертирует. Контейнеров два. .gltf — это JSON, а буферы геометрии и картинки лежат либо рядом отдельными файлами, либо внутри в base64. .glb упаковывает тот же JSON и один бинарный блок в один файл. Base64 раздувает бинарные данные примерно на треть, поэтому отдавать наружу стоит именно GLB.

Спецификация фиксирует ровно то, что FBX оставляет на усмотрение. Все линейные расстояния — в метрах. Система координат правая, +Y вверх, +Z вперёд. Углы в радианах. Материалы — metallic-roughness, причём в ядре спецификации, а не в расширении.

FBX

FBX появился в Kaydara как формат Filmbox, приложения для захвата движения; Autodesk купила его в 2006 году. Это формат авторинга и обмена, а не рантайма, и ведёт он себя соответственно: умеет нести NURBS-поверхности, констрейнты, LOD-группы, несколько дублей анимации, камеры и источники света.

Публичной спецификации нет. Референсная реализация — Autodesk FBX SDK, который поставляется закрытыми бинарниками, поэтому любой инструмент под GPL — Blender в том числе — вынужден был писать собственный ридер с нуля. Файлы бывают бинарные и ASCII, оба с расширением .fbx, и формат версионируется: файлы FBX 2020 — это версия 7.7, а инструмент, собранный на SDK 2014 года, читая такой файл, может молча потерять анимацию и пользовательские свойства. «Экспортировать в FBX» — это не одно действие.

Сравнение по строкам

glTF 2.0 / GLBFBX
ВладелецKhronos Group, открытая безроялтийная спецификацияAutodesk, публичной спецификации нет; референс — закрытый FBX SDK
Контейнеры.gltf (JSON плюс файлы рядом) или .glb (один бинарный файл).fbx, бинарный или ASCII, с номером версии
Модель материалаMetallic-roughness PBR в ядре спецификацииLambert и Phong; PBR едет по вендорским договорённостям
ТекстурыPNG и JPEG в ядре, KTX2 через расширение; внутри GLBЛюбой формат, который пишет DCC; внутри файла только при Embed Media
ЕдиницыМетры, требование спецификацииТо, что записано в UnitScaleFactor; по умолчанию сантиметры
Оси+Y вверх, +Z вперёд, правая система, требованиеОбъявляются в GlobalSettings каждого файла; зависят от программы
АнимацияЗапечённые треки нод и весов морфов, step / linear / cubic splineДубли, констрейнты, блендшейпы, анимация камер и света
Свои данныеJSON в extras почти на любом объектеПользовательские свойства, с хуками импорта в Unity и Unreal
СжатиеDraco и meshopt для геометрии, KTX2 для текстурВ формате нет
Поддержка движкамиНативно в Godot, Interchange в Unreal, пакет в Unity, стандарт для вебаНативно в Unity, давно в Unreal, ufbx в Godot и Blender

Где каждый теряет данные

Материалы — вот настоящая разница

Базовый материал glTF — metallic-roughness, с заданной раскладкой по каналам: шероховатость в зелёном канале текстуры metallic-roughness, металличность в синем, ambient occlusion в красном, чтобы одна упакованная картинка обслуживала все три. У base color, нормалей и эмиссии свои слоты. Отображать нечего: материал metallic-roughness, собранный в Blender или Substance, приезжает как материал metallic-roughness.

FBX определяет Lambert и Phong. Ни то, ни другое не PBR. Любой экспортёр, который пишет PBR в FBX, делает это по договорённости, а не по спецификации — чаще всего через неймспейс свойств Stingray PBS от Autodesk, — и любой импортёр обязан распознать именно ту договорённость, которой пользовался экспортёр. Когда в FBX карта шероховатости оказывается воткнутой в specular или слоты metallic и roughness просто пустые — произошло именно это несовпадение. Это самое крупное практическое различие между форматами и причина существования большинства тредов «модель приехала серой».

Встроенные текстуры против ссылок

GLB встраивает по устройству: картинки лежат в том же бинарном буфере, что и геометрия, поэтому один файл перевозит ассет целиком. Ядро glTF допускает PNG и JPEG; расширение KHR_texture_basisu добавляет контейнеры KTX2 с данными Basis Universal, которые остаются сжатыми в видеопамяти, а не разворачиваются в сырой RGBA.

FBX по умолчанию ссылается. Текстуры — это пути, а пути ломаются при переезде на другую машину. Опция Embed Media в экспортёрах Maya, 3ds Max и Blender кладёт картинки внутрь FBX, и при импорте они распаковываются в папку с суффиксом .fbm, названную по имени файла и лежащую рядом. Цена — размер: один и тот же экспорт вырастает примерно с мегабайта до десятков мегабайт, как только внутрь попадают 4K-карты. В большинстве экспортёров Embed Media выключен по умолчанию — отсюда и файлы FBX, приезжающие сплошным розовым.

Скиннинг, анимация и пользовательские свойства

glTF хранит запечённый результат. Анимация — это треки перемещения, поворота, масштаба и весов морф-таргетов на нодах, с интерполяцией step, linear или cubic spline. Влияния скина идут четвёрками — JOINTS_0 вместе с WEIGHTS_0, — дополнительные наборы разрешены, но поддержка у ридеров разная: сообщалось, что импортёр glTF в Unreal Interchange обрезает до четырёх влияний на вершину независимо от содержимого файла. Прогоните через glTF риг с IK и констрейнтами — получите движение, но не риг.

FBX, наоборот, везёт авторские данные: несколько дублей, блендшейпы, констрейнты, анимированные камеры и свет. С произвольными данными картина переворачивается лишь отчасти. У glTF есть extras — любой JSON на нодах, мешах и материалах; формат сохраняет его идеально, а импортёры движков игнорируют, пока вы не напишете хук. У пользовательских свойств FBX дорога в движки протоптана лучше: Unity отдаёт их через OnPostprocessGameObjectWithUserProperties, у Unreal есть пайплайн метаданных FBX. Если вы размечаете точки спавна или геймплейные значения прямо на нодах в DCC, FBX потребует от вас меньше.

Повёрнуто на девяносто градусов или в сто раз больше

Это один баг с двумя причинами, и ни одна из них не про повреждение файла. Обе — про договорённости, о которых две программы не сошлись.

Единицы. Файл FBX несёт UnitScaleFactor в блоке GlobalSettings, а базовая единица формата — сантиметр: множитель 1 означает сантиметры. Дверь 2 м, собранная в метровой сцене и выгруженная без пересчёта чисел, превращается в «2» внутри файла, который объявляет эти единицы сантиметрами. Ридер, доверяющий заголовку, выдаст дверь 2 см; ридер, игнорирующий его, — 2 м. Импортёр FBX в Unity по умолчанию ставит в поле Scale Factor значение 0.01 ровно из-за этого. У glTF такой ручки нет, потому что метры — требование, а не настройка. Зеркальная версия проблемы — Unreal, у которого мировая единица сантиметр: GLB в метрах требует множителя 100 где-то по дороге, и когда здание приезжает в сто раз меньше нужного, потерялось именно это умножение.

Оси. glTF предписывает +Y вверх. FBX объявляет свои оси up и front в каждом файле, а программы по умолчанию расходятся: 3ds Max и Blender — Z-up, Maya и Unity — Y-up. У экспортёра glTF в Blender есть галка +Y Up, включённая по умолчанию, которая делает пересчёт за вас. Экспортёр FBX вместо этого просит выбрать Up и Forward, и если ваш выбор расходится с тем, что предполагает ридер, ассет ложится на спину — в Unity это обычно видно как поворот -90 градусов по X, запечённый в импортированный корень, который потом спорит с каждым скриптом, читающим вектор forward.

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

Что экспортировать под конкретный движок

Unity

FBX — нативный путь: Unity читает его без единого пакета. Импорт glTF идёт через Unity glTFast, пакет com.unity.cloud.gltfast, который делает и импорт в редакторе, и загрузку в рантайме на built-in, URP и HDRP, — но это пакет, и кто-то в команде должен его поставить. Экспортируйте FBX, если glTFast в проекте нет и не планируется. Экспортируйте GLB, если он есть, и особенно если что-то грузит модели в рантайме, где один самодостаточный файл с нативным PBR-материалом обходится куда дешевле. Тот же выбор действует и для целых сгенерированных окружений, где уже одно количество материалов делает проблему договорённостей FBX дорогой.

Unreal Engine

Unreal принимает оба. У FBX длиннее история и глубже обвязка. glTF теперь импортируется через фреймворк Interchange, плагины которого включены по умолчанию, а старые glTF Importer и Datasmith glTF Importer Epic пометила к удалению — направление движения читается однозначно. По материалам выигрывает glTF: metallic-roughness ложится на модель Unreal без перетолкования. По скелетной работе пока выигрывает FBX, отчасти из-за ограничения на число влияний выше. Помните, что Unreal — Z-up, левая система, сантиметры; Epic заявляла о намерении постепенно перейти к правой системе с Y-up, начиная с UEFN, но редактор сегодня по-прежнему Z-up. Разделение «GLB для окружений и пропсов, FBX для персонажей» держится.

Godot

Документация прямо говорит: glTF 2.0, рекомендуется. FBX импортируется нативно начиная с Godot 4.3 через открытую библиотеку ufbx; до этого требовался FBX2glTF — внешний бинарник, слинкованный с проприетарным SDK Autodesk, который приходилось ставить отдельно. Godot — Y-up, правая система, метры, ровно то, что предписывает glTF, поэтому на входе ничего не пересчитывается. GLB, без оговорок, которые стоило бы записывать.

Blender

Оба ходят туда-обратно, но не одинаково хорошо. Импортёр и экспортёр glTF делались вместе с Khronos и поставляются с Blender. FBX никогда не мог пользоваться SDK от Autodesk по лицензионным причинам; импортёр переписали на C++ поверх библиотеки ufbx, и в Blender 5.0 он стал использоваться по умолчанию, тогда как экспортёр по-прежнему питоновский. Берите GLB — если только файл не уходит человеку, работающему в Maya или 3ds Max, для которого FBX и есть родной язык.

Веб и three.js

Здесь спора нет. GLTFLoader — поддерживаемый и рекомендуемый путь; FBXLoader существует и открывает не всякий файл, который ему дают. Один GLB — это один запрос без потерянных зависимостей. Добавьте Draco или meshopt для геометрии и KTX2 для текстур: на телефоне это важнее размера загрузки, а подрезка сгенерированной сцены — отдельная работа со своими решениями.

Когда правильный ответ — экспортировать оба

Второй экспорт из того же источника стоит секунд, и есть несколько ситуаций, где это просто верное действие:

  • Вы не управляете принимающим пайплайном. Листинг на маркетплейсе, передача клиенту, другая студия. Отдайте оба и дайте выбрать.
  • У модели два назначения. Сборке движка и веб-вьюеру или конфигуратору нужны от одного ассета разные вещи.
  • Разные части едут по разным дорогам. Окружение уходит в движок как GLB, а персонаж возвращается аниматору как FBX.
  • Вы локализуете баг импорта. Если GLB заходит чисто, а FBX нет, проблема в договорённости о материалах FBX, а не в вашем меше — и вы только что сэкономили полдня.

Cuberta экспортирует GLB или FBX с текстурами, поэтому прогнать такое сравнение на целой сгенерированной локации — это двухминутный эксперимент, а не повторный авторинг. Один раз за проект это стоит сделать пораньше, пока на предположении не висит четыреста объектов.

Что проверить, как только файл приехал

Две минуты внимания в таком порядке ловят почти всё:

  1. Масштаб. Поставьте рядом эталонный куб 2 м. Двери и ступени выдают ошибку быстрее всего.
  2. Ориентация. Поворот импортированного корня должен быть нулевым. -90 по X означает, что разошлись договорённости об осях.
  3. Число материалов. Совпадает с источником или всё схлопнулось в один слот.
  4. Назначение текстур. Base color в sRGB, нормали и упакованные карты в linear. Серое или пурпурное означает, что ссылка не разрешилась; ищите папку .fbm рядом с FBX.
  5. Шейдинг. Гранёное там, где должно быть гладким, — не доехали группы сглаживания или тангенты. Переэкспортируйте с явной записью тангентов.
  6. Скиннинг. Максимум влияний на вершину и совпадение bind pose с источником.
  7. Имена. Имена в иерархии, потому что за них цепляются скрипты и варианты префабов, а переименовывать потом дорого.

Правило, которое из всего этого следует, скучнее самого спора: берите glTF и GLB, если только что-то конкретное в вашем пайплайне не требует FBX, — и умейте назвать это конкретное. В 2019-м честным ответом был FBX с оговорками. Сегодня Godot рекомендует glTF прямым текстом, Unreal сворачивает старые glTF-плагины в пользу полноценного импортёра, а Unity выпускает собственный пакет. FBX никуда не денется: он остаётся языком, на котором авторские приложения разговаривают друг с другом, и везёт риги, которые glTF описать не умеет. Но как то, что вы отдаёте рантайму, он сдаёт позиции — по причинам, записанным в спецификациях, а не обсуждаемым на форумах.