Da Blender alla produzione: un walkthrough di compressione end-to-end
A questo punto della serie, strumenti, principi e selezione sono trattati. In quest'ultimo articolo leghiamo tutto in una pipeline che gira: partendo da un modello reale di Blender, comprimiamo passo dopo passo, registrando dimensione del file, VRAM e tempo di caricamento a ogni passo, e alla fine vediamo se può passare da un peso massimo di 50 MB a un modello di 5 MB che si apre istantaneamente sul mobile.
Lettore target: chi ha letto i cinque precedenti ed è pronto a fare sul serio. Qui niente nuovi concetti — solo flussi, comandi e script copiabili.
Punto di partenza: un modello PBR reale
Come campione usiamo un modello di vetrina e-commerce molto tipico: un modello di prodotto ad alta precisione con map PBR complete.
| Metrica iniziale | Valore |
|---|---|
| File sorgente Blender | ~120 MB (incl. high-poly non esportate) |
| GLB esportato (float32 + PNG) | ~50 MB |
| Numero di vertici | ~180k |
| Map | 6 × 4096×4096 (albedo, normal, roughness, metallic, AO, emissive) |
| Uso VRAM (6 pienamente decompressi) | ~520 MB |
| Obiettivo | File ≤ 5 MB, VRAM controllabile, apertura istantanea su mobile |
Un file da 50 MB e 520 MB di VRAM — questo modello crashea sicuro su mobile. Andiamo passo dopo passo.
Passo 0: esportare correttamente da Blender
La prima porta della compressione è in realtà l'esportazione; molti sanguinano qui.
Impostazioni chiave all'esportazione glTF da Blender:
- Formato:
glTF Binary (.glb)(file singolo, facile da trasferire) - Geometria: spunta
Normals,Tangents(le normal map PBR hanno bisogno di tangenti) - UV: assicurati che vengano esportate (attivo per impostazione predefinita)
- Texture:
AutomaticoJPEG(il formato texture qui non conta, ricomprimeremo dopo — ma che siano esportate) - Compressione: non spuntare la compressione mesh integrata di Blender; useremo strumenti più specializzati
- Trasformazione:
+Y Up(standard glTF) - Dati: spunta solo il necessario (animazione, telecamere, luci se non necessari non esportare, per ridurre le dimensioni)
Dopo l'esportazione, model.glb: 50 MB, 6 map PNG, vertici float32. Questa è la nostra base.
La prima trappola comune è qui: Blender per impostazione predefinita esporta anche mesh inutilizzate e oggetti helper nascosti. Prima dell'esportazione, esegui
File > Clean Up > Purge Orphanse nell'outliner seleziona solo gli oggetti da esportare.
La pipeline end-to-end, quadro completo
Disegniamo l'intera linea per avere una mappa mentale:
File sorgente Blender
│ esporta .glb (float32 + PNG) 50 MB
▼
[1] Dedup + saldatura vertici duplicati (gltf-transform) ~45 MB
│
[2] Compressione vertici: MeshOpt (gltfpack / gltf-transform) ~30 MB
│
[3] Compressione texture: PNG → KTX2 (ETC1S/UASTC) ~6 MB
│
[4] (facoltativo) Semplificazione geometria LOD (simplify) ~4-5 MB
▼
Finale model-final.glb ~5 MB
│
Caricamento motore (Three.js / Babylon.js) → transcodifica runtime → produzione
I numeri di ciascun passo sono seguiti live nelle tabelle sotto.
Toolchain: quale scegliere
Ci sono diversi strumenti di compressione; ecco un confronto per non scegliere male:
| Strumento | Punto di forza | Debolezza | Buono per |
|---|---|---|---|
| gltf-transform | Tuttofare, texture + vertici in un colpo; con API, scriptabile | Rapporto massimo sotto strumenti dedicati | Strumento principale consigliato per la maggior parte degli scenari |
| gltfpack | Pro della compressione vertici, MeshOpt nativo | Compressione texture debole | Denso di vertici, controllo fine di MeshOpt |
| toktx | Strumento di texture più professionale, più parametri | Solo texture, non interi modelli | Messa a punto di una singola texture |
| gltf-pipeline | Veterano, supporta Draco | Manutenzione inattiva, poche funzioni | Progetti legacy con Draco esistenti |
| Strumenti online (gltf.report) | Zero installazione | Non per automazione/massa | Esperimenti, attività una tantum |
Raccomandazione principale: percorri tutto il flusso con gltf-transform; usa gltfpack per il dettaglio dei vertici e toktx per affinare una singola texture all'occorrenza. Tutti i passi sotto sono basati su gltf-transform.
Passo 1: dedup + saldatura
I modelli hanno spesso vertici duplicati, nodi e materiali inutilizzati. Puliamo prima.
gltf-transform optimize model.glb step1.glb --weld --prune
| Fase | Dim. file | VRAM | Cambiamento |
|---|---|---|---|
| Base | 50 MB | ~520 MB | — |
| Step 1 dedup | 45 MB | ~520 MB | -5 MB (VRAM invariato, perché le texture ci sono ancora) |
La VRAM si è mossa appena — come previsto. La dedup risparmia principalmente vertici e struttura; le texture sono il peso massimo della VRAM.
Passo 2: compressioni vertici MeshOpt
gltf-transform optimize step1.glb step2.glb --meshopt --weld --prune
--meshopt quantizza i vertici a 16 bit e applica la codifica senza perdita MeshOpt, aggiungendo automaticamente l'estensione EXT_meshopt_compression.
| Fase | Dim. file | VRAM | Cambiamento |
|---|---|---|---|
| Step 1 | 45 MB | ~520 MB | — |
| Step 2 + MeshOpt | 30 MB | ~520 MB | -15 MB (parte vertici) |
La VRAM ancora ~520 MB? Esatto — perché i vertici sono una piccola parte della VRAM (10-20%); tagliarli ha un impatto VRAM limitato. Il vero mostro della VRAM sono le texture, trattate dopo.
Passo 3: compressioni texture PNG → KTX2
Questo passo è il re del costo-beneficio.
gltf-transform optimize step2.glb step3.glb \
--texture-compress basisu \
--meshopt --weld --prune
--texture-compress basisu rileva automaticamente ogni map: color map (albedo, emissive) → ETC1S; data map (normal, roughness, metallic, AO) → UASTC.
| Fase | Dim. file | VRAM | Cambiamento |
|---|---|---|---|
| Step 2 | 30 MB | ~520 MB | — |
| Step 3 + KTX2 | 6 MB | ~70 MB | -24 MB file / -450 MB VRAM |
Questo passo è il punto di svolta dell'intera pipeline:
- Il file cade da 30 MB a 6 MB
- La VRAM cade da 520 MB a ~70 MB — perché le sei map 4096 passano da «pixel grezzi decompressi» a «compressione a blocchi», ciascuna da ~87 MB a ~11-14 MB
La VRAM scende di un ordine di grandezza — questa è la chiave per sapere se gira su mobile.
Passo 4: (facoltativo) semplificazione geometria
Se vuoi ancora più piccolo e la scena permette di abbassare la precisione dei vertici, aggiungi la semplificazione geometria.
gltf-transform optimize step3.glb final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
--simplify-ratio 0.5 significa conservare circa il 50% dei vertici.
| Fase | Dim. file | VRAM | Cambiamento |
|---|---|---|---|
| Step 3 | 6 MB | ~70 MB | — |
| Step 4 + semplificazione 0.5 | 4.5 MB | ~70 MB | -1.5 MB (VRAM circa invariata) |
La semplificazione risparmia soprattutto la dimensione del file; l'impatto sulla VRAM è piccolo. Il costo è una minore ricchezza di dettaglio del modello — visibile da vicino. Le pagine prodotto e-commerce di solito non dovrebbero semplificare eccessivamente; edifici/grandi scene si adattano molto bene.
Tabella totale di monitoraggio degli effetti
Impiliamo i quattro passi per il quadro complessivo (basato sul campione sopra; i numeri illustrano l'ordine di grandezza):
| Passo | Dim. file | VRAM | Riduzione cumulata |
|---|---|---|---|
| Base (float32 + PNG) | 50 MB | ~520 MB | — |
| + dedup e saldatura | 45 MB | ~520 MB | -10% |
| + vertici MeshOpt | 30 MB | ~520 MB | -40% |
| + texture KTX2 | 6 MB | ~70 MB | -88% file / -87% VRAM |
| + semplif. geometria (0.5) | 4.5 MB | ~70 MB | -91% file |
Conclusione: la compressione delle texture apporta la grandissima maggioranza dei guadagni di dimensione e VRAM. La compressione dei vertici è la ciliegina; quella delle texture è il salvavita. Questo corrisponde pienamente alla tesi del primo articolo — le texture sono l'80% della dimensione, quindi ottimizzarle è il più redditizio.
Versione a un comando: compressione pigra di un colpo
Se non vuoi procedere passo passo, fai tutte le ottimizzazioni in una volta:
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
Questo unico comando = dedup + saldatura + vertici MeshOpt + texture KTX2 + semplificazione geometria. Basta per il 90% degli scenari; il passo-passo serve soprattutto a capire e a sintonizzare.
Script di automazione: riutilizzabile
Incapsula il flusso in uno script da inserire nel build. Questo script produce una versione diversa per piattaforma target e stampa l'effetto di ogni passo.
// scripts/compress-model.mjs
import { optimize } from "@gltf-transform/functions";
import { NodeIO } from "@gltf-transform/core";
import { KHRONOS_EXTENSIONS } from "@gltf-transform/extensions";
import { filesize } from "filesize";
const io = new NodeIO().registerExtensions(KHRONOS_EXTENSIONS);
// Strategie di compressione per piattaforma
const PROFILES = {
mobile: {
textureCompression: "basisu",
meshCompression: "meshopt",
simplify: { ratio: 0.5 },
weld: true,
prune: true,
},
vr: {
textureCompression: "basisu",
meshCompression: "meshopt",
// Visione ravvicinata VR, nessuna semplificazione
simplify: null,
weld: true,
prune: true,
},
desktop: {
textureCompression: "webp",
meshCompression: "meshopt",
simplify: null,
weld: true,
prune: true,
},
};
async function compress(inputPath, profileName) {
const cfg = PROFILES[profileName];
const doc = await io.read(inputPath);
const before = Buffer.byteLength(await io.writeBinary(doc), "utf8");
await optimize(doc, {
textureCompression: cfg.textureCompression,
meshCompression: cfg.meshCompression,
simplify: cfg.simplify ?? undefined,
weld: cfg.weld,
prune: cfg.prune,
});
const bytes = await io.writeBinary(doc);
const outPath = inputPath.replace(/\.glb$/, `-${profileName}.glb`);
await io.write(outPath, doc);
const after = bytes.byteLength;
console.log(
`${profileName.padEnd(8)} ${filesize(before)} → ${filesize(after)} ` +
`(${Math.round((1 - after / before) * 100)}% smaller) → ${outPath}`
);
}
// Uso: node scripts/compress-model.mjs path/to/model.glb
const input = process.argv[2];
for (const profile of Object.keys(PROFILES)) {
await compress(input, profile);
}
Da inserire nel progetto:
node scripts/compress-model.mjs public/models/model.glb
# mobile 50 MB → 4.5 MB (91% più piccolo) → model-mobile.glb
# vr 50 MB → 6.2 MB (87% più piccolo) → model-vr.glb
# desktop 50 MB → 11 MB (78% più piccolo) → model-desktop.glb
Il frontend carica semplicemente la versione corrispondente per dispositivo a runtime.
Non vuoi costruire questa pipeline da solo? Lo strumento online di Any3D fa tutto quanto sopra in un colpo — carica un GLB e automaticamente fa partire texture KTX2 + vertice MeshOpt e produce versioni compresse per piattaforma, risparmiandoti la seccatura di installare una toolchain locale.
FAQ delle trappole comuni
Il modello diventa nero / le texture non si mostrano dopo la compressione
- 99% è lo spazio colore: a una color map manca sRGB. In Three.js
texture.colorSpace = THREE.SRGBColorSpace. - In toktx dimenticato
--srgbsulle color map.
L'illuminazione risulta sbagliata dopo la compressione delle normal map
- La normal map ha usato ETC1S; passa a UASTC.
- La normal map è in stile DirectX (canale verde verso il basso); il motore vuole stile OpenGL, bisogna invertire il canale G.
Il caricamento mobile si blocca al primo paint
- Controlla se stai caricando il wasm del decoder Draco (richiesta extra). Su mobile preferisci MeshOpt.
- Il percorso del transcoder KTX2 mal configurato; il transcode fallisce e ricade sul decode CPU.
Il file compresso è diventato più grande
- La map è troppo piccola (< 128 px); KTX2 non vale — la compressione a blocchi ha un costo fisso.
- Il modello era già compresso una volta; una seconda passata non dà guadagno (persino negativo).
Il modello si rompe dopo la semplificazione
--simplify-ratiotroppo basso; alza a 0.7-0.8.- La semplificazione è amica delle superfici dure (macchinari, architettura) e incline a rompere le curve organiche (personaggi).
KTX2 fallisce il caricamento in alcuni browser
- Safari vecchio / WebView vecchio non supportati. Prepara un fallback PNG/WebP, o usa il campo
fallbackdiKHR_texture_basisucome rete di sicurezza.
Promemoria della serie
L'essenza di tutti i sei articoli condensata in una tabella — metti nei preferiti.
Composizione della dimensione
| Componente | Quota | Strumento di ottimizzazione |
|---|---|---|
| Map di texture | 70-85% | KTX2 (guadagno maggiore) |
| Dati di vertici | 10-20% | MeshOpt / quantizzazione / Draco |
| Dati di animazione | 0-15% | Ridurre keyframe / comprimere |
| Altro | < 2% | Dedup |
Formula della VRAM
VRAM dei formati tradizionali = larghezza * altezza * 4 byte * 1.333 (con mipmap)
VRAM compressa a blocchi KTX2 ≈ quanto sopra / 4 (ETC1S) o / 2 (UASTC)
Selezione della compressione dei vertici
| Scenario | Raccomandazione |
|---|---|
| Zero dipendenze, la più semplice | Quantizzazione pura (KHR_mesh_quantization) |
| Equilibrata, primo favorito web | MeshOpt |
| Rapporto massimo, si può attendere il decode | Draco |
| Mini Program / sensibile al pacchetto | Quant. pura / MeshOpt; evitare Draco |
Selezione della compressione delle texture
| Tipo di map | Codifica consigliata |
|---|---|
| albedo / emissive (colore) | KTX2 ETC1S |
| normal / roughness / metallic / AO (dati) | KTX2 UASTC |
| Web desktop, inseguire velocità di download | WebP / AVIF |
| Map piccole (< 128 px) | Mantenere PNG, non KTX2 |
Comando unico
# Ottimizzazione completa (texture + vertice + semplificazione)
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu --meshopt \
--simplify --simplify-ratio 0.5 --weld --prune
Promemoria piattaforma
| Piattaforma | Texture | Vertice |
|---|---|---|
| Web desktop | WebP / KTX2 | MeshOpt |
| Web mobile | KTX2 obbligatorio | MeshOpt |
| VR | KTX2 obbligatorio | MeshOpt + LOD |
| Mini Program | KTX2 / WebP | MeshOpt / quantizzazione |
| Scena grande | KTX2 obbligatorio | MeshOpt + Draco + LOD |
Retrospettiva della serie
Sei articoli percorsi; messi insieme formano una catena completa:
- Perché così pesante: fissare la composizione della dimensione e la verità della VRAM
- Le tre armi della compressione dei vertici: principi e scelta di quantizzazione, MeshOpt, Draco
- Il problema della VRAM delle texture: perché PNG/JPG sono colpevoli agli occhi della GPU
- KTX2 in pratica: selezione ETC1S/UASTC, toolchain, caricamento nel motore
- Guida alla selezione: un quadro decisionale per piattaforma/scenario
- Questo articolo: pipeline end-to-end, da Blender alla produzione
Il cuore è una frase: pensa prima al collo di bottiglia (download/VRAM/framerate), poi scegli gli strumenti; la compressione delle texture ha il rendimento maggiore, quella dei vertici è la ciliegina; piattaforme diverse, destini diversi — non applicare una regola universale.
Seguendo lo script e il promemoria di questo articolo, portare il tuo modello da 50 MB a 5 MB e la VRAM da 520 MB a 70 MB dovrebbe essere un percorso riproducibile. Il resto è solo mettersi all'opera.