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 + texturessingle binary, everything embedded
Human-readableShip-ready
Multiple HTTP fetchesOne fetch
Good for dev, debugGood 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, liquids
  • KHR_materials_clearcoat — car paint, varnish
  • KHR_lights_punctual — lights baked into scene
  • KHR_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.