How to Optimize glTF/.glb Files for Faster 3D Loading in Web Projects
This article explains the glTF format, compares .gltf and .glb, shows how to split and compress glTF assets using tools like gltf‑pipeline, Draco, mesh quantization and meshopt, and presents performance tests across various devices to guide efficient 3D model delivery in web applications.
Introduction
When developing interactive 3D projects, three key questions arise: which export format to use for 3D models, how to optimise the model files, and how the solution scales under high traffic.
What is a glTF file
glTF (Graphics Language Transmission Format) is the standard file format for 3D scenes and models. Its core is a JSON document that describes the scene hierarchy, meshes, materials, animations, skins and cameras. Binary data and image resources are referenced or embedded.
.gltf vs .glb
.gltf files are JSON/ASCII and may reference external binary buffers and textures, while .glb files are binary containers that embed all resources, eliminating extra HTTP requests.
.glb file origin
glTF offers two delivery options: JSON pointing to external binaries, or JSON embedding base64‑encoded binaries. Base64 adds about 33% overhead, so the binary container format (.glb) was introduced to reduce request count and size.
Splitting glTF files
glTF assets can be split into a .gltf/.glb file, separate .bin buffers, and texture images. By extracting these components and compressing textures individually, loading performance improves.
Use gltf-pipeline to perform the following operations:
Convert between .gltf and .glb
Save buffers/textures as embedded or external files
Upgrade glTF 1.0 models to glTF 2.0 (using KHR_techniques_webgl and KHR_blend)
Apply Draco mesh compression
Example command to compress a .glb file:
gltf-pipeline -i male.glb -o male-processed.glb -sLoad the resulting files with Three.js:
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
const loader = new GLTFLoader();
loader.load(MODEL_FILE_PATH, (gltf) => {
// ...
});glTF Compression Techniques
KHR_draco_mesh_compression
Draco is an open‑source algorithm that compresses mesh geometry and point clouds, dramatically reducing file size but requiring additional decoding time on the client.
Compression command:
gltf-pipeline -i male.glb -o male-processed.glb -dThree.js usage with DRACOLoader:
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath(DECODER_PATH);
loader.setDRACOLoader(dracoLoader);
loader.load(MODEL_FILE_PATH, (gltf) => {
// ...
});A 3.2 MB glb reduced to 1.8 MB (≈56% of original). Including the two decoder WASM files, the effective compression ratio is about 62.5%.
KHR_mesh_quantization
This extension quantises vertex attributes from 32‑bit floats to 16‑bit or 8‑bit integers, cutting per‑vertex size from ~48 bytes to ~20 bytes.
Compression command (using gltfpack): gltfpack -i male.glb -o male-processed.glb Result: 3.2 MB → 1.9 MB (≈59.3% of original) with no visible quality loss.
EXT_meshopt_compression
Meshopt applies GPU‑friendly quantisation and reordering, then adds a fast WebAssembly‑based decoder that can decompress at ~1 GB/s.
Compression command: gltfpack -i male.glb -o male-processed.glb -cc Three.js usage with MeshoptDecoder:
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
const loader = new GLTFLoader();
loader.setMeshoptDecoder(MeshoptDecoder);
loader.load(MODEL_FILE_PATH, (gltf) => {
// ...
});Result: 3.2 MB → 1.1 MB (≈65.6% of original) with faster initial load and no quality degradation.
Device‑level performance comparison
Tests on iPhone 12 (iOS 14.4), Huawei Mate 40 Pro (HarmonyOS), Xiaomi Mix 2 (Android 8.0) and iPhone 6s Plus (iOS 13.7) measured load times and network impact. Draco‑compressed assets incurred higher decode latency, while mesh quantisation and meshopt provided the best balance of size reduction and load speed.
Conclusion
For projects that load a single model, using KHR_mesh_quantization or EXT_meshopt_compression for mesh compression, combined with gltf-pipeline to separate buffers and compress textures, offers the most effective optimisation.
Other useful extensions
EXT_mesh_gpu_instancing – supported in Babylon.js, not yet in Three.js GLTFLoader.
KHR_texture_basisu – texture compression extension.
EXT_texture_webp – WebP texture support.
References
glTF specification and tutorials –
https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_002_BasicGltfStructure.md.glb file format –
https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specificationKHR_draco_mesh_compression –
https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.mdKHR_mesh_quantization –
https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_mesh_quantization/README.mdEXT_meshopt_compression –
https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Vendor/EXT_meshopt_compression/README.mdglTF‑pipeline – https://github.com/CesiumGS/gltf-pipeline DRACOLoader docs –
https://threejs.org/docs/#examples/en/loaders/DRACOLoaderSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Aotu Lab
Aotu Lab, founded in October 2015, is a front-end engineering team serving multi-platform products. The articles in this public account are intended to share and discuss technology, reflecting only the personal views of Aotu Lab members and not the official stance of JD.com Technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
