FOnline Engine
Current 2026.1.118-dev GitHub
Документация Docs/ru/how-to/content/model-format.md

Формат моделей и 3D-композиция

FOnline использует описания моделей .fo3d, чтобы собрать на клиенте запечённые 3D-меши, преобразованные исходные анимации, выбираемую слоями экипировку, дочерние модели, частицы, переопределения материалов и объёмы отсечения.

Это руководство описывает авторинг и runtime-модель. Точный контракт текущей ревизии приведён в сгенерированных справочниках токенов, ресурсов и лимитов, правил валидации и в канонической JSON-модели.

Область и авторитетные источники

Контрактом владеют:

  • Source/Tools/ModelMeshBaker.cpp и Source/Common/ModelMeshData.* для импорта и проверки мешей .fbx / .obj, а также mesh-only payload LFMODMSH;
  • Source/Tools/ModelSourceLoader.*, Source/Tools/ModelAnimationConverter.* и Source/Common/ModelAnimationData.* для извлечения исходного скелета и клипов, анализа совместимости, преобразования Ozz и нативного rig payload;
  • Source/Tools/ModelInfoBaker.cpp для разбора .fo3d, раскрытия include, проверки зависимостей и исходников, сериализации model info, создания runtime rig и метаданных анимации;
  • Source/Client/ModelManager.*, ModelHierarchy.*, ModelInformation.*, ModelInstance.* и ModelAnimation.* для строгой runtime-загрузки, общих неизменяемых данных, композиции и позы экземпляра, контроллеров анимации и рисования;
  • Source/Frontend/Rendering.h и сгенерированный CMake-интерфейс проекта для compile-time лимитов моделей;
  • тесты baker, mesh data, source loader, animation data/converter/runtime, совместимости скелета, Ozz и client engine как исполняемые примеры грамматики, форматов, преобразования, загрузки и ошибок.

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

Полная машинная модель генерируется из BuildTools/ModelFormatInterface.json. Генератор напрямую сравнивает документированный набор токенов с ModelDescriptionParser::ParseToken; расхождение парсера и документации останавливает проверку.

Обзор конвейера

Конвейер моделей состоит из двух упорядоченных baker и общих модулей загрузки и преобразования:

  1. ModelMeshBaker с порядком 4 импортирует .fbx и .obj и записывает версионированный mesh-only ресурс LFMODMSH по тому же пути и с тем же расширением. Клипы и изменяемая поза в этот payload не входят.
  2. ModelInfoBaker с порядком 6 разбирает конкретные .fo3d, проверяет ссылки и свежесть исходников, загружает выбранные скелеты и клипы через ModelSourceAssetCache, преобразует канонический runtime rig и записывает LFMODINF с обязательным payload LFOZZRIG по пути .fo3d. Он также создаёт ModelAnimationInfo.foinfo для общих длительностей и границ.

Клиент не разбирает авторский текст, FBX или OBJ. ModelManager загружает общие иерархии мешей, ModelInformation строго читает неизменяемое описание и rig, а каждый ModelInstance владеет изменяемыми контроллерами, матрицами позы, дочерними объектами, частицами и render-композицией. Старые payload без заголовка и частичные fallback для rig отклоняются.

Файлы с basename TEMPLATE_ предназначены только для include. Они влияют на конкретные описания и timestamps запекания, но не создаются как самостоятельные .fo3d-ресурсы или секции ModelAnimationInfo.foinfo.

Контракт исходного меша

Поддерживаемые входы

Текущий ModelMeshBaker сканирует только:

  • .fbx для скелетных и статических мешей, skinning, имён diffuse-текстур материалов, исходных скелетов и анимационных клипов;
  • .obj для статических моделей, присоединяемых объектов и объёмов отсечения.

Устаревшие .x и .3ds не являются текущими входами. ModelMeshBaker не выберет файл с таким расширением.

Поведение импорта

Mesh baker и source loader используют закреплённую версию ufbx, но имеют разных владельцев. Первый выдаёт иерархию, bind, vertices, indices, skin и materials; второй извлекает проверенные данные skeleton/TRS/clip для преобразования анимации. Встроенные файлы игнорируются, skinning вычисляется, веса очищаются, а отсутствующие normals обрабатываются детерминированно.

