// glTF / GLB models
Loading 3D models
Besides procedural shapes, flutter_fiber loads finished 3D models in glTF 2.0 format: a binary .glb, or a .gltf with its data embedded. A loaded model keeps its node hierarchy, PBR materials and textures, and sits in a Fiber3DCanvas like any other shape, lit by the same lights and environment.
Loading is two steps: parse the file into a Fiber3DGltfScene, then place that scene in the canvas with the Fiber3DGltfModel widget.
// demo
Demo
A 30-material car model loaded from a .glb with the code below, lit with ACES Filmic tone mapping and the default procedural sky.
// how to use it
How to use it
1. Put the model in your app and declare it under flutter: assets: in pubspec.yaml:
flutter:
assets:
- assets/YOUR_MODEL.glb2. Load the bytes, parse them, and show the scene. This is a complete widget you can drop into your app:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_fiber/flutter_fiber.dart';
class ModelViewer extends StatefulWidget {
const ModelViewer({super.key});
@override
State<ModelViewer> createState() => _ModelViewerState();
}
class _ModelViewerState extends State<ModelViewer> {
Fiber3DGltfScene? _scene;
Object? _error;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
try {
final data = await rootBundle.load('assets/YOUR_MODEL.glb');
final bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
final scene = await Fiber3DGltfLoader.loadGlb(bytes);
if (!mounted) return;
setState(() => _scene = scene);
} catch (e) {
if (!mounted) return;
setState(() => _error = e);
}
}
@override
Widget build(BuildContext context) {
if (_error != null) return Center(child: Text('Failed to load model:\n$_error'));
final scene = _scene;
if (scene == null) return const Center(child: CircularProgressIndicator());
return Fiber3DCanvas(
backgroundColor: 0x1a1a1a,
toneMapping: Fiber3DToneMapping.acesFilmic,
camera: Fiber3DCamera(
position: const Fiber3DVector3(0, 2, 8),
target: const Fiber3DVector3.zero(),
),
orbitEnabled: true,
lights: const [
Fiber3DAmbientLight(color: 0xffffff, intensity: 0.3),
Fiber3DPointLight(
color: 0xffffff,
intensity: 3.0,
position: Fiber3DVector3(4, 5, 5),
),
Fiber3DPointLight(
color: 0xffffff,
intensity: 1.5,
position: Fiber3DVector3(-4, 2, -2),
),
],
children: [Fiber3DGltfModel(scene: scene, scale: 1.0)],
);
}
}Scale and framing. glTF files disagree on real-world units (meters versus centimeters is common), so a model can arrive far smaller or larger than your camera expects. Use Fiber3DGltfModel.scale and the camera distance to frame it.
Rotating or moving a model. Wrap it in a Fiber3DGroup and drive that group's transform in onFrame:
Fiber3DGroup(
onFrame: (elapsed, delta, transform) {
final t = delta.inMicroseconds / 1e6;
transform.rotation.y += t * 0.5;
},
children: [Fiber3DGltfModel(scene: scene, scale: 1.0)],
)A .gltf with embedded data. Read the file as text and use loadEmbeddedGltf:
final text = await rootBundle.loadString('assets/YOUR_MODEL.gltf');
final scene = await Fiber3DGltfLoader.loadEmbeddedGltf(text);// api reference
API reference
Fiber3DGltfLoader.loadGlb(Uint8List bytes)
Parses a binary .glb. Returns Future<Fiber3DGltfScene>.
Fiber3DGltfLoader.loadEmbeddedGltf(String jsonText)
Parses a .gltf whose buffers and images are all base64 data URIs. You read the file text yourself. Returns Future<Fiber3DGltfScene>.
Fiber3DGltfModel(scene:, scale:)
Widget that adds a loaded scene to the canvas. scale (default 1.0) is a uniform scale applied to the whole model.
// supported & limits
Supported & limits
Supported
- .glb, and .gltf with embedded (data URI) buffers and images; PNG and JPEG images embedded in the file.
- The node hierarchy, with translation / rotation / scale or a single matrix per node.
- Triangle meshes with POSITION, NORMAL, TEXCOORD_0 and float COLOR_0 attributes, indexed or not.
- The metallic-roughness material: base color factor and texture, metallic and roughness factors, the combined metallic-roughness texture, emissiveFactor, and alphaMode BLEND (as transparency).
- KHR_materials_clearcoat (clearcoat factors) and KHR_materials_emissive_strength.
Not supported (yet)
- External .bin or image files referenced by URI.
- Primitives with more than 65,535 vertices (the loader throws a FormatException).
- Non-triangle primitives (lines, points, strips, fans) are skipped. Skinning, morph targets, animations, cameras and lights in the file are ignored.
- Normal, emissive and occlusion textures; alphaMode MASK (treated as opaque); texture wrap modes and UV transforms; normalized (non-float) vertex colors.
- Other KHR_materials_* extensions (specular, transmission and the rest) are ignored, so glass built with transmission renders as a plain alpha blend.
- There is no depth-sorted transparency pass, so a model with many alpha-blended parts can show sorting artifacts.