As you delve deeper into creating 3D web experiences with Three.js, loading external assets like 3D models and textures becomes a crucial skill. However, just like any other network operation, these loading processes can sometimes fail. It's essential to anticipate and gracefully handle these potential errors to provide a robust and user-friendly experience. Furthermore, for larger assets, showing the user some indication of progress can significantly improve their perception of the application's responsiveness.
Three.js provides built-in mechanisms to manage loading progress and errors. When you use loaders like GLTFLoader or TextureLoader, they emit events that you can listen to.
The primary event for monitoring loading progress is onProgress. This event fires periodically during the loading process and provides information about the total bytes loaded and the total bytes expected. You can use this data to update a progress bar or a textual indicator on your web page.
const loader = new GLTFLoader();
loader.load(
'path/to/your/model.gltf',
function (gltf) {
// Model loaded successfully
scene.add(gltf.scene);
},
function (xhr) {
// Progress callback
if (xhr.lengthComputable) {
const percentComplete = (xhr.loaded / xhr.total) * 100;
console.log(`${percentComplete.toFixed(2)}% loaded`);
// Update your UI element here (e.g., a progress bar)
}
},
function (error) {
// Error callback
console.error('An error happened:', error);
}
);The onError callback is where you'll handle any issues that arise during the loading of an asset. This could be due to a broken file path, network connectivity problems, or an improperly formatted asset. In this callback, you'll receive an error object that you can inspect to understand what went wrong. It's good practice to display a user-friendly message to the user, letting them know that the asset couldn't be loaded and perhaps suggesting what they can do (e.g., check their internet connection).
Consider a scenario where multiple assets are being loaded simultaneously. You might want to aggregate the progress of all these loadings to display a single, overall progress indicator. This often involves maintaining counters for loaded and total assets and calculating a combined percentage.
graph TD;
A[Start Loading Assets] --> B{Asset 1 Loading?};
B -- Yes --> C[Update Progress for Asset 1];
C --> D{Asset 1 Loaded?};
D -- No --> C;
D -- Yes --> E{Asset 2 Loading?};
B -- No --> E;
E -- Yes --> F[Update Progress for Asset 2];
F --> G{Asset 2 Loaded?};
G -- No --> F;
G -- Yes --> H[All Assets Loaded];
E -- No --> H;
For more complex applications, you might want to implement a more sophisticated loading manager. Three.js provides a LoadingManager class that can help you coordinate multiple loaders and provide a central point for handling progress and errors across all loaded assets.
const manager = new THREE.LoadingManager();
manager.onStart = function (url, itemsLoaded, itemsTotal) {
console.log('Started loading file:', url);
console.log(`Loaded ${itemsLoaded} of ${itemsTotal} files.`);
};
manager.onProgress = function (url, itemsLoaded, itemsTotal) {
console.log(`Progress: Loaded ${itemsLoaded} of ${itemsTotal} files.`);
// Update your overall progress bar here
};
manager.onLoad = function () {
console.log('All files loaded.');
// All assets are ready, show your 3D scene
};
manager.onError = function (url) {
console.error('There was an error loading:', url);
// Display an error message to the user
};
const textureLoader = new THREE.TextureLoader(manager);
const modelLoader = new GLTFLoader(manager);
textureLoader.load('path/to/texture.jpg', function (texture) {
// Use texture
});
modelLoader.load('path/to/model.gltf', function (gltf) {
// Use gltf scene
});When an error occurs, instead of crashing the application, consider providing a fallback. For example, if a texture fails to load, you could apply a default checkered material to the object. If a 3D model fails, you might display a placeholder or a simple geometric shape. This enhances the user's experience by still providing some visual feedback, even if it's not the intended final result.
Remember that network requests are asynchronous. This means that your code will continue to execute while the assets are being downloaded. Your progress and error handling logic should be designed to work within this asynchronous flow, ensuring that you only interact with loaded assets once they are confirmed to be ready.