Требования к исходникам:

  • faces должны быть заранее триангулированы;
  • конкретная модель должна содержать хотя бы один drawable mesh;
  • имена nodes становятся именами bones, а nodes с геометрией — именами drawable meshes;
  • используйте один material на drawable node, если важно детерминированное владение текстурой;
  • файловая текстура DiffuseColor первого material становится texture slot 0;
  • имена текстур сохраняются без исходной директории и затем разрешаются относительно запечённого меша;
  • используется только первый skin deformer;
  • число skin clusters должно помещаться в FO_MODEL_MAX_BONES;
  • у вершины сохраняются только FO_MODEL_BONES_PER_VERTEX влияний, после чего веса нормализуются;
  • меш без skin получает детерминированную привязку к одной кости;
  • имена animation stacks являются clip names для Anim, но клипы загружаются из исходника и входят в rig model info, а не в LFMODMSH;
  • прямые .fbx-attachments должны содержать только rest pose; если у присоединённого исходника есть клипы, используйте дочерний .fo3d с явными Anim;
  • внешние animation sources должны содержать только hierarchy и animation. Drawable geometry запрещена, кроме точного файла с временным исключением AllowAnimationGeometry.

Source loader отклоняет не-конечные transforms, дубликаты clip names без учёта регистра, неверные durations и key times, превышение лимитов и глубины, а также некорректные отношения skeleton. Animation sources могут добавлять совместимые канонические joints без физического ModelBone; физические meshes и cuts остаются в базовой иерархии.

Текущие лимиты по умолчанию:

Опция проекта Runtime-константа По умолчанию
FO_MODEL_LAYERS_COUNT MODEL_LAYERS_COUNT 30
FO_MODEL_MAX_TEXTURES MODEL_MAX_TEXTURES 8
FO_MODEL_MAX_BONES MODEL_MAX_BONES 54
FO_MODEL_BONES_PER_VERTEX MODEL_BONES_PER_VERTEX 4

Это контракты бинарной формы и shader layout. При переопределении проект обязан использовать одинаковые значения в client binaries, запечённых моделях, Critter.ModelLayers, effects и packages.

Лексический синтаксис

.fo3d представляет собой последовательность токенов, разделённых whitespace:

  • # и ; начинают комментарий;
  • quoted strings и escape syntax отсутствуют;
  • paths и names не могут содержать whitespace;
  • в одной строке может быть несколько directives;
  • directive забирает обязательные arguments, затем разбор продолжается со следующего token;
  • неизвестный token или отсутствующий argument является ошибкой запекания;
  • integer arguments принимают числа, явные booleans или enum names из metadata resolver;
  • float arguments должны быть конечными числами.

Компактная запись допустима:

Layer 1 Value 2 Attach Hat.fbx Link Head RotY 180 Texture 0 Hat.tga

Для сопровождения размещайте structural selectors (Layer, Value, Root, Attach) перед относящимися к ним modifiers.

Минимальные описания

Минимальная статическая модель:

Model Props/Crate.obj

Скелетная модель с анимациями и attachment, выбранным слоем:

Model Characters/Human.fbx
RotationBone Spine

Anim CritterStateAnim.Unarmed CritterActionAnim.Idle ModelFile Idle
Anim CritterStateAnim.Unarmed CritterActionAnim.Walk ModelFile Walk

Layer 1
Value 1
Attach Items/Hat.fbx Link Head

Enum names зависят от metadata встраивающего проекта. Числа в тестах движка доказывают поведение parser, но не являются рекомендуемым словарём проекта.

Include и шаблоны

Include разбирает другой файл inline:

Include TEMPLATE_Humanoid.fo3d mesh Human.fbx scale 0.9

После path идут пары name/value. До tokenization каждое буквальное %name% в подключаемом тексте заменяется значением:

# TEMPLATE_Humanoid.fo3d
Model %mesh%
Scale* %scale%

Правила include:

  • path задаётся относительно файла, содержащего Include;
  • пути Model, Attach и Cut в подключённом тексте задаются относительно include-файла;
  • внешний файл Anim позднее разрешается относительно итогового конкретного .fo3d;
  • include arguments занимают остаток строки, поэтому следующую directive на той же строке размещать нельзя;
  • replacements являются простой заменой текста, а не token-aware операцией;
  • включённый текст разделяет parser state с вызывающим файлом;
  • рекурсивные include отклоняются;
  • самый новый timestamp во всём include graph управляет incremental rebake.

Предпочитайте самодостаточные шаблоны, явно устанавливающие Root, Layer, Value и Mesh. Скрытая зависимость от состояния вызывающего файла затрудняет работу людей, ИИ и валидаторов.

