What Is glTF?
glTF — GL Transmission Format — is a royalty-free open standard for 3D scenes and models, developed and maintained by the Khronos Group (the same consortium behind OpenGL, Vulkan, WebGL, and OpenCL). First released as version 1.0 in 2015 and significantly revised in version 2.0 (2017), glTF is designed to be the "JPEG of 3D" — a compact, efficient, GPU-ready runtime format for delivering 3D content over the web and embedding it in applications.
Unlike CAD-oriented formats (STEP, IFC) or DCC-oriented formats (FBX, Blender's .blend), glTF is specifically optimized for real-time rendering — the data structures inside a glTF file mirror what a GPU needs directly, minimizing the parsing overhead between loading a file and displaying it in a WebGL, Vulkan, or Metal renderer.
Two File Variants
| Variant | Extension | Structure |
|---|---|---|
| glTF | .gltf + .bin + texture files |
JSON manifest referencing separate binary and texture files |
| GLB | .glb |
Single binary file containing all data — JSON + binary buffer + textures |
GLB is the preferred format for distribution — everything in one file, no broken links, easier to serve from a web server or embed in an email. Unpack any .glb file to inspect its internals (the structure starts with a 12-byte binary header followed by JSON and binary chunks).
glTF JSON Structure
A glTF file is a JSON document with top-level arrays for each component type:
{
"asset": {
"version": "2.0",
"generator": "Blender 4.1.0 glTF 2.0 exporter"
},
"scene": 0,
"scenes": [{"name": "Scene", "nodes": [0]}],
"nodes": [
{
"name": "Cube",
"mesh": 0,
"translation": [0.0, 0.0, 0.0],
"rotation": [0.0, 0.0, 0.0, 1.0],
"scale": [1.0, 1.0, 1.0]
}
],
"meshes": [
{
"name": "Cube",
"primitives": [
{
"attributes": {
"POSITION": 0,
"NORMAL": 1,
"TEXCOORD_0": 2
},
"indices": 3,
"material": 0,
"mode": 4
}
]
}
],
"materials": [...],
"textures": [...],
"images": [...],
"samplers": [...],
"accessors": [...],
"bufferViews": [...],
"buffers": [{"uri": "scene.bin", "byteLength": 24576}]
}
The accessors and bufferViews form a typed-array view system — they specify exact byte ranges, component types (FLOAT, UNSIGNED_SHORT, etc.), and data shapes (VEC3, VEC4, MAT4) within the binary buffer. This mirrors how WebGL and Vulkan bind vertex data directly.
PBR Materials: Physically Based Rendering
glTF 2.0 mandates a metallic-roughness PBR material model — the same model used by Unreal Engine, Unity, and major game engines:
{
"name": "CopperMetal",
"pbrMetallicRoughness": {
"baseColorFactor": [0.955, 0.638, 0.538, 1.0],
"metallicFactor": 1.0,
"roughnessFactor": 0.2,
"baseColorTexture": {"index": 0},
"metallicRoughnessTexture": {"index": 1}
},
"normalTexture": {"index": 2, "scale": 1.0},
"occlusionTexture": {"index": 3, "strength": 1.0},
"emissiveTexture": {"index": 4},
"emissiveFactor": [0.0, 0.0, 0.0],
"doubleSided": false,
"alphaMode": "OPAQUE"
}
The material pack maps directly to renderer uniforms:
baseColorTexture/baseColorFactor— albedo (the base color)metallicFactor(0=dielectric/plastic, 1=metal) androughnessFactor(0=mirror, 1=matte)normalTexture— tangent-space normal map for surface detail without extra geometryocclusionTexture— pre-baked ambient occlusionemissiveFactor— self-illumination (for screens, lights, glowing elements)
Animations and Skinning
glTF 2.0 supports full skeletal animation with keyframe interpolation:
"animations": [
{
"name": "Walk",
"channels": [
{
"sampler": 0,
"target": {"node": 5, "path": "rotation"}
}
],
"samplers": [
{
"input": 10, /* accessor: time values */
"output": 11, /* accessor: rotation quaternions per keyframe */
"interpolation": "LINEAR"
}
]
}
]
Interpolation modes: LINEAR (slerp for rotations), STEP (instant snap), CUBICSPLINE (smooth Hermite curves with tangents).
Morph targets (blend shapes) for facial animation:
"primitives": [{
"attributes": {"POSITION": 0},
"targets": [
{"POSITION": 5}, /* morph target 0: "smile" offset positions */
{"POSITION": 6} /* morph target 1: "blink" offset positions */
]
}]
Skinning uses a joint/weight system:
"attributes": {
"POSITION": 0,
"JOINTS_0": 4, /* bone indices per vertex (uvec4) */
"WEIGHTS_0": 5 /* bone weights per vertex (vec4, sums to 1.0) */
}
Draco Mesh Compression
The KHR_draco_mesh_compression extension uses Google's Draco library for geometry compression:
"extensions": {
"KHR_draco_mesh_compression": {
"bufferView": 0,
"attributes": {
"POSITION": 0,
"NORMAL": 1,
"TEXCOORD_0": 2
}
}
}
Draco compresses vertex positions through quantization (e.g., 16-bit integer precision for positions within the bounding box) and connectivity data using edge-breaker encoding. Typical compression ratios: 5–15× versus uncompressed glTF binary. Supported natively by Three.js (DRACOLoader), Babylon.js, and the Khronos gltf-transform toolkit.
Working with glTF in JavaScript (Three.js)
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({ antialias: true });
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 1.5, 3);
// Set up Draco decoder
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');
// Load glTF/GLB
const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
loader.load('character.glb', (gltf) => {
scene.add(gltf.scene);
// Play animation
const mixer = new THREE.AnimationMixer(gltf.scene);
const action = mixer.clipAction(gltf.animations[0]);
action.play();
// Render loop
function animate(time) {
requestAnimationFrame(animate);
mixer.update(time * 0.001);
renderer.render(scene, camera);
}
animate(0);
});
Working with glTF in Python
trimesh for geometry access:
import trimesh
mesh = trimesh.load("model.glb")
# For a scene with multiple meshes:
if isinstance(mesh, trimesh.scene.Scene):
for name, geom in mesh.geometry.items():
print(f"Mesh '{name}': {len(geom.vertices)} vertices, {len(geom.faces)} triangles")
else:
print(f"Vertices: {len(mesh.vertices)}, Faces: {len(mesh.faces)}")
print(f"Bounds: {mesh.bounds}")
pygltflib for full JSON/binary access:
from pygltflib import GLTF2
gltf = GLTF2().load("scene.gltf")
print(f"Meshes: {len(gltf.meshes)}")
print(f"Materials: {len(gltf.materials)}")
print(f"Animations: {len(gltf.animations)}")
print(f"Nodes: {len(gltf.nodes)}")
glTF Extensions Ecosystem
The extension system allows optional capabilities beyond the core spec:
| Extension | Purpose |
|---|---|
KHR_draco_mesh_compression |
Draco geometry compression |
KHR_texture_basisu |
KTX2 + Basis Universal texture compression (GPU-native) |
KHR_materials_clearcoat |
Lacquer/varnish layer (car paint, nail polish) |
KHR_materials_transmission |
Glass, transparent refractive materials |
KHR_materials_volume |
Volumetric absorption (colored glass, gemstones) |
KHR_materials_unlit |
Disable PBR lighting for UI, sprites |
KHR_lights_punctual |
Point, spot, and directional lights in the scene |
EXT_mesh_gpu_instancing |
GPU instancing for repeated objects (forests, crowds) |
KHR_animation_pointer |
Animate any JSON property, not just node transforms |
KHR_xmp_json_ld |
XMP metadata for copyright, authorship |
glTF vs OBJ vs FBX
| Feature | glTF 2.0 | OBJ | FBX |
|---|---|---|---|
| Open standard | Yes (Khronos) | De facto | Proprietary (Autodesk) |
| PBR materials | Yes (metallic-roughness) | No (Phong only) | Partial |
| Animation | Yes (skeletal, morph) | No | Yes |
| Skinning | Yes | No | Yes |
| Binary variant | GLB | No | Yes (.fbx binary) |
| Compression | Draco, KTX2 | No | Internal |
| Web native | Yes (WebGL, WebGPU) | Plugin needed | Plugin needed |
| AR support | Yes (iOS, Android) | Limited | Limited |
AR and Real-Time Use Cases
- Apple AR Quick Look: iOS/iPadOS displays
.usdzand.realitynatively, but glTF → USDZ conversion via Reality Converter is the standard pipeline - Google model-viewer:
<model-viewer src="scene.glb">— one HTML tag to embed a 3D model with AR mode on Android - Meta Quest / WebXR: glTF 2.0 is the primary scene graph format for WebXR experiences
- Google Maps / Immersive View: 3D building assets in glTF
- Sketchfab: the dominant 3D model sharing platform uses glTF as its primary interchange
Related conversions
Most teams that read this guide convert images in one of these directions: