FBX to NWB Conversion - limztudio/NWBLot GitHub Wiki
FBX to NWB Conversion
nwb_fbx_to_nwb imports binary or ASCII FBX scenes (through the vendored ufbx loader) into NWB mesh metadata. It can write a standalone mesh, a self-contained asset bunch, a separately packaged model, or the skeleton and skin assets required by a skinned mesh. It also refreshes existing NWB mesh sources into the canonical stream layout.
The source-controlled command reference lives in utilities/fbx_to_nwb/README.md. This page summarizes the current main-branch workflow and output contract.
Build and run
From the repository root, build the importer without starting it (python3 on Linux):
python -m launcher fbx-to-nwb --build-only --config dbg
The utility owns utilities/fbx_to_nwb/launch.py. Its discovered shortcut selects the matching preset, configures when needed, and builds its dependencies; no manual CMake command is needed. The run examples pass --working-directory . before -- so relative input and output paths resolve from the repository root.
The executable target is nwb_fbx_to_nwb. Use the discovered fbx-to-nwb repository command so it builds the target as needed; arguments after -- are passed to the importer:
python -m launcher fbx-to-nwb --working-directory . -- --help
python -m launcher fbx-to-nwb --working-directory . -- assets/models/crate.fbx
The second command starts the interactive workflow. Automated pipelines should pass --yes, which accepts defaults for every omitted option and disables prompts:
python -m launcher fbx-to-nwb --working-directory . -- \
assets/models/crate.fbx \
--output assets/models/crate.nwb \
--asset-type bunch \
--normal-mode imported \
--yes
When --output is omitted, the tool replaces the input extension with .nwb. It never overwrites an existing primary output unless --force is supplied or an interactive overwrite prompt is accepted.
Select source meshes
Inspect visible mesh instances before exporting a scene:
python -m launcher fbx-to-nwb --working-directory . -- assets/characters/hero.fbx --list-meshes
--mesh (or -m) defaults to all. It also accepts first, a zero-based instance index, a node name, or a mesh name. Matching is case-insensitive: exact matches win, while partial matches export every matching instance. Hidden mesh nodes are excluded unless --include-hidden is present.
For a single static mesh from the first instance:
python -m launcher fbx-to-nwb --working-directory . -- \
assets/props/crate.fbx \
--output assets/meshes/crate.nwb \
--asset-type mesh \
--mesh first \
--yes
Selected instances are merged into one exported mesh. Polygon faces are triangulated and degenerate triangles are discarded. The default --triangle-area-length-squared-epsilon is 1e-20; raise it to discard additional small triangles.
Space and vertex attributes
By default, the importer converts to NWB space: +X right, +Y up, +Z forward, with one unit equal to one metre. Use --preserve-space to retain source axes and units. Node transforms are baked into the mesh unless --local is passed, and --scale applies an additional positive uniform scale.
Normal handling is explicit:
| Mode | Result |
|---|---|
imported (default) |
Uses the imported per-corner normal stream. |
smooth |
Rebuilds smooth normals shared by identical output positions. |
regenerate |
Rebuilds one face normal per triangle. |
NWB meshes always have tangents. Complete source tangents are retained only with imported normals; otherwise the tool regenerates them from uv0. Missing or degenerate UVs use a safe fallback tangent frame. uv0 defaults to zero when absent. Vertex colors are imported unless --ignore-colors requests the --default-color R,G,B,A value (default 1,1,1,1). --flip-winding swaps the second and third vertex of every output triangle.
Output layouts
--asset-type determines the output contract:
| Type | Files written | Intended use |
|---|---|---|
bunch (default) |
One .nwb containing a mesh and model, plus skeleton/skin data when needed. |
Self-contained import. |
mesh |
One mesh .nwb. |
Standalone mesh payload; no skin or skeleton output. |
model |
One model .nwb with package-asset references. |
Referenced mesh/skin/skeleton assets already exist. |
skeleton |
One skeleton .nwb. |
Skinned source only. |
skin |
One skin .nwb with mesh and skeleton references. |
Skinned source only; referenced assets are not written. |
For model, skin, and separate-package output, asset references are derived from the output path. For example, assets/characters/hero.nwb produces a default virtual base of project/characters/hero; --virtual-root engine uses engine/... instead. A path outside an assets directory falls back to its stem under the selected virtual root.
--separate-assets is valid only with --asset-type bunch. It writes a model to the requested output and its child assets alongside it:
assets/characters/hero.nwb
assets/characters/hero/mesh.nwb
assets/characters/hero/skeleton.nwb # skinned sources only
assets/characters/hero/skin.nwb # skinned sources only
bunch, model, skeleton, and skin selections cannot mix static and skinned meshes. The skeleton and skin forms require a skinned selection.
The emitted model metadata uses the explicit named object maps described in Mesh Model and Skinning: skeletons, static_meshes, and skinned_meshes. Static objects declare their mesh. Skinned objects declare a Skin reference and local skeleton-object name; their mesh comes from the Skin and is not repeated in the model.
Refresh an NWB mesh source
Passing a .nwb file automatically enters refresh mode; --refresh-nwb can force it. Refresh validates each supported mesh declaration, canonicalizes and deduplicates its streams (including associated skin influences), then rewrites only changed lists while preserving the rest of the document.
Create a canonical copy:
python -m launcher fbx-to-nwb --working-directory . -- \
assets/meshes/crate.nwb \
--output assets/meshes/crate_canonical.nwb \
--yes
Replace an input in place only with an explicit overwrite acknowledgement:
python -m launcher fbx-to-nwb --working-directory . -- \
assets/meshes/crate.nwb \
--yes --force
--list-meshes is available only for FBX input. Refresh rejects unsupported mesh fields rather than silently dropping them. See Mesh Model and Skinning for the runtime mesh, model, skeleton, and skin contracts that consume this authored metadata.
Command-line reference
| Option | Description |
|---|---|
input |
FBX input path, or an NWB mesh path for refresh mode. |
-o, --output PATH |
Primary output .nwb path. |
--asset-type TYPE |
bunch, mesh, model, skeleton, or skin. |
--virtual-root ROOT |
Virtual root for generated package references; defaults to project. |
-m, --mesh SELECTOR |
all, first, an index, a node name, or a mesh name. |
--normal-mode MODE |
imported, smooth, or regenerate. |
--scale VALUE |
Positive finite uniform scale after import. |
--triangle-area-length-squared-epsilon VALUE |
Non-negative threshold for discarding degenerate triangles. |
--default-color R,G,B,A |
Fallback color, four finite values. |
--preserve-space |
Do not convert source axes or units to NWB space. |
--include-hidden |
Include hidden FBX mesh nodes. |
--local |
Do not bake node transforms into the mesh. |
--ignore-colors |
Use the default color even when source vertex colors exist. |
--flip-winding |
Reverse every output triangle winding. |
--separate-assets |
Write a bunch as a model plus child .nwb files. |
--refresh-nwb |
Treat the input as an NWB mesh asset to canonicalize. |
--list-meshes |
Print importable FBX mesh instances and exit. |
--force |
Allow replacement of an existing primary output. |
-y, --yes |
Accept defaults for omitted import options and disable prompts. |
-h, --help |
Show the generated command help. |
For the exact source-managed documentation and future option changes, use utilities/fbx_to_nwb/README.md on main.