Состояние парсера

Parser отслеживает выбранные Layer, Value, текущий link для modifiers и текущий selector Mesh для Texture и Effect.

В начале файла текущим link является default root, поэтому top-level transforms и materials применяются к базовой модели даже без Root.

Layer или Value изменяет selector, очищает Mesh и переводит текущий link на dummy object. После выбора пары layer/value запишите Root, Attach или AttachParticles до transform, material, disable или cut. Modifiers при активном dummy link разбираются, но отбрасываются.

Directive для возврата Layer к начальному -1 нет. Все default-root declarations должны идти до первого Layer либо в более раннем include.

Root также очищает Mesh. Attach и AttachParticles создают link и очищают Mesh. Размещайте Mesh после selector link, к которому он относится.

Link сохраняется только для не-default и не-dummy link. На default root он игнорируется. Link у layer Root сериализуется, но дочернего объекта для присоединения нет; не задавайте его.

Слои и значения

Layer выбирает индекс фиксированного массива:

0 <= layer < FO_MODEL_LAYERS_COUNT

Value выбирает точное целое, определённое проектом. Ноль означает inactive и не может создать layer entry Root, Attach или AttachParticles.

В runtime ModelInstance::PlayAnim копирует или повторно использует массив слоёв, применяет точные overrides AnimLayerValue, сбрасывает модель к default root, находит совпавшие пары Layer/Value, применяет root modifiers и materials, создаёт или сохраняет children и particles, удаляет больше не выбранные элементы и перестраивает combined meshes при изменении композиции.

Layer value — это состояние render-композиции, а не только косметические metadata. Оно может менять transforms, animation speed, geometry, materials, effects, cuts, child models, particles и batching. Семантика каждого layer/value принадлежит документации и тестам проекта.

Модификаторы корня

Без выбранного layer Root выбирает default link базовой модели:

Root
Scale 0.9
RotX 90

При выбранной ненулевой паре layer/value он создаёт условный root modifier:

Layer 3
Value 2
Root
DisableMesh Torso
Texture 0 Armor.tga

Условные root links могут добавлять transforms и speed multipliers, переопределять textures/effects, отключать layers и meshes, добавлять cuts. Дочернюю модель они не создают.

Присоединение моделей

Attach требует выбранного layer и ненулевого value:

Layer 1
Value 4
Attach Weapons/Rifle.fo3d Link RightHand

Путь дочернего объекта задаётся относительно declaring file.

Присоединение к одной кости

При Link <bone> весь child становится дочерним объектом одной проверенной кости:

Attach Hat.fbx Link Head

Rotation, translation, scale, speed, materials, disables и cuts этого link применяются внутри child instance.

Общий скелет

Без Link runtime сопоставляет одноимённые кости child и parent:

Attach ArmorTorso.fbx

Используйте это только для одежды и частей тела, созданных под один skeleton. Если общих bones нет, runtime creation завершается ошибкой.

Дочернее описание или прямой меш

Используйте Attach child.fo3d, когда child нужны собственные base mesh, layers/attachments, default material/effect policy, cuts, animations или rendering flags. Для простой запечённой иерархии достаточно прямого .fbx / .obj. Дочерний .fo3d запекается самостоятельно; parent проверяет существование descriptor и bone из Link.

У direct attachment нет description-level коррекции scale. Maximum-axis extent его static bounds должен оставаться в диапазоне Baking.ModelAttachmentMinExtent .. Baking.ModelAttachmentMaxExtent; иначе bake завершается ошибкой с измеренным extent и limit. Используйте child .fo3d, если composition требует явного scale. Mesh nodes с отрицательным transform determinant раньше отклоняет ModelMeshBaker: reset/freeze mirrored geometry к положительному transform до export, не рассчитывая на переворот normals и winding в baker-е.

Присоединение частиц

AttachParticles выбирается слоем:

Layer 8
Value 1
AttachParticles Particles/Jet.spk Link Backpack
MoveY 0.15
RotY 90

Particle path является глобальным путём запечённого ресурса, а не путём относительно .fo3d. Ссылайтесь на созданный .spk или .efk, а не на авторский .spark или .efkproj. Всегда задавайте корректную bone в Link: runtime-создание частиц требует её.

MoveX/Y/Z и RotY определяют placement частицы. Instance живёт, пока активна точная пара layer/value, и удаляется при изменении композиции. XML, SPARK objects, renderer fields, effects/textures, runtime cache и визуальная проверка принадлежат формату частиц. Частицы на bones используют прямой путь 3D-композиции, а не selector atlas/direct-scene у ParticleSprite.

