Three.js LoadingManager: Track Asset Loading Progress
In web-based 3D applications, loading heavy assets like 3D models,
textures, and audio files can heavily impact user experience. This
article explores the Three.js LoadingManager, explaining
how it serves as a central hub to globally track the loading progress of
all your scene assets, and how you can use its built-in event hooks to
build functional loading screens.
What is the LoadingManager?
The LoadingManager is a built-in Three.js class designed
to coordinate and monitor the loading status of multiple external files.
Instead of tracking each loader (such as GLTFLoader,
TextureLoader, or FontLoader) individually,
you can pass a single LoadingManager instance to all of
them. The manager then aggregates their progress, giving you a unified
way to handle loading states.
How Global Tracking Works
When you instantiate a loader in Three.js, you can optionally pass a
LoadingManager as an argument to its constructor. Once
passed, the loader automatically registers its network requests with
that manager.
If you do not pass a custom manager to your loaders, Three.js
automatically assigns them to a global default instance called
THREE.DefaultLoadingManager. You can configure this default
manager directly if you want to track all loading activity across your
entire application without passing a manager to every individual
loader.
Key Callback Functions
The LoadingManager provides four essential callback
properties that you can define to handle different stages of the loading
process:
onStart: Triggered when the first asset begins loading. It receives the URL of the first item, the number of items loaded so far (usually 0), and the total number of items to be loaded.onProgress: Triggered every time an individual asset finishes loading. It receives the URL of the loaded asset, the number of items currently loaded, and the total number of items. This is the callback used to update progress bars or loading percentages (e.g.,(itemsLoaded / itemsTotal) * 100).onLoad: Triggered only when all registered files have successfully finished loading. This is where you typically dismiss your loading screen and render your 3D scene.onError: Triggered when a loader encounters an error fetching a specific file, allowing you to handle broken paths or network failures.
Code Implementation
Here is a practical example of how to set up and use the
LoadingManager with multiple loaders:
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
// 1. Create the LoadingManager
const loadingManager = new THREE.LoadingManager();
// 2. Define the callbacks
loadingManager.onStart = function (url, itemsLoaded, itemsTotal) {
console.log(`Started loading: ${url}. Loaded ${itemsLoaded} of ${itemsTotal} files.`);
};
loadingManager.onProgress = function (url, itemsLoaded, itemsTotal) {
const progressPercent = (itemsLoaded / itemsTotal) * 100;
console.log(`Loading: ${progressPercent.toFixed(0)}%`);
// Update your HTML progress bar element here
};
loadingManager.onLoad = function () {
console.log('All assets loaded successfully! Ready to render scene.');
// Hide loading screen and start the animation loop here
};
loadingManager.onError = function (url) {
console.error(`There was an error loading ${url}`);
};
// 3. Pass the manager to your loaders
const textureLoader = new THREE.TextureLoader(loadingManager);
const gltfLoader = new GLTFLoader(loadingManager);
// 4. Load your assets
const colorTexture = textureLoader.load('textures/color.jpg');
gltfLoader.load('models/character.gltf', (gltf) => {
scene.add(gltf.scene);
});By leveraging the LoadingManager, you avoid writing
complex asynchronous tracking logic yourself. It keeps your code clean
and provides a reliable way to ensure your users are greeted with a
smooth, informative loading experience.