Any3DAny3D
·Any3D Team

Da Blender alla produzione: un walkthrough di compressione end-to-end

3d-compressionpipelinetexture-compressionvertex-compressiongltf

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 inizialeValore
File sorgente Blender~120 MB (incl. high-poly non esportate)
GLB esportato (float32 + PNG)~50 MB
Numero di vertici~180k
Map6 × 4096×4096 (albedo, normal, roughness, metallic, AO, emissive)
Uso VRAM (6 pienamente decompressi)~520 MB
ObiettivoFile ≤ 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: Automatic o JPEG (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 Orphans e 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:

StrumentoPunto di forzaDebolezzaBuono per
gltf-transformTuttofare, texture + vertici in un colpo; con API, scriptabileRapporto massimo sotto strumenti dedicatiStrumento principale consigliato per la maggior parte degli scenari
gltfpackPro della compressione vertici, MeshOpt nativoCompressione texture deboleDenso di vertici, controllo fine di MeshOpt
toktxStrumento di texture più professionale, più parametriSolo texture, non interi modelliMessa a punto di una singola texture
gltf-pipelineVeterano, supporta DracoManutenzione inattiva, poche funzioniProgetti legacy con Draco esistenti
Strumenti online (gltf.report)Zero installazioneNon per automazione/massaEsperimenti, 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
FaseDim. fileVRAMCambiamento
Base50 MB~520 MB
Step 1 dedup45 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.

FaseDim. fileVRAMCambiamento
Step 145 MB~520 MB
Step 2 + MeshOpt30 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.

FaseDim. fileVRAMCambiamento
Step 230 MB~520 MB
Step 3 + KTX26 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.

FaseDim. fileVRAMCambiamento
Step 36 MB~70 MB
Step 4 + semplificazione 0.54.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):

PassoDim. fileVRAMRiduzione cumulata
Base (float32 + PNG)50 MB~520 MB
+ dedup e saldatura45 MB~520 MB-10%
+ vertici MeshOpt30 MB~520 MB-40%
+ texture KTX26 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 --srgb sulle 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-ratio troppo 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 fallback di KHR_texture_basisu come rete di sicurezza.

Promemoria della serie

L'essenza di tutti i sei articoli condensata in una tabella — metti nei preferiti.

Composizione della dimensione

ComponenteQuotaStrumento di ottimizzazione
Map di texture70-85%KTX2 (guadagno maggiore)
Dati di vertici10-20%MeshOpt / quantizzazione / Draco
Dati di animazione0-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

ScenarioRaccomandazione
Zero dipendenze, la più sempliceQuantizzazione pura (KHR_mesh_quantization)
Equilibrata, primo favorito webMeshOpt
Rapporto massimo, si può attendere il decodeDraco
Mini Program / sensibile al pacchettoQuant. pura / MeshOpt; evitare Draco

Selezione della compressione delle texture

Tipo di mapCodifica consigliata
albedo / emissive (colore)KTX2 ETC1S
normal / roughness / metallic / AO (dati)KTX2 UASTC
Web desktop, inseguire velocità di downloadWebP / 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

PiattaformaTextureVertice
Web desktopWebP / KTX2MeshOpt
Web mobileKTX2 obbligatorioMeshOpt
VRKTX2 obbligatorioMeshOpt + LOD
Mini ProgramKTX2 / WebPMeshOpt / quantizzazione
Scena grandeKTX2 obbligatorioMeshOpt + Draco + LOD

Retrospettiva della serie

Sei articoli percorsi; messi insieme formano una catena completa:

  1. Perché così pesante: fissare la composizione della dimensione e la verità della VRAM
  2. Le tre armi della compressione dei vertici: principi e scelta di quantizzazione, MeshOpt, Draco
  3. Il problema della VRAM delle texture: perché PNG/JPG sono colpevoli agli occhi della GPU
  4. KTX2 in pratica: selezione ETC1S/UASTC, toolchain, caricamento nel motore
  5. Guida alla selezione: un quadro decisionale per piattaforma/scenario
  6. 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.

Supportaci