Преобразования и скорость

Поля link: RotX/Y/Z в градусах, MoveX/Y/Z в координатах модели, ScaleX/Y/Z и playback multiplier Speed. Scale задаёт все три оси.

У каждого поля есть assignment, additive и multiplicative формы:

Scale 0.9
Scale+ 0.1
Scale* 1.5

RotY 90
RotY+ 15
RotY* 0.5

Для форм + и * действует особая инициализация: если поле равно нулю, operand становится его значением; иначе выполняется обычное сложение или умножение. Поэтому template может использовать Scale* 0.9 или Speed* 1.2 без предшествующего assignment, а порядок declarations наблюдаем.

В runtime ноль означает identity/no contribution. Ненулевые transforms перемножаются с текущим model transform. Отрицательный итоговый Speed запрещён при запекании; ноль означает отсутствие вклада в скорость.

Меши, текстуры и эффекты

Mesh выбирает drawable node:

Mesh Torso
Texture 0 Armor.tga
Effect Effects/Armor.fofx

Mesh All очищает selector, и следующие material directives применяются ко всем drawable meshes текущей модели link. Subset устарел: parser забирает argument и пишет warning, но ничего не выбирает.

Текстуры

Texture 0 Diffuse.fofrm

Слоты находятся в [0, FO_MODEL_MAX_TEXTURES). Mesh выбирает отрисовываемые меши, пути разрешаются относительно файла меша. Безусловный Texture слота 0 заменяет импортированную diffuse-текстуру, чей исходник может быть поглощён рецептом. Baker проверяет действующие умолчания; runtime загружает их для включённых мешей после переопределений и привязки вложенных моделей.

Текстура требует опубликованный выход SpriteInfo с одним направлением и одним кадром. FOFRM Size позволяет запечь уменьшенный вариант большого источника, поставляя только корневой выход. Направление выбирается явно через FOFRM InputDir. Обрезанный sprite mesh восстанавливает полный логический холст до загрузки, сохраняя UV изображения. TextureAnimation не поддерживается и вызывает ошибку неизвестной директивы; многокадровые ресурсы текстур отвергаются при выпечке и в runtime.

Во вложенной модели Parent или Parent_<mesh> наследует текущую статическую текстуру родителя в том же слоте. При нескольких мешах родителя задавайте суффикс имени меша. В корне Parent запрещён.

Пересоберите согласованные бинарники и принудительно перепеките описания моделей и метаданные для LFMODINF schema 5/runtime 0.0.76: переопределения больше не хранят флаг анимации. Прежние описания отвергаются; остальные схемы моделей и изображений прежние.

Эффекты

Effect Effects/SkinnedArmor.fofx

Effect paths являются глобальными baked-resource paths. Parent и Parent_<mesh> копируют текущий effect родителя по тем же правилам. Meshes объединяются в draw batch только при совместимых effect, texture set и bone capacity, поэтому material overrides могут менять batching и требуют измерения на типичных композициях.

Отключение слоёв и мешей

DisableLayer принимает layer indices через дефис:

DisableLayer 5-6-7

При активном link эти slots пропускаются внутри model instance.

DisableMesh принимает drawable node names через дефис, а DisableMesh All сохраняет wildcard и отключает все meshes:

DisableMesh Hair-HelmetBase

Используйте отключения для взаимоисключающей композиции, но явно документируйте project ownership слоёв. Циклическая и зависящая от порядка политика плохо тестируется.

Объёмы отсечения

Cut удаляет geometry из выбранных слоёв combined mesh:

Cut CutVolumes/Helmet.obj All HeadVolume - - -

Шесть arguments:

  1. path .fbx / .obj cut volume относительно declaring file;
  2. target layers через дефис либо All;
  3. drawable shape names из cut file через дефис либо All;
  4. первая unskin bone либо -;
  5. вторая unskin bone либо -;
  6. unskin shape, ~shape для reversed behavior либо -.

All для layers раскрывается во все compile-time layers, кроме текущего выбранного. В default-root scope включаются все layers. All для shapes выбирает все drawable shapes, кроме отдельно указанного unskin shape.

Runtime классифицирует cut shape по числу запечённых vertices: ровно 36 означает axis-aligned box bounds, любое другое число — sphere radius по X extent. Это правило формата движка, а не общий mesh heuristic. Создавайте простые специализированные cut assets и проверяйте результат визуально.

