Three.js From Zero · Article s6-01
S6-01 glTF 2.0 Deep Dive
Season 6 · Article 01
glTF 2.0 — the format everything converges on
"JPEG for 3D." Khronos spec. Binary or JSON. Scene graph + meshes + materials + skins + animation + PBR + morph targets. Every major tool speaks it. Three.js imports it natively.
1. What's in a glTF file
{
"asset": { "version": "2.0", "generator": "..." },
"scenes": [ { "nodes": [0, 1] } ],
"nodes": [ { "mesh": 0, "translation": [0,0,0], "rotation": [...] } ],
"meshes": [ { "primitives": [ { "attributes": {...}, "indices": 0, "material": 0 } ] } ],
"materials": [ { "pbrMetallicRoughness": {...}, "normalTexture": {...} } ],
"textures": [ { "source": 0, "sampler": 0 } ],
"images": [ { "uri": "tex.png" } ],
"samplers": [ { "magFilter": 9729, "minFilter": 9987 } ],
"buffers": [ { "uri": "data.bin", "byteLength": 123456 } ],
"bufferViews":[ { "buffer": 0, "byteOffset": 0, "byteLength": 1000 } ],
"accessors": [ { "bufferView": 0, "componentType": 5126, "count": 100, "type": "VEC3" } ],
"skins": [...],
"animations": [...]
}
2. The accessor abstraction
Three-layer indirection: buffer → bufferView → accessor.
- buffer: raw byte blob (the .bin file).
- bufferView: a slice of the buffer.
- accessor: typed view — "this slice is 100 VEC3s of float32." Includes min/max.
Why? Multiple meshes can share buffer views. An animation and a mesh can interleave in one buffer. Decoder batches everything in a single read.
3. .gltf vs .glb
| .gltf | .glb |
|---|---|
| JSON + external .bin + textures | single binary, everything embedded |
| Human-readable | Ship-ready |
| Multiple HTTP fetches | One fetch |
| Good for dev, debug | Good for production |
4. Extensions (the extensibility play)
{
"extensionsUsed": [ "KHR_draco_mesh_compression", "KHR_texture_basisu", "KHR_materials_transmission" ],
"materials": [ {
"extensions": {
"KHR_materials_transmission": { "transmissionFactor": 1.0 }
}
} ]
}
Core is lean. Extensions add PBR transmission, clearcoat, sheen, volume, IOR, emissive strength, anisotropy, etc. Three.js's MeshPhysicalMaterial implements most.
5. Live demo — load & inspect a glTF
Loads a small model and prints the asset anatomy in the panel.
–
Parsed structure
loading…
6. Common extensions you'll see
KHR_draco_mesh_compression— Draco geo compression (S6-02)KHR_texture_basisu— KTX2/Basis textures (S6-03)EXT_meshopt_compression— Meshopt-compressed streams (S6-04)KHR_materials_transmission/_volume/_ior— glass, liquidsKHR_materials_clearcoat— car paint, varnishKHR_lights_punctual— lights baked into sceneKHR_animation_pointer— animate material properties, not just TRS
7. Validation
Always validate before shipping:
npm i -g gltf-validator
gltf-validator model.glb
Or the online tool: Khronos validator.
8. Three.js loader dance
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
const loader = new GLTFLoader();
const draco = new DRACOLoader().setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
const ktx2 = new KTX2Loader().setTranscoderPath('...').detectSupport(renderer);
loader.setDRACOLoader(draco);
loader.setKTX2Loader(ktx2);
loader.load('model.glb', (gltf) => scene.add(gltf.scene));
9. Takeaways
- glTF 2.0 = JSON scene graph + binary data + textures.
- .glb = one-file binary version. Ship this.
- Accessor/bufferView/buffer is three-layer indirection for efficient sharing.
- Extensions cover everything from Draco to transmission to clearcoat.
- Three.js loads it natively. Add Draco + KTX2 loaders for compressed variants.