Loading glTF and 3D Models in Babylon.js
Every web game reaches a point where primitive shapes are not enough and you need real 3D models: characters, vehicles, environments, weapons, and props. Getting these models from a 3D authoring tool into a running Babylon.js scene involves choosing the right file format, exporting correctly, loading at runtime, and optimizing for browser delivery. Each step has decisions that affect both visual quality and loading performance.
Step 1: Install the Loaders Package
If you are using Babylon.js via npm, the model loaders are in a separate package. Run npm install @babylonjs/loaders and import the specific loader you need. For glTF, import @babylonjs/loaders/glTF. This registers the glTF loader with the SceneLoader so it knows how to handle .gltf and .glb files. If you are using the CDN, include the babylon.loaders.min.js script after the core library.
The loaders package supports multiple formats. The glTF loader handles both text-based .gltf files (with separate .bin and texture files) and binary .glb files (everything packed into one file). The OBJ loader handles Wavefront OBJ with MTL material files. The STL loader handles stereolithography files, which are geometry-only with no materials or animations. For games, glTF is almost always the right choice because it includes materials, animations, and skeleton data in a single standardized format.
Step 2: Export from Your 3D Tool
Blender has a built-in glTF exporter that works well with Babylon.js. In Blender, go to File, Export, glTF 2.0. Choose GLB format for a single binary file, or glTF Separate for text-based glTF with external texture files. Under the export settings, enable "Apply Modifiers" to bake any modifiers into the geometry, and check "Include" to select which data to export (mesh, animation, skinning, shape keys).
For Maya and 3ds Max, the Khronos Group maintains official glTF exporters. Autodesk also includes glTF export support in recent versions of both tools. When exporting from Maya, make sure "Animation" is checked if your model has keyframe data, and verify that the material export mode is set to PBR (metallic-roughness) rather than Phong, which does not translate cleanly to glTF.
Common export issues include incorrect scale (Blender uses meters, some engines use centimeters), flipped UV channels, missing textures, and broken animation references. The Babylon.js Sandbox at sandbox.babylonjs.com lets you drag and drop a glTF file to preview it instantly, which is invaluable for catching these issues before writing any code.
Step 3: Load the Model at Runtime
The simplest loading method is SceneLoader.ImportMeshAsync. Call it with an empty string for the mesh names (loads all meshes), the file path, and the filename: BABYLON.SceneLoader.ImportMeshAsync("", "/models/", "character.glb", scene). This returns a promise that resolves with an object containing meshes, particleSystems, skeletons, and animationGroups.
For more control, use SceneLoader.LoadAssetContainerAsync. This loads the file into a container without adding anything to the scene. You can then inspect the meshes, modify materials, and selectively add objects with container.addAllToScene(). This is useful when you need to clone models, merge materials, or make adjustments before the player sees the model.
The SceneLoader.Append method loads a file and adds its content to an existing scene, merging with whatever is already there. This is useful for loading environment sections incrementally, such as loading dungeon rooms as the player explores. Each appended file merges its meshes, lights, and cameras into the existing scene graph.
Step 4: Position and Scale the Model
Loaded models often need adjustment to fit your scene. The root mesh (usually the first element of the returned meshes array) is a transform node that you can position, rotate, and scale. Set rootMesh.position to place the model, rootMesh.rotation to orient it, and rootMesh.scaling to resize it. All child meshes transform with the root.
Coordinate system differences between tools cause frequent confusion. Blender uses Z-up, while Babylon.js uses Y-up. The glTF exporter handles this conversion automatically, so models exported from Blender should appear correctly oriented. If a model appears sideways or upside-down, check whether the exporter applied the coordinate conversion, and verify that the model's transforms were applied (Ctrl+A in Blender) before export.
Scale mismatches happen when the authoring tool uses different units. A model created in centimeters will appear 100 times too large in a scene that uses meters. Either fix the scale in the 3D tool before export, or set rootMesh.scaling = new BABYLON.Vector3(0.01, 0.01, 0.01) to compensate. Fixing at the source is always preferable because it keeps the numbers in your code clean.
Step 5: Compress Textures with KTX2
Textures are typically the largest part of a 3D model file. A single 2048x2048 RGBA texture uses 16MB of GPU memory uncompressed. KTX2 with Basis Universal compression reduces this to 2-4MB while maintaining visual quality. The compressed textures also download faster, which directly improves loading times for players on slower connections.
To use KTX2 in Babylon.js, convert your PNG or JPEG textures using the toktx command-line tool from the Khronos KTX-Software package. The tool compresses textures into the Basis Universal format and wraps them in a KTX2 container. At runtime, Babylon.js transcodes the compressed data into the optimal GPU format for the user's device: BC7 on desktop, ASTC on modern mobile, or ETC2 as a fallback.
Enable KTX2 support in Babylon.js by setting scene.environmentTexture to a KTX2 file and configuring the KTX2 decoder. The decoder runs as a Web Worker to avoid blocking the main thread during transcoding. For production, host the decoder files (basis_transcoder.wasm and basis_transcoder.js) on your CDN alongside your game assets.
Step 6: Set Up the Asset Manager for Multiple Models
Games typically load many assets simultaneously: character models, environment pieces, sound effects, textures, and configuration files. The AssetsManager coordinates these parallel downloads with progress tracking and error handling. Create one with new BABYLON.AssetsManager(scene), add tasks for each asset, and call assetsManager.loadAsync() to start all downloads.
Add mesh tasks with assetsManager.addMeshTask("taskName", "", "/models/", "filename.glb"). Each task has onSuccess and onError callbacks where you can process the loaded asset or handle failures. The onProgress callback on the manager itself reports overall progress as a percentage, which you can display as a loading bar.
For texture preloading, use addTextureTask. For binary data files (like sound effects or configuration JSON), use addBinaryFileTask. The Asset Manager downloads all tasks in parallel using the browser's connection pool, typically six simultaneous connections per domain. For games with many assets, consider splitting files across subdomains or using HTTP/2 to increase parallelism.
Use GLB for single-file delivery, compress textures with KTX2 for mobile performance, and preview every export in the Babylon.js Sandbox before writing loading code. The export pipeline matters as much as the runtime code.