Обе unskin bones задаются вместе; unskin shape требует обеих. Все bones и drawable shapes проверяются при запекании. Любой cut отключает обычный culling composed model, поэтому это correctness feature с render cost.

Управление рендерингом

Автоматический layout model sprite

DrawSize и ViewSize удалены. ModelInfoBaker пишет aggregate bounds, project-selected preview view/name bounds и per-animation bounds в ModelAnimationInfo.foinfo версии 2. Клиент проецирует их для каждого направления, расширяет с учётом children и layers и вычисляет offscreen frame, visual anchor, lighting envelope и interaction/view rectangle.

Каждый non-particle child link сериализует проверенный root-space AABB; default link и particle links не содержат geometry payload. При расчёте envelope baker учитывает disabled meshes, nested descriptions, link transforms и sampled animations родителя. Runtime framing объединяет bounds активных animations с envelopes выбранных links и проецирует только их corners без per-frame weighted-vertex sweep. Live particles всё ещё могут вызвать ограниченный expansion/rerender при выходе за baked geometry envelope. Авторы настраивают source transforms, animation reach, attachments и Render.ModelProjFactor, а не фиксированные пиксельные прямоугольники в .fo3d.

Проверяйте все направления и типичные animations в видимом клиенте. Для диагностики clipping, пустого пространства, polygon edges и crop placement используйте Game.DumpAtlases() или Dump atlases в Mapper. Бинарный и runtime-контракты описаны в Baking Pipeline и Frontend и рендеринг.

Прочие флаги

  • DisableShadow отключает тень модели.
  • DisableAnimationInterpolation выбирает nearest-key sampling.
  • DisableBackwardAnim выбирает forward walk/run вместо WalkBack / RunBack и совмещает look direction с движением.
  • RotationBone <bone> включает movement overlay controller и directional rotation torso/head.
  • FastTransitionBone <bone> сбрасывает transition state нового child на указанной link bone.

Граница анимации

Animation directives .fo3d:

Anim <state> <action> <ModelFile|animation-source> <clip|~clip|Base>
AnimSpeed <state> <action> <positive-factor>
AllowAnimationGeometry <external-animation-file>
AnimLayerValue <state> <action> <layer> <value>
StateAnimEqual <from> <to>
ActionAnimEqual <from> <to>
FastTransitionBone <bone>
RotationBone <bone>
DisableAnimationInterpolation
DisableBackwardAnim

Model Animation описывает first-entry-wins tuples, ModelFile/Base/~clip, совместимость skeleton и rig conversion, one-step aliases, effective duration, common и loaded-client lookup, substitutions и validation.

AnimLayerValue применяется к точной запрошенной паре до model composition. Alias resolution относится к animation lookup; не считайте, что alias также переписывает key для layer override.

AllowAnimationGeometry — узкий migration aid. Он называет один точный внешний файл из Anim, разрешается от конечного .fo3d, используется только baker validation и не сериализуется. Duplicate paths/targets, невыбранные файлы и оставшиеся после удаления geometry исключения являются ошибками. Исправьте export, сохранив необходимую helper/bone hierarchy, и удалите исключение в той же миграции.

3D skeletal animation отделена от 2D-контракта Motion в Sprite Root Motion.

Runtime-загрузка и кеширование

ModelManager::CreateModel(name) принимает запечённый .fo3d с полной composition semantics либо baked mesh path с простой rest-pose model без declarations и animation controller.

Descriptions и mesh hierarchies кешируются по resource name. Неизменяемые clips, remaps, bindings и canonical skeleton принадлежат ModelInformation; mutable timelines, poses, matrices, children и procedural transforms — каждому ModelInstance. При смене слоёв активные children повторно используются по stable baked link id, а переставшие совпадать children и particles удаляются.

Combined mesh generation объединяет совместимые видимые meshes, пока effect, textures или bone capacity не требуют нового batch. Cuts применяются после объединения parent и child meshes.

Не изменяйте и не разбирайте binary payload запечённых .fo3d, .fbx или .obj из project scripts. Их layout является приватным контрактом baker/runtime.

Поведение при ошибках

