The status of loading and viewing FBX models using different WebGL libraries.
Test environment: Windows 11 + Chrome 147
Legend:
| Model | Three.js r184 | Babylon.js custom loader | Notes |
|---|---|---|---|
| Samba Dancing | :white_check_mark: Sample | :white_check_mark: Sample | Skinned animation model. |
| morph_test | :white_check_mark: Sample | :white_check_mark: Sample | Morph targets. Adjust influence in the Morphs folder of the GUI. |
| monkey | :white_check_mark: Sample | :white_check_mark: Sample | Static mesh. |
| monkey_embedded_texture | :white_check_mark: Sample | :white_check_mark: Sample | Embedded texture. |
| vCube | :white_check_mark: Sample | :white_check_mark: Sample | Static mesh. |
| archer/ArcherRi01 | :white_check_mark: Sample | :white_check_mark: Sample | Static mesh with geometric transform. |
| warrior/Warrior | :white_check_mark: Sample | :warning: Sample | Skinned animation model. ByVertice UV/normal mapping fix applied. |
| stanford-bunny | :white_check_mark: Sample | :white_check_mark: Sample | Large static mesh (ASCII FBX format). |
| mixamo | :white_check_mark: Sample | :white_check_mark: Sample | Skinned animation model. |
| RotationTest | :white_check_mark: Sample | :warning: Sample | Rotation-order coverage is still being verified. |
| exampleWindow | :white_check_mark: Sample | :white_check_mark: Sample | Static mesh. |
| Head_69 | :white_check_mark: Sample | :white_check_mark: Sample | Static mesh with multi-material support. |
| morph-translation | :white_check_mark: Sample | :white_check_mark: Sample | Morph targets (8 meshes). Adjust influence in the Morphs folder of the GUI. |
A standalone binary and ASCII FBX parser and Babylon.js mesh builder. No build step or npm install required — just include it as a <script> tag.
<script src="example/babylonjs/fbx-loader.js"></script>
FBXLoader.loadFBX(url, scene, options) — Load from URLconst nodes = await FBXLoader.loadFBX(url, scene, options);
| Parameter | Type | Description |
|---|---|---|
url |
string |
URL of the .fbx file to load |
scene |
BABYLON.Scene |
Target Babylon.js scene |
options |
object |
Optional settings (see below) |
Returns: Promise<BABYLON.Node[]> — all created nodes (meshes and transform nodes).
FBXLoader.loadFBXFromBuffer(buffer, baseDir, scene, options) — Load from ArrayBufferconst nodes = await FBXLoader.loadFBXFromBuffer(buffer, baseDir, scene, options);
| Parameter | Type | Description |
|---|---|---|
buffer |
ArrayBuffer |
Raw FBX file data |
baseDir |
string |
Base URL for resolving relative texture paths (e.g. "assets/models/") |
scene |
BABYLON.Scene |
Target Babylon.js scene |
options |
object |
Optional settings (see below) |
| Option | Type | Default | Description |
|---|---|---|---|
animation |
boolean |
true |
Start animation playback automatically |
animationTime |
number |
0 |
Initial animation time in seconds |
fbx-loader.js automatically registers itself as a Babylon.js Scene Loader Plugin when included, enabling the standard scene loader API for .fbx files.
// Babylon.js v9+: pass a single full URL
const result = await BABYLON.ImportMeshAsync('https://example.com/assets/model.fbx', scene);
console.log(result.meshes); // BABYLON.Mesh[]
console.log(result.skeletons); // BABYLON.Skeleton[]
// Load into an AssetContainer (can be added/removed from scene later)
const container = await BABYLON.LoadAssetContainerAsync('https://example.com/assets/model.fbx', scene);
container.addAllToScene();
Loader options can be passed via pluginOptions:
const result = await BABYLON.ImportMeshAsync('https://example.com/assets/model.fbx', scene, {
pluginOptions: { fbx: { animation: false, animationTime: 2.0 } },
});
To register manually, use FBXLoader.createPlugin():
BABYLON.RegisterSceneLoaderPlugin({
name: 'fbx',
extensions: '.fbx',
createPlugin: (opts) => FBXLoader.createPlugin(opts?.fbx ?? {}),
});
For Babylon.js v8 and earlier, use the SceneLoader class methods with a split rootUrl + fileName:
const result = await BABYLON.SceneLoader.ImportMeshAsync('', 'https://example.com/assets/', 'model.fbx', scene);
When a skinned animation is present, the root node’s metadata.fbxAnimationControls contains an array of animation control objects.
const nodes = await FBXLoader.loadFBX(url, scene);
// Find the root node (__root__)
const root = nodes.find(n => n.name === '__root__');
const controls = root?.metadata?.fbxAnimationControls ?? [];
// Each control exposes:
const ctrl = controls[0];
ctrl.name; // animation stack name (string)
ctrl.duration; // total duration in seconds (number)
ctrl.time; // current playback time (number)
ctrl.playing; // true if playing (boolean)
ctrl.setTime(t); // seek to time t (seconds)
ctrl.setPlaying(bool); // play or pause
ctrl.dispose(); // clean up observer when done
The root node’s metadata.fbxSkeletons contains an array of BABYLON.Skeleton objects for the loaded model.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="fbx-loader.js"></script>
</head>
<body>
<canvas id="c" style="width:100%;height:100vh"></canvas>
<script>
const canvas = document.getElementById('c');
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera('cam', -Math.PI / 2, Math.PI / 2.5, 5, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);
// Direct load via FBXLoader.loadFBX
FBXLoader.loadFBX('model.fbx', scene, { animation: true }).then(nodes => {
console.log('Loaded nodes:', nodes.length);
});
// Or via the Scene Loader Plugin (auto-registered when fbx-loader.js is included)
// await BABYLON.ImportMeshAsync('https://example.com/model.fbx', scene); // v9+
// await BABYLON.SceneLoader.ImportMeshAsync('', '', 'model.fbx', scene); // v8
engine.runRenderLoop(() => scene.render());
window.addEventListener('resize', () => engine.resize());
</script>
</body>
</html>
The example viewer also accepts these query parameters:
| Parameter | Example | Description |
|---|---|---|
model |
?model=monkey |
Select a bundled model by name |
url |
?url=https://…/model.fbx |
Load an arbitrary FBX URL |
scale |
?scale=0.01 |
Override the model scale |
animation |
?animation=0 |
Disable auto-play (0 / false / off) |
time |
?time=1.5 |
Set the initial animation time (seconds) |
The Babylon.js sample uses a custom FBX parser supporting both binary and ASCII formats. It currently focuses on static mesh loading, transform hierarchy validation, basic skinning data, and sampled skeleton animation.
Supported or partially supported:
DeformPercent animation. In-between shapes (multi-FullWeights) currently use only the final shape.