Loaders
Loaders import external 3D models, textures, and other assets into Three.js scenes.
Model Loaders
GLTF/GLB Loader
Most recommended format for 3D models.
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
// Load GLTF/GLB model
loader.load(
'path/to/model.gltf',
gltf => {
// Success callback
const model = gltf.scene;
scene.add(model);
// Access animations
if (gltf.animations.length > 0) {
const mixer = new THREE.AnimationMixer(model);
const action = mixer.clipAction(gltf.animations[0]);
action.play();
}
},
progress => {
// Progress callback
console.log(
'Loading progress:',
(progress.loaded / progress.total) * 100 + '%'
);
},
error => {
// Error callback
console.error('Error loading model:', error);
}
);
OBJ Loader
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
const loader = new OBJLoader();
loader.load(
'path/to/model.obj',
object => {
// Scale and position
object.scale.set(0.1, 0.1, 0.1);
object.position.set(0, 0, 0);
// Apply material
object.traverse(child => {
if (child.isMesh) {
child.material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
}
});
scene.add(object);
},
progress => {
console.log('Loading progress:', progress);
},
error => {
console.error('Error loading OBJ:', error);
}
);
MTL Loader (Material Template Library)
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
const mtlLoader = new MTLLoader();
const objLoader = new OBJLoader();
mtlLoader.load('path/to/model.mtl', materials => {
materials.preload();
objLoader.setMaterials(materials);
objLoader.load('path/to/model.obj', object => {
scene.add(object);
});
});
FBX Loader
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
const loader = new FBXLoader();
loader.load(
'path/to/model.fbx',
object => {
// Scale model
object.scale.setScalar(0.01);
// Setup animations
if (object.animations.length > 0) {
const mixer = new THREE.AnimationMixer(object);
const action = mixer.clipAction(object.animations[0]);
action.play();
}
scene.add(object);
},
progress => {
console.log('Loading progress:', progress);
},
error => {
console.error('Error loading FBX:', error);
}
);
Collada (DAE) Loader
import { ColladaLoader } from 'three/examples/jsm/loaders/ColladaLoader.js';
const loader = new ColladaLoader();
loader.load('path/to/model.dae', collada => {
const model = collada.scene;
// Access animations
if (collada.animations.length > 0) {
const mixer = new THREE.AnimationMixer(model);
collada.animations.forEach(clip => {
const action = mixer.clipAction(clip);
action.play();
});
}
scene.add(model);
});
Texture Loaders
Texture Loader
const textureLoader = new THREE.TextureLoader();
// Load single texture
const texture = textureLoader.load('path/to/texture.jpg');
// Load with callbacks
const texture = textureLoader.load(
'path/to/texture.jpg',
texture => {
console.log('Texture loaded');
console.log('Dimensions:', texture.image.width, 'x', texture.image.height);
},
progress => {
console.log('Loading progress:', progress);
},
error => {
console.error('Error loading texture:', error);
}
);
// Configure texture
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);
Cube Texture Loader
const cubeTextureLoader = new THREE.CubeTextureLoader();
const cubeTexture = cubeTextureLoader.load([
'px.jpg',
'nx.jpg', // positive x, negative x
'py.jpg',
'ny.jpg', // positive y, negative y
'pz.jpg',
'nz.jpg', // positive z, negative z
]);
// Use as environment map
scene.environment = cubeTexture;
scene.background = cubeTexture;
HDR Loader
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
const loader = new RGBELoader();
loader.load('path/to/environment.hdr', texture => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
scene.environment = texture;
});
EXR Loader
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
const loader = new EXRLoader();
loader.load('path/to/texture.exr', texture => {
texture.mapping = THREE.EquirectangularReflectionMapping;
const material = new THREE.MeshStandardMaterial({
envMap: texture,
});
});
Font Loaders
Font Loader
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
const loader = new FontLoader();
loader.load('path/to/font.json', font => {
const textGeometry = new TextGeometry('Hello Three.js!', {
font: font,
size: 1,
height: 0.1,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelOffset: 0,
bevelSegments: 5,
});
const textMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const textMesh = new THREE.Mesh(textGeometry, textMaterial);
scene.add(textMesh);
});
Audio Loaders
Audio Loader
// Create audio listener
const listener = new THREE.AudioListener();
camera.add(listener);
// Create audio source
const sound = new THREE.Audio(listener);
// Load audio
const audioLoader = new THREE.AudioLoader();
audioLoader.load('path/to/sound.mp3', buffer => {
sound.setBuffer(buffer);
sound.setLoop(true);
sound.setVolume(0.5);
sound.play();
});
// Positional audio
const positionalAudio = new THREE.PositionalAudio(listener);
audioLoader.load('path/to/sound.mp3', buffer => {
positionalAudio.setBuffer(buffer);
positionalAudio.setRefDistance(20);
positionalAudio.play();
});
// Attach to object
soundObject.add(positionalAudio);
Loading Manager
Basic Loading Manager
const loadingManager = new THREE.LoadingManager();
loadingManager.onStart = (url, itemsLoaded, itemsTotal) => {
console.log('Started loading:', url);
};
loadingManager.onLoad = () => {
console.log('Loading complete');
hideLoadingScreen();
};
loadingManager.onProgress = (url, itemsLoaded, itemsTotal) => {
const progress = (itemsLoaded / itemsTotal) * 100;
console.log(`Loading progress: ${progress}%`);
updateProgressBar(progress);
};
loadingManager.onError = url => {
console.error('Error loading:', url);
};
// Use with loaders
const textureLoader = new THREE.TextureLoader(loadingManager);
const gltfLoader = new GLTFLoader(loadingManager);
Progress Tracking
class LoadingProgress {
constructor() {
this.loadingManager = new THREE.LoadingManager();
this.progressElement = document.getElementById('progress');
this.loadingScreen = document.getElementById('loading-screen');
this.setupEventListeners();
}
setupEventListeners() {
this.loadingManager.onProgress = (url, itemsLoaded, itemsTotal) => {
const progress = (itemsLoaded / itemsTotal) * 100;
this.updateProgress(progress);
};
this.loadingManager.onLoad = () => {
this.hideLoadingScreen();
};
}
updateProgress(progress) {
this.progressElement.style.width = `${progress}%`;
this.progressElement.textContent = `${Math.round(progress)}%`;
}
hideLoadingScreen() {
this.loadingScreen.style.display = 'none';
}
getManager() {
return this.loadingManager;
}
}
const loadingProgress = new LoadingProgress();
const textureLoader = new THREE.TextureLoader(loadingProgress.getManager());
Asset Optimization
Texture Compression
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
const ktx2Loader = new KTX2Loader();
ktx2Loader.setTranscoderPath('path/to/basis/');
ktx2Loader.detectSupport(renderer);
ktx2Loader.load('path/to/texture.ktx2', texture => {
const material = new THREE.MeshStandardMaterial({
map: texture,
});
});
Draco Compression
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('path/to/draco/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load('path/to/compressed-model.gltf', gltf => {
scene.add(gltf.scene);
});
Async Loading
Promise-based Loading
function loadModel(url) {
return new Promise((resolve, reject) => {
const loader = new GLTFLoader();
loader.load(
url,
gltf => resolve(gltf),
undefined,
error => reject(error)
);
});
}
// Usage
async function loadAssets() {
try {
const model = await loadModel('path/to/model.gltf');
scene.add(model.scene);
} catch (error) {
console.error('Failed to load model:', error);
}
}
Multiple Assets
async function loadMultipleAssets() {
const promises = [
loadModel('model1.gltf'),
loadModel('model2.gltf'),
loadTexture('texture1.jpg'),
loadTexture('texture2.jpg'),
];
try {
const results = await Promise.all(promises);
const [model1, model2, texture1, texture2] = results;
scene.add(model1.scene);
scene.add(model2.scene);
// Use textures
material.map = texture1;
material.normalMap = texture2;
} catch (error) {
console.error('Failed to load assets:', error);
}
}
Error Handling
Retry Logic
function loadWithRetry(url, maxRetries = 3) {
return new Promise((resolve, reject) => {
let attempts = 0;
function attemptLoad() {
const loader = new GLTFLoader();
loader.load(
url,
gltf => resolve(gltf),
undefined,
error => {
attempts++;
if (attempts < maxRetries) {
console.log(`Retry ${attempts}/${maxRetries} for ${url}`);
setTimeout(attemptLoad, 1000 * attempts);
} else {
reject(error);
}
}
);
}
attemptLoad();
});
}
Fallback Assets
async function loadWithFallback(primaryUrl, fallbackUrl) {
try {
return await loadModel(primaryUrl);
} catch (error) {
console.warn('Primary asset failed, using fallback:', error);
return await loadModel(fallbackUrl);
}
}
Performance Tips
// Dispose of loaded assets when not needed
model.traverse(child => {
if (child.isMesh) {
child.geometry.dispose();
child.material.dispose();
}
});
// Reuse geometries and materials
const sharedGeometry = new THREE.BoxGeometry(1, 1, 1);
const sharedMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
for (let i = 0; i < 100; i++) {
const mesh = new THREE.Mesh(sharedGeometry, sharedMaterial);
scene.add(mesh);
}
// Use texture atlases
const atlasTexture = textureLoader.load('texture-atlas.png');
const material = new THREE.MeshStandardMaterial({ map: atlasTexture });