Kris

From Blender to Launch: An End-to-End Compression Pipeline

3D CompressionPipelineTexture CompressionVertex CompressionglTF

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 MetricValue
Blender source file~120MB (includes unexported high-poly)
Exported GLB (float32 + PNG)~50MB
Vertex count~180k
Textures6x 4096×4096 (albedo, normal, roughness, metallic, AO, emissive)
VRAM usage (all textures decompressed)~520MB
TargetFile ≤ 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: Automatic or JPEG (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 Orphans and 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:

ToolStrengthsWeaknessesBest For
gltf-transformAll-in-one, textures + vertices, scriptableNot the absolute best compression ratioRecommended primary tool for most scenarios
gltfpackProfessional vertex compression, native MeshOptWeak texture compressionVertex-heavy models, need fine MeshOpt control
toktxMost professional texture compression, full parametersTextures only, not whole modelsFine-tuning single textures
gltf-pipelineOld-school, supports DracoNot actively maintained, limited featuresExisting Draco projects
Online tools (gltf.report)Zero installationNot suitable for automation, batch jobsExperiments, 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
StageFile SizeVRAMChange
Baseline50MB~520MB
Step 1 Dedup45MB~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.

StageFile SizeVRAMChange
Step 145MB~520MB
Step 2 + MeshOpt30MB~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.

StageFile SizeVRAMChange
Step 230MB~520MB
Step 3 + KTX26MB~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.

StageFile SizeVRAMChange
Step 36MB~70MB
Step 4 + simplify 0.54.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):

StepFile SizeVRAMCumulative Reduction
Baseline (float32 + PNG)50MB~520MB
+ Dedup + Weld45MB~520MB-10%
+ MeshOpt vertices30MB~520MB-40%
+ KTX2 textures6MB~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 --srgb for 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-ratio is 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 fallback field of KHR_texture_basisu to provide backup textures.

Series Cheat Sheet

The essence of all 6 posts condensed into a single table. Bookmark this.

Volume Breakdown

ComponentPercentageOptimization Tool
Textures70-85%KTX2 (biggest gain)
Vertex data10-20%MeshOpt / Quantization / Draco
Animation data0-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

ScenarioRecommended
Zero dependencies, simplestPure quantization (KHR_mesh_quantization)
Web balanced first choiceMeshOpt
Extreme compression ratio, can wait for decodeDraco
Mini programs / package-sensitivePure quantization / MeshOpt, avoid Draco

Texture Compression Selection

Texture TypeRecommended Codec
albedo / emissive (color)KTX2 ETC1S
normal / roughness / metallic / AO (data)KTX2 UASTC
Desktop web, prioritize download speedWebP / 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

PlatformTexturesVertices
Desktop WebWebP / KTX2MeshOpt
Mobile WebKTX2 mandatoryMeshOpt
VRKTX2 mandatoryMeshOpt + LOD
Mini programsKTX2 / WebPMeshOpt / Quantization
Large scenesKTX2 mandatoryMeshOpt + Draco + LOD

Series Recap

Six posts take you through a complete chain:

  1. Why So Heavy : Understand volume composition and VRAM reality
  2. **[Vertex Compression
Support Us