ModelInfoBaker отклоняет или сообщает: отсутствующий Model; недоступные, устаревшие или malformed baked meshes и sources; primary mesh без drawable geometry; отсутствующие textures/effects/particles/children/cuts; неверные layer/texture indices; нулевые layer values для Root/Attach; отсутствующие bones или meshes; malformed includes; invalid/non-finite numbers; отрицательный Speed; неположительный AnimSpeed; неизвестные enums, clips или несовместимые skeleton; attached FBX с clips; внешнюю animation geometry без точного временного исключения; mirrored mesh nodes; direct FBX/OBJ attachments вне настроенного диапазона Engine world units; неверные cut combinations; неизвестные tokens.

Runtime повторяет критические binary и range checks. Runtime exception означает повреждённые или устаревшие baked data либо пробел в validation; не ловите её для тихой подстановки несвязанной модели.

Предупреждение об устаревшем контенте

Не выводите текущую поддержку из старых FOnline-проектов:

  • .x и .3ds не выбираются текущим mesh baker;
  • AnimEqual заменён на StateAnimEqual и ActionAnimEqual;
  • CalculateTangentSpace, RenderFrame и RenderFrames не являются текущими tokens;
  • Subset оставлен только как warning path и ничего не выбирает.

Сначала переведите legacy assets на текущие source formats и grammar, затем проверяйте против текущей ревизии Engine. Старый проектный контент — свидетельство исторического использования, а не нормативная спецификация.

Практики авторинга

  1. Размещайте default-root declarations до первого Layer.
  2. Оставляйте у concrete description ровно один намеренный итоговый Model.
  3. Начинайте include-only files с TEMPLATE_.
  4. Пусть template явно задаёт selector context.
  5. Используйте enum names и project layer constants из metadata.
  6. Документируйте каждый layer index, allowed value, owner и конфликтующий layer.
  7. Делайте отдельный drawable node для независимо заменяемого material/effect.
  8. Используйте direct mesh для простого prop, а child .fo3d для переиспользуемой композиции.
  9. Всегда задавайте Link у particle attachment.
  10. Соблюдайте регистр paths, bones, meshes, animation stacks и effects.
  11. Делайте cut volumes простыми и специализированными.
  12. Проверяйте матрицу сочетаний layers, а не только каждый attachment отдельно.
  13. Экспортируйте external animations без drawable geometry, сохраняя нужную hierarchy.
  14. Считайте каждый AllowAnimationGeometry временным долгом с владельцем ремонта.
  15. После изменений loader, converter, mesh wire или animation sources выполняйте force bake и затем incremental bake.

Для ИИ-авторинга фиксируйте parser state перед каждым modifier:

current layer = 3
current value = 2
current link = Attach Armor.fo3d
current mesh = Torso
next directive = Texture 0 Parent_Torso

Если состояние нельзя назвать однозначно, разбейте компактную строку и явно задайте selectors.

Процесс проверки

  1. Перегенерируйте и проверьте справочник:

    python BuildTools\docs_model_format.py --write
    python BuildTools\docs_model_format.py --check
    python -m unittest BuildTools.tests.test_docs_model_format
    
  2. Запустите focused Engine tests:

    .\Binaries\Tests-Windows-win64\LF_UnitTests.exe "ModelBaker*"
    
  3. Перезапеките встраивающий проект:

    cmake --build Build\Auto --config RelWithDebInfo --target BakeResources
    
  4. В видимом клиенте проверьте framing/anchors/crop bounds, все layer/value, оба вида attachment, particles, inheritance textures/effects, disables, cuts, idle/movement/turn/backward/action animations, shadows и interpolation.
  5. Зафиксируйте project-specific layer semantics, ожидаемые screenshots и regression routes в документации проекта.

Чистый bake доказывает grammar, asset closure, enums/ranges и serialization. Он не доказывает качество позы, scale, clipping, материалы, blending, cut geometry, interaction bounds или performance.

Маршрутизация изменений

  • При изменении .fo3d tokens, parser state, include, path rules или validation обновите руководство, BuildTools/ModelFormatInterface.json, generated outputs и focused tests.
  • При изменении импорта .fbx / .obj, skinning, materials, animation conversion или model limits обновите asset/limit contract и native mesh-baker tests.
  • При изменении layers, attachments, particles, transforms, materials, cuts, batching или flags обновите composition/runtime sections и проверьте видимый client scene.
  • Animation tuples, aliases, speed, duration и script lookup принадлежат также Model Animation.
  • 2D frame offsets и sprite phase принадлежат Sprite Root Motion.
  • Каталоги моделей и семантика слоёв принадлежат только документации встраивающего проекта, которая ссылается на этот контракт.
Введите запрос.