So far, we've focused on loading single models and textures. But real-world 3D scenes are rarely composed of just one asset. You'll often need to load multiple models, several textures for different materials, or even a combination of both. Fortunately, Three.js provides robust ways to handle this efficiently. The key to managing multiple assets lies in understanding how to initiate and track multiple asynchronous loading operations.
The THREE.LoadingManager is your best friend when dealing with multiple assets. It acts as a central hub for all loading operations. You can assign it to various loaders (like GLTFLoader, TextureLoader, etc.), and it will keep track of how many tasks are pending and when they've all completed. This is crucial for knowing when your entire scene is ready to be displayed or interacted with.
const manager = new THREE.LoadingManager();
manager.onStart = function ( url, itemsLoaded, itemsTotal ) {
console.log( 'Started loading file: ' + url + '.' );
console.log( 'Loading progress: ' + itemsLoaded + '/' + itemsTotal );
};
manager.onLoad = function ( ) {
console.log( 'All files have been loaded.' );
// Now you can render your scene or enable user interaction
};
manager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
console.log( 'Loading file: ' + url + '.' );
console.log( 'Loading progress: ' + itemsLoaded + '/' + itemsTotal );
};
manager.onError = function ( url ) {
console.error( 'There was an error loading ' + url );
};The LoadingManager provides several callback functions that are invaluable for providing feedback to your users or orchestrating your application's logic: onStart, onLoad, onProgress, and onError. The onLoad callback is particularly important – it signifies that all the assets assigned to this manager have finished loading.
To use the LoadingManager, you simply create an instance of it and then pass that instance to the loaders you intend to use. Each loader that utilizes this manager will automatically report its status back to the manager.
const manager = new THREE.LoadingManager();
const gltfLoader = new THREE.GLTFLoader(manager);
const textureLoader = new THREE.TextureLoader(manager);
// Use gltfLoader to load models
gltfLoader.load('path/to/model1.glb', (gltf) => {
// ... handle model1
});
gltfLoader.load('path/to/model2.glb', (gltf) => {
// ... handle model2
});
// Use textureLoader to load textures
const texture1 = textureLoader.load('path/to/texture1.jpg');
const texture2 = textureLoader.load('path/to/texture2.png');
manager.onLoad = () => {
console.log('All assets loaded!');
// Add models to scene, apply textures, etc.
};In the example above, both GLTFLoader and TextureLoader are configured to use the same LoadingManager. When the manager.onLoad function is called, you can be confident that all the models and textures initiated through these loaders have been successfully loaded.
Consider a scenario where you have a complex scene with multiple interconnected models and various textures. The LoadingManager helps orchestrate the loading of all these components. You can even use the onProgress callback to display a loading bar to your users, improving the user experience significantly.
graph TD
A[Start Application] --> B{Create LoadingManager};
B --> C{Instantiate Loaders (e.g., GLTFLoader, TextureLoader)};
C --> D{Assign LoadingManager to Loaders};
D --> E[Load Model 1];
D --> F[Load Model 2];
D --> G[Load Texture 1];
E --> H{Loader Reports Progress to Manager};
F --> H;
G --> H;
H --> I{Manager Updates Progress Count};
I --> J{Are all items loaded?};
J -- No --> H;
J -- Yes --> K[Trigger manager.onLoad Callback];
K --> L[Render Scene/Enable Interaction];
By leveraging the THREE.LoadingManager, you can gracefully handle the asynchronous nature of loading multiple assets, ensuring your application is ready only when all necessary resources are available. This leads to a more stable and polished 3D web experience.