Course outline
Loading Models
In one line
GLTFLoader.loadAsync(url) fetches and parses a model and gives you its scene. Then you measure it, scale it to real size, stand it on the floor, and handle the ways a load fails: a missing file, a file that is not a model, no network.
Think of it like this
A parcel arrives. Before it goes on the shelf you open it, check it is what you ordered, and see how big it is. A model from a file is the same: load it, then measure and place it, and know what to do when the parcel never comes.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- GLTFLoader
- The three.js add-on that reads .gltf and .glb files and builds three.js objects from them.
- gltf.scene
- The root
Groupof the loaded model: add this to your scene. - LoadingManager
- An object that loaders report to, so you can follow progress across many files and know when all are done.
- CORS
- Cross-Origin Resource Sharing: the server's permission, in a response header, for pages on other sites to read a file. Without it the browser blocks the read.
Step by step
01Load two very different models
The first example loads the course's bike and the Fox, measures each with Box3, scales it to a chosen length, and stands it on the floor. The console prints each size as loaded, the scale used, and the lowest point after: 0.000 for both.
02Read the Fox's numbers
154.72 along z means the fox is about 155 units long. A fox is about 0.9 m long, so the file's unit is roughly a centimetre. scale × 0.0058 converts it. Real-world files come in metres, centimetres, inches or no unit at all: always measure.
03Make a load fail three ways
The second example asks for a misspelled file, a text file and a server that does not exist, and prints each error's name and message (with the site's address cut off). Note that only the first message says what happened in words a person could act on.
04Turn errors into decisions
A 404 is a bug in your paths or deployment (Topic 18.6). A SyntaxError usually means the server sent an HTML page instead of the model: a wrong path that a single-page app's server answers with index.html. Failed to fetch means no network, a blocked request or CORS: retrying may help. Topic 10.4 shows the visitor something useful in each case.
Try it yourself
- 1
Leave the fox in centimetres
In the first example, change the fox's target length
0.9to154.72. Its scale becomesx1.0000and the fox is 155 m long: the picture shows two huge brown blocks (parts of the fox) hanging from the top edge, towering over the small bike, because the camera is now inside a 155 m animal. - 2
Turn the bike around
In the first example add
bike.rotation.y = Math.PI;after the linefox.position.x += 1.4;. The console is unchanged, but the bike now faces left: the handlebar and front wheel are on the left of the picture. The half turn happens about the model's own origin, so it also moves a little: a wrapperGroupat the centre avoids that. - 3
Load a model from a data URL
In the second example add a case
["a data URL", "data:text/plain,hello"]. It fails withSyntaxError: Unexpected token 'h', "hello" is not valid JSON: the loader accepted the URL and read its content as glTF JSON.
Code & diagrams
The bike is already in metres; the fox is not. Both end with their lowest point on the floor. Fox model by PixelMannen (CC0), rigging and animation by tomkranis (CC BY 4.0), glTF conversion by @AsoboStudio and @scurest (CC BY 4.0); the licences are the subject of Topic 10.6.
Console
Run the scene to see its console.Expected console output
bike as loaded: 1.83 x 0.92 x 0.56 | scale x0.9978 | lowest point now 0.000
fox as loaded: 25.19 x 79.03 x 154.72 | scale x0.0058 | lowest point now 0.000Console only. The address of the site is removed from the message, so the output is the same here and on your computer.
Console
Run the scene to see its console.Expected console output
a file that is not there:
Error: fetch for "/data/3d/models/lumen-bikee.glb" responded with 404: Not Found
a file that is not a model:
SyntaxError: Unexpected token '#', "# Assets o"... is not valid JSON
a server that is not reachable:
TypeError: Failed to fetchBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Forget to wait for the model
In the first example change (await loader.loadAsync("/data/3d/models/lumen-bike.glb")).scene to loader.loadAsync("/data/3d/models/lumen-bike.glb").scene.
Myth vs fact
Myth
If a model looks wrong, the file is broken.
Fact
Most "broken" models are fine: wrong units (a centimetre model is 100 times too big), a different up axis, or the origin far from the object. Measure it with Box3 before blaming the file.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
THREE.Cache.enabled = true(off by default) makes three.js keep downloaded files in memory; otherwise loading the same URL twice asks the browser again (its HTTP cache may answer), and either way the file is parsed again. For repeated parts, load once andclone()(useSkeletonUtils.clonefor skinned models, Topic 9.4). - ▸
loader.setPath("/data/3d/models/")sets a base path;loader.setResourcePath()sets where a .gltf's separate .bin and images are found. A .glb has everything inside, so it never needs a resource path.
Remember this
- 1
The problem this solves: a model made by someone else is in their units, facing their direction, standing wherever their scene's origin was. Put it in the showroom as it is and it may be a hundred times too big, under the floor, or behind the camera.
- 2
Loading.
const gltf = await new GLTFLoader().loadAsync(url)resolves with an object:gltf.scene(aGroupto add to your scene),gltf.animations(clips for Phase 9's mixer),gltf.cameras,gltf.asset(the file's version, generator, copyright) andgltf.parser. The callback formloader.load(url, onLoad, onProgress, onError)does the same with callbacks. Add-ons import fromthree/addons/loaders/GLTFLoader.js. - 3
Measure, scale, place.
new THREE.Box3().setFromObject(model)gives its size in your units. The course's bike arrives 1.83 × 0.92 × 0.56 m (the handlebar is 0.56 m wide): right already. The Fox arrives 25.19 × 79.03 × 154.72: it was made in centimetres, so it needsscale× 0.0058 to be 0.9 m long. Then move it so its centre is over the origin and its lowest point is at y = 0, as the first example'sfit()does. - 4
How a load fails, and what you see. A wrong path:
Error: fetch for "/data/3d/models/lumen-bikee.glb" responded with 404: Not Found. A file that is not a model (an HTML error page, a text file):SyntaxError: Unexpected token '#', "# Assets o"... is not valid JSON, because the loader tried to read it as glTF JSON. No network:TypeError: Failed to fetch. A server that forgets CORS headers fails the same way as no network, with the real reason only in the browser's console. A wrongContent-Typeon a.glb(for exampletext/plain) is harmless: the loader reads bytes and checks the file's ownglTFmagic, not the label. The case that hurts is a server that answers200with an HTML page. - 5
A model facing the wrong way. glTF says up is +Y and the front of a model faces +Z. A model from a tool that treats Z as up lies on its back (rotate it -90° about x), and a model that faces away needs a half turn (
model.rotation.y = Math.PI). Put the loaded scene inside aGroupand turn the group: the correction then lives in one place, and the model's own transform stays as the artist made it. - 6
Several files at once. A
LoadingManagerpassed to loaders (new GLTFLoader(manager)) counts every item they start: models, and also textures inside models.onProgress(url, loaded, total)andonLoad()let one loading bar cover everything. In a real run with the Fox, a JPEG and one missing file the manager's total reached 6, not 3: the Fox's own texture counts too, and the missing file's error was reported twice. Treat the total as a growing number, not a fixed one.
Explain it without notes
A model loads but nothing appears. Name three things you would check, in order.
What does SyntaxError: Unexpected token '<' usually mean when loading a .glb, and how do you confirm it?
Practice
Write fitToLength(object, metres) that scales an object so its longest side has that length and puts its lowest point at y = 0.
Load the Fox and print the names of its animation clips and its node count.
Done when you can
Load a model with GLTFLoader and add its scene
Measure a model and fit it to a real size on the floor
Read the three common load errors and say what each means
Follow several loads with a LoadingManager