From Blender to Launch: An End-to-End Compression Pipeline
By now we've covered the tools, theory, and decision-making. In this final post, we'll stitch everything together into a real, runnable pipeline: starting from a real Blender model, compressing step by step, tracking file size, VRAM, and load time, and seeing if we can turn a 50MB beast into a 5MB model that loads instantly on a phone.
Target audience: those who've read the first 5 posts and are ready to do it for real. No new concepts here—just a repeatable process, commands, and scripts.
Starting Point: A Real PBR Model
Let's use a typical e-commerce product showcase model: a high-precision product with full PBR textures.
| Initial Metric | Value |
|---|---|
| Blender source file | ~120MB (includes unexported high-poly) |
| Exported GLB (float32 + PNG) | ~50MB |
| Vertex count | ~180k |
| Textures | 6x 4096×4096 (albedo, normal, roughness, metallic, AO, emissive) |
| VRAM usage (all textures decompressed) | ~520MB |
| Target | File ≤ 5MB, VRAM manageable, instant mobile load |
A 50MB file with 520MB of VRAM—this model would crash any mobile device. Let's go step by step.
Step 0: Exporting Correctly from Blender
The first compression checkpoint is actually the export itself. Many people lose blood here.
Key settings when exporting glTF from Blender:
- Format:
glTF Binary (.glb)(single file, easier to transfer) - Geometry: Check
Normals,Tangents(PBR normal maps need tangents) - UV: Ensure they're exported (on by default)
- Textures:
AutomaticorJPEG(texture format doesn't matter now—we'll recompress later, but make sure they're exported) - Compression: Do not check Blender's built-in Mesh compression; we'll use more professional tools
- Transform:
+Y Up(glTF standard) - Data: Only export what you need (animations, cameras, lights—if not needed, don't export them and reduce size)
After export, model.glb: 50MB, 6 PNG textures, float32 vertices. This is our baseline.
Common pitfall: Blender exports unused meshes, hidden helper objects, etc. by default. Before exporting, run
File > Clean Up > Purge Orphansand select only the objects you want to export in the outliner.
End-to-End Pipeline Overview
Let's visualize the whole pipeline:
Blender source file
│ Export .glb (float32 + PNG) 50MB
▼
[1] Deduplication + Weld duplicate vertices (gltf-transform) ~45MB
│
[2] Vertex compression: MeshOpt (gltfpack / gltf-transform) ~30MB
│
[3] Texture compression: PNG → KTX2 (ETC1S/UASTC) ~6MB
│
[4] (Optional) Geometry simplification LOD (simplify) ~4-5MB
▼
Final model-final.glb ~5MB
│
Engine loading (Three.js / Babylon.js) → runtime transcoding → Deploy
The numbers for each step will be tracked in the table below.
Toolchain: Which One to Choose
Several compression tools are available. Let's compare them so you don't pick the wrong one:
| Tool | Strengths | Weaknesses | Best For |
|---|---|---|---|
| gltf-transform | All-in-one, textures + vertices, scriptable | Not the absolute best compression ratio | Recommended primary tool for most scenarios |
| gltfpack | Professional vertex compression, native MeshOpt | Weak texture compression | Vertex-heavy models, need fine MeshOpt control |
| toktx | Most professional texture compression, full parameters | Textures only, not whole models | Fine-tuning single textures |
| gltf-pipeline | Old-school, supports Draco | Not actively maintained, limited features | Existing Draco projects |
| Online tools (gltf.report) | Zero installation | Not suitable for automation, batch jobs | Experiments, one-off tasks |
Main recommendation: Use gltf-transform for the entire pipeline. Supplement with gltfpack for vertices and toktx for individual textures when needed. All steps below use gltf-transform.
Step 1: Deduplication + Weld
Models often have duplicate vertices, unused nodes, and materials. Clean them up first.
gltf-transform optimize model.glb step1.glb --weld --prune
| Stage | File Size | VRAM | Change |
|---|---|---|---|
| Baseline | 50MB | ~520MB | — |
| Step 1 Dedup | 45MB | ~520MB | -5MB (VRAM unchanged, textures still there) |
VRAM barely moved—expected. Deduplication mainly saves vertices and structure; textures are the VRAM hog.
Step 2: Vertex Compression with MeshOpt
gltf-transform optimize step1.glb step2.glb --meshopt --weld --prune
--meshopt quantizes vertices to 16-bit and uses MeshOpt lossless encoding, automatically adding the EXT_meshopt_compression extension.
| Stage | File Size | VRAM | Change |
|---|---|---|---|
| Step 1 | 45MB | ~520MB | — |
| Step 2 + MeshOpt | 30MB | ~520MB | -15MB (vertex part) |
VRAM still ~520MB? Yes—because vertices take up a small portion of VRAM (10-20%). Cutting vertices has limited impact on VRAM. The real VRAM monster is textures, which we tackle next.
Step 3: Texture Compression PNG → KTX2
This step is the biggest bang for your buck.
gltf-transform optimize step2.glb step3.glb \
--texture-compress basisu \
--meshopt --weld --prune
--texture-compress basisu automatically determines each texture: color textures (albedo, emissive) use ETC1S, data textures (normal, roughness, metallic, AO) use UASTC.
| Stage | File Size | VRAM | Change |
|---|---|---|---|
| Step 2 | 30MB | ~520MB | — |
| Step 3 + KTX2 | 6MB | ~70MB | -24MB file / -450MB VRAM |
This step is the turning point of the entire pipeline:
- File size drops from 30MB to 6MB
- VRAM drops from 520MB to ~70MB—because the 6 4096 textures go from "decompressed raw pixels" to "block compressed", each dropping from ~87MB to ~11-14MB
VRAM is reduced by an order of magnitude. This is the key to whether a mobile device can handle it.
Step 4: (Optional) Geometry Simplification
If you want even smaller, and the scene can tolerate lower vertex precision, add geometry simplification.
gltf-transform optimize step3.glb final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
--simplify-ratio 0.5 means keep about 50% of the vertices.
| Stage | File Size | VRAM | Change |
|---|---|---|---|
| Step 3 | 6MB | ~70MB | — |
| Step 4 + simplify 0.5 | 4.5MB | ~70MB | -1.5MB (VRAM nearly unchanged) |
Simplification mainly saves file size, with little impact on VRAM. The trade-off is reduced model detail—noticeable at close range. For e-commerce product pages, over-simplification is usually not recommended; it's great for architecture/large scenes.
Full Progress Tracking Table
Let's stack all four steps for a complete picture (based on the sample model, numbers are illustrative):
| Step | File Size | VRAM | Cumulative Reduction |
|---|---|---|---|
| Baseline (float32 + PNG) | 50MB | ~520MB | — |
| + Dedup + Weld | 45MB | ~520MB | -10% |
| + MeshOpt vertices | 30MB | ~520MB | -40% |
| + KTX2 textures | 6MB | ~70MB | -88% file / -87% VRAM |
| + Geometry simplify (0.5) | 4.5MB | ~70MB | -91% file |
Conclusion: Texture compression provides the vast majority of file size and VRAM savings. Vertex compression is the icing on the cake; texture compression is the lifesaver. This perfectly matches the conclusion from Part 1—textures make up 80% of the volume, so optimizing them yields the highest return.
One-Command Version: Lazy All-in-One
If you don't want to do it step by step, apply all optimizations at once:
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
This single command = dedup + weld + MeshOpt vertices + KTX2 textures + geometry simplification. It covers 90% of scenarios. The step-by-step approach is mainly for understanding and tuning parameters.
Don't Want to Set Up an Environment? Use Any3D Online Compression
The above gltf-transform commands and scripts require installing Node, configuring the toolchain, and remembering a bunch of parameters. Any3D's online compression tool eliminates all that:
- No need to download scripts or set up an environment—just open a web page and use it
- Model never leaves your device—everything is processed locally in the browser
- Visual configuration—texture KTX2, vertex MeshOpt, geometry simplification—sliders for parameters, real-time preview
- One-click multi-platform—export compressed results for mobile / desktop / VR
Pick a GLB, choose a target platform, click, and get the compressed model. Under the hood it's the same engine as the command line (gltf-transform), but with zero learning curve—no terminal required.
Common Pitfalls FAQ
Model turns black / textures don't show after compression
- 99% of the time it's color space: color textures missing sRGB. In Three.js:
texture.colorSpace = THREE.SRGBColorSpace. - When using toktx, forgot
--srgbfor color textures.
Normal map lighting is wrong after compression
- Normal map was encoded with ETC1S; switch to UASTC.
- Normal map is in DirectX style (green channel pointing down), but the engine expects OpenGL style; need to flip the G channel.
Mobile loading hangs on the first screen
- Check if you're loading the Draco decoder wasm (extra request). Prefer MeshOpt for mobile.
- KTX2 transcoder path is misconfigured, causing fallback to CPU decompression.
Compressed file is larger than the original
- Texture is too small (< 128px). KTX2 isn't cost-effective for small textures due to block compression overhead.
- Model was already compressed; recompressing offers no benefit (or negative benefit).
Model breaks after simplification
--simplify-ratiois too low; try 0.7-0.8.- Simplification works well for hard surfaces (mechanical, architectural) but can break organic surfaces (characters).
KTX2 fails to load in some browsers
- Old Safari / old WebView don't support it. Prepare a PNG/WebP fallback, or use the
fallbackfield ofKHR_texture_basisuto provide backup textures.
Series Cheat Sheet
The essence of all 6 posts condensed into a single table. Bookmark this.
Volume Breakdown
| Component | Percentage | Optimization Tool |
|---|---|---|
| Textures | 70-85% | KTX2 (biggest gain) |
| Vertex data | 10-20% | MeshOpt / Quantization / Draco |
| Animation data | 0-15% | Reduce keyframes / compress |
| Other | < 2% | Deduplication |
VRAM Formula
Traditional format VRAM = width * height * 4 bytes * 1.333 (with mipmaps)
KTX2 block compressed VRAM ≈ above / 4 (ETC1S) or / 2 (UASTC)
Vertex Compression Selection
| Scenario | Recommended |
|---|---|
| Zero dependencies, simplest | Pure quantization (KHR_mesh_quantization) |
| Web balanced first choice | MeshOpt |
| Extreme compression ratio, can wait for decode | Draco |
| Mini programs / package-sensitive | Pure quantization / MeshOpt, avoid Draco |
Texture Compression Selection
| Texture Type | Recommended Codec |
|---|---|
| albedo / emissive (color) | KTX2 ETC1S |
| normal / roughness / metallic / AO (data) | KTX2 UASTC |
| Desktop web, prioritize download speed | WebP / AVIF |
| Small textures (< 128px) | Keep PNG, don't compress to KTX2 |
One-Click Command
# Full optimization (textures + vertices + simplification)
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu --meshopt \
--simplify --simplify-ratio 0.5 --weld --prune
Platform Quick Reference
| Platform | Textures | Vertices |
|---|---|---|
| Desktop Web | WebP / KTX2 | MeshOpt |
| Mobile Web | KTX2 mandatory | MeshOpt |
| VR | KTX2 mandatory | MeshOpt + LOD |
| Mini programs | KTX2 / WebP | MeshOpt / Quantization |
| Large scenes | KTX2 mandatory | MeshOpt + Draco + LOD |
Series Recap
Six posts take you through a complete chain:
- Why So Heavy : Understand volume composition and VRAM reality
- **[Vertex Compression