Compressing Binary glTF Assets for Version Control
Binary glTF (.glb) files present significant challenges
in version control systems like Git due to their monolithic binary
nature, which causes repository bloat and prevents delta compression.
This article examines the most effective compression techniques and
workflow strategies—including geometry compression with Draco and
Meshopt, texture decoupling, and Git Large File Storage (LFS)
configuration—to keep 3D asset repositories lightweight, maintainable,
and fast to synchronize.
The Core Challenge of Binary glTF in VCS
A standard .glb file packages 3D model geometry, scene
hierarchy, animations, and image textures into a single binary blob.
Version control systems (VCS) like Git are designed for line-by-line
text diffing. When a .glb asset is modified—even by moving
a single vertex or tweaking an embedded texture—the internal byte layout
shifts dramatically. Git cannot create efficient binary deltas for
packed assets, forcing it to store a nearly complete duplicate of the
file with every commit, leading to rapid repository growth.
Geometry Compression: Draco vs. Meshopt
Geometry data accounts for a large portion of untextured models. Two primary compression standards exist within the glTF ecosystem:
- Draco Compression
(
KHR_draco_mesh_compression): Draco aggressively compresses vertex positions, normals, texture coordinates, and indices. While it achieves high compression ratios (often reducing geometry by 70–90%), it alters vertex order and requires significant CPU overhead to decode. For version control, a Draco-compressed.glbremains an opaque binary file; modifying the mesh creates an entirely different binary stream, offering no delta benefits in Git. - Meshoptimizer
(
EXT_meshopt_compression): Meshopt focuses on optimizing vertex cache efficiency and compressing data into SIMD-friendly formats. Although its compression ratio is slightly lower than Draco's, it maintains the deterministic order of data and decodes orders of magnitude faster. For assets stored directly in Git, Meshopt's predictable structure yields more consistent binary footprints across asset revisions.
Container Decoupling: glTF vs. GLB
The most effective technique for version control is avoiding
monolithic .glb containers during the active production
phase:
- Split the Asset: Save models as plain-text
.gltffiles accompanied by separate external.binbuffers and distinct image files (such as PNG or KTX2). - Targeted Commits: In a decoupled state, editing a
material only alters the JSON-formatted
.gltftext file, which Git diffs with near-zero overhead. Modifying a texture updates only that specific image file, leaving the geometry.binfile untouched. - Automated Build Pipelines: Compile the decoupled
.gltf,.bin, and textures into a single, optimized.glbfile during a downstream continuous integration (CI) release step rather than tracking the compiled.glbin the core source tree.
Texture Optimization and Basis Universal
Textures typically account for 60% to 80% of a .glb
file's total size. Compressing embedded textures drastically reduces
asset weight:
- KTX2 and Basis Universal
(
KHR_texture_basisu): Convert embedded PNG or JPEG textures to KTX2 containers using Basis Universal encoding (ETC1S or UASTC). ETC1S provides massive size reductions for standard albedo textures, while UASTC is ideal for normal maps requiring high fidelity. - Channel Packing: Pack grayscale maps (roughness, metallic, ambient occlusion) into the separate color channels of a single texture to eliminate duplicate image overhead.
Version Control Infrastructure Optimization
Compression applied at the file level must be paired with appropriate VCS configuration:
- Git Large File Storage (Git LFS): Move all
.glb,.bin, and texture files to Git LFS using.gitattributes. This stores files on a remote server while keeping lightweight pointer files in the Git history, preventing the local.gitdirectory from expanding indefinitely with every revision. - Disable Meaningless Deltas: For repositories
storing
.glbfiles without Git LFS, configure.gitattributesto mark the format as binary (*.glb -diff -merge). This prevents the VCS from spending CPU cycles attempting to calculate line-by-line diffs on binary data.