De Blender à la production : un walkthrough de compression de bout en bout
À ce point de la série, outils, principes et sélection sont couverts. Dans ce dernier article, nous relions tout en un pipeline qui tourne : à partir d'un vrai modèle Blender, compressons pas à pas, en enregistrant à chaque étape taille de fichier, VRAM et temps de chargement, et voyons enfin s'il peut passer d'un poids lourd de 50 Mo à un modèle de 5 Mo qui s'ouvre instantanément sur mobile.
Lecteur cible : quelqu'un qui a lu les cinq précédents et est prêt à passer à l'acte. Pas de nouveaux concepts ici — seulement des flux, commandes et scripts copiables.
Point de départ : un vrai modèle PBR
Comme échantillon, un modèle d'exposition e-commerce très typique : un modèle de produit haute précion avec des maps PBR complets.
| Métrique initiale | Valeur |
|---|---|
| Fichier source Blender | ~120 Mo (incl. high-poly non exporté) |
| GLB exporté (float32 + PNG) | ~50 Mo |
| Nombre de sommets | ~180k |
| Maps | 6 × 4096×4096 (albedo, normal, roughness, metallic, AO, emissive) |
| Utilisation VRAM (6 entièrement décompressées) | ~520 Mo |
| Objectif | Fichier ≤ 5 Mo, VRAM contrôlable, ouverture instantanée sur mobile |
Un fichier de 50 Mo et 520 Mo de VRAM — ce modèle crashe à coup sûr sur mobile. Allons pas à pas.
Étape 0 : exporter correctement depuis Blender
La première porte de la compression est en fait l'export ; beaucoup saignent ici.
Réglages clés à l'export glTF depuis Blender :
- Format :
glTF Binary (.glb)(fichier unique, facile à transférer) - Géométrie : cocher
Normals,Tangents(les normal maps PBR ont besoin de tangentes) - UV : s'assurer de l'export (activé par défaut)
- Textures :
AutomaticouJPEG(le format de texture ici n'importe pas ; nous recomprimerons plus tard — mais il faut qu'elles soient exportées) - Compression : ne pas cocher la compression de maillage intégrée à Blender ; nous utiliserons des outils plus spécialisés
- Transformation :
+Y Up(standard glTF) - Données : ne cocher que le nécessaire (animation, caméras, lumières inutiles ne pas exporter, pour réduire la taille)
Après l'export, model.glb : 50 Mo, 6 maps PNG, sommets float32. C'est notre base.
Le premier piège courant est ici : Blender exporte par défaut aussi les meshes inutilisés et les objets auxiliaires cachés. Avant l'export, lancez
File > Clean Up > Purge Orphanset dans l'outliner ne sélectionnez que les objets à exporter.
Le pipeline de bout en bout, vue d'ensemble
Dessinons toute la ligne pour avoir une carte mentale :
Fichier source Blender
│ exporter .glb (float32 + PNG) 50 Mo
▼
[1] Déduplication + soudure des sommets dupliqués (gltf-transform) ~45 Mo
│
[2] Compression des sommets : MeshOpt (gltfpack / gltf-transform) ~30 Mo
│
[3] Compression des textures : PNG → KTX2 (ETC1S/UASTC) ~6 Mo
│
[4] (facultatif) Simplification de géométrie LOD (simplify) ~4-5 Mo
▼
Final model-final.glb ~5 Mo
│
Chargement moteur (Three.js / Babylon.js) → transcodage runtime → production
Les chiffres de chaque étape sont suivis en direct dans les tableaux ci-dessous.
Toolchain : laquelle choisir
Il y a plusieurs outils de compression ; voici une comparaison pour ne pas se tromper :
| Outil | Force | Faiblesse | Bon pour |
|---|---|---|---|
| gltf-transform | Polyvalent, textures + sommets d'un coup ; API-able, scriptable | Ratio max inférieur aux outils dédiés | Outil principal recommandé pour la plupart des scénarios |
| gltfpack | Pro de la compression des sommets, MeshOpt natif | Compression des textures faible | Dense en sommets, contrôle fin de MeshOpt |
| toktx | Outil de textures le plus professionnel, le plus de paramètres | Seulement les textures, pas les modèles entiers | Réglage fin d'une texture unique |
| gltf-pipeline | Vétéran, prend en charge Draco | Maintenance inactive, peu de fonctions | Projets legacy Draco existants |
| Outils en ligne (gltf.report) | Zéro installation | Pas pour l'automatisation/masse | Expériences, tâches uniques |
Recommandation principale : parcourez tout le flux avec gltf-transform ; utilisez gltfpack pour le détail des sommets et toktx pour affiner une texture unique au besoin. Toutes les étapes ci-dessous sont basées sur gltf-transform.
Étape 1 : déduplication + soudure
Les modèles ont souvent des sommets dupliqués, des nœuds et matériaux inutilisés. Nettoyons d'abord.
gltf-transform optimize model.glb step1.glb --weld --prune
| Étape | Taille fichier | VRAM | Changement |
|---|---|---|---|
| Base | 50 Mo | ~520 Mo | — |
| Step 1 déduplication | 45 Mo | ~520 Mo | -5 Mo (VRAM inchangé, car les textures sont toujours là) |
Le VRAM a à peine bougé — c'est attendu. La déduplication économise surtout sommets et structure ; les textures sont le poids lourd du VRAM.
Étape 2 : compression des sommets MeshOpt
gltf-transform optimize step1.glb step2.glb --meshopt --weld --prune
--meshopt quantifie les sommets sur 16 bits et applique un codage sans perte MeshOpt, ajoutant automatiquement l'extension EXT_meshopt_compression.
| Étape | Taille fichier | VRAM | Changement |
|---|---|---|---|
| Step 1 | 45 Mo | ~520 Mo | — |
| Step 2 + MeshOpt | 30 Mo | ~520 Mo | -15 Mo (partie sommets) |
Le VRAM toujours ~520 Mo ? Exact — parce que les sommets sont une petite part du VRAM (10-20 %) ; les couper a un impact VRAM limité. Le vrai monstre VRAM est les textures, traité ensuite.
Étape 3 : compression des textures PNG → KTX2
Cette étape est le roi du rapport coût-bénéfice.
gltf-transform optimize step2.glb step3.glb \
--texture-compress basisu \
--meshopt --weld --prune
--texture-compress basisu détecte chaque map automatiquement : color maps (albedo, emissive) → ETC1S ; data maps (normal, roughness, metallic, AO) → UASTC.
| Étape | Taille fichier | VRAM | Changement |
|---|---|---|---|
| Step 2 | 30 Mo | ~520 Mo | — |
| Step 3 + KTX2 | 6 Mo | ~70 Mo | -24 Mo fichier / -450 Mo VRAM |
Cette étape est le tournant de tout le pipeline :
- Le fichier tombe de 30 Mo à 6 Mo
- Le VRAM tombe de 520 Mo à ~70 Mo — parce que les six maps 4096 passent de « pixels bruts décompressés » à « compression par bloc », chacune de ~87 Mo à ~11-14 Mo
Le VRAM chute d'un ordre de grandeur — c'est la clé de savoir si ça tourne sur mobile.
Étape 4 : (facultatif) simplification de géométrie
Si vous voulez encore plus petit et que la scène permet de baisser la précision des sommets, ajoutez la simplification de géométrie.
gltf-transform optimize step3.glb final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
--simplify-ratio 0.5 signifie conserver environ 50 % des sommets.
| Étape | Taille fichier | VRAM | Changement |
|---|---|---|---|
| Step 3 | 6 Mo | ~70 Mo | — |
| Step 4 + simplification 0.5 | 4.5 Mo | ~70 Mo | -1.5 Mo (VRAM à peu près inchangé) |
La simplification économise surtout la taille du fichier ; l'impact VRAM est faible. Le coût est une réduction du détail du modèle — visible de près. Les pages produit e-commerce ne devraient généralement pas trop simplifier ; bâtiments/grandes scènes conviennent très bien.
Tableau total de suivi des effets
Empilons les quatre étapes pour la vue d'ensemble (basé sur l'échantillon ci-dessus ; les chiffres illustrent l'ordre de grandeur) :
| Étape | Taille fichier | VRAM | Réduction cumulée |
|---|---|---|---|
| Base (float32 + PNG) | 50 Mo | ~520 Mo | — |
| + déduplication et soudure | 45 Mo | ~520 Mo | -10 % |
| + sommets MeshOpt | 30 Mo | ~520 Mo | -40 % |
| + textures KTX2 | 6 Mo | ~70 Mo | -88 % fichier / -87 % VRAM |
| + simplif. géométrie (0.5) | 4.5 Mo | ~70 Mo | -91 % fichier |
Conclusion : la compression des textures apporte la très grande majorité des gains de taille et de VRAM. La compression des sommets est la cerise ; la compression des textures est la planche de salut. Cela correspond totalement à la thèse du premier article — les textures sont 80 % de la taille, donc les optimiser est le plus rentable.
Version une commande : compression fainéante d'un coup
Si vous ne voulez pas procéder par étapes, faites toutes les optimisations d'un coup :
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--weld --prune
Cette commande unique = déduplication + soudure + sommets MeshOpt + textures KTX2 + simplification de géométrie. Elle suffit pour 90 % des scénarios ; le pas à pas sert surtout à comprendre et régler.
Script d'automatisation : réutilisable
Encapsulez le flux dans un script à intégrer au build. Ce script produit une version différente par plateforme cible et imprime l'effet de chaque étape.
// 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);
// Stratégies de compression par plateforme
const PROFILES = {
mobile: {
textureCompression: "basisu",
meshCompression: "meshopt",
simplify: { ratio: 0.5 },
weld: true,
prune: true,
},
vr: {
textureCompression: "basisu",
meshCompression: "meshopt",
// Vision rapprochée VR, pas de simplification
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}`
);
}
// Usage : 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);
}
À intégrer au projet :
node scripts/compress-model.mjs public/models/model.glb
# mobile 50 Mo → 4.5 Mo (91 % plus petit) → model-mobile.glb
# vr 50 Mo → 6.2 Mo (87 % plus petit) → model-vr.glb
# desktop 50 Mo → 11 Mo (78 % plus petit) → model-desktop.glb
Le frontend charge simplement la version correspondante par appareil à l'exécution.
Vous ne voulez pas monter ce pipeline vous-même ? L'outil en ligne d'Any3D réalise tout ce qui précède d'un coup — téléversez un GLB, il lance automatiquement texture KTX2 + sommet MeshOpt et produit des versions compressées par plateforme, vous évitant d'installer une toolchain locale.
FAQ des pièges courants
Le modèle devient noir / les textures ne s'affichent pas après compression
- 99 % c'est l'espace colorimétrique : un color map a oublié sRGB. Dans Three.js
texture.colorSpace = THREE.SRGBColorSpace. - En toktx oubli de
--srgbsur les color maps.
L'éclairage est mauvais après compression des normal maps
- Le normal map a utilisé ETC1S ; passez à UASTC.
- Le normal map est de style DirectX (canal vert vers le bas) ; le moteur veut du style OpenGL, il faut inverser le canal G.
Le chargement mobile reste bloqué au premier rendu
- Vérifier si vous chargez le wasm du décodeur Draco (requête supplémentaire). Sur mobile préférez MeshOpt.
- Le chemin du transcodeur KTX2 mal configuré ; le transcodage échoue et retombe sur le décodage CPU.
Le fichier compressé est devenu plus grand
- Le map est trop petit (< 128 px) ; KTX2 ne vaut pas le coup — la compression par bloc a un coût fixe.
- Le modèle a déjà été compressé une fois ; une seconde passe n'apporte rien (voire négatif).
Le modèle se casse après simplification
--simplify-ratiotrop bas ; monter à 0.7-0.8.- La simplification est amie avec les surfaces dures (machines, architecture) et casse les courbes organiques (personnages).
KTX2 échoue à charger dans certains navigateurs
- Ancien Safari / ancien WebView non pris en charge. Préparez un fallback PNG/WebP, ou utilisez le champ
fallbackdeKHR_texture_basisucomme filet.
Fiche mémo de la série
L'essence des six articles condensée en un tableau — à bookmarker.
Composition de la taille
| Composant | Part | Outil d'optimisation |
|---|---|---|
| Maps de texture | 70-85 % | KTX2 (gain le plus grand) |
| Données de sommets | 10-20 % | MeshOpt / quantification / Draco |
| Données d'animation | 0-15 % | Réduire les keyframes / compresser |
| Autres | < 2 % | Déduplication |
Formule du VRAM
VRAM des formats traditionnels = largeur * hauteur * 4 octets * 1.333 (avec mipmaps)
VRAM compressé par bloc KTX2 ≈ ci-dessus / 4 (ETC1S) ou / 2 (UASTC)
Sélection de compression des sommets
| Scénario | Recommandation |
|---|---|
| Zéro dépendance, le plus simple | Quantification pure (KHR_mesh_quantization) |
| Équilibré, premier choix web | MeshOpt |
| Ratio max, peut attendre le décodage | Draco |
| Mini Program / sensible au paquet | Quant. pure / MeshOpt ; éviter Draco |
Sélection de compression des textures
| Type de map | Encodage recommandé |
|---|---|
| albedo / emissive (couleur) | KTX2 ETC1S |
| normal / roughness / metallic / AO (données) | KTX2 UASTC |
| Web bureau, vitesse de téléchargement | WebP / AVIF |
| Petits maps (< 128 px) | Garder PNG, pas de KTX2 |
Commande unique
# Optimisation complète (texture + sommet + simplification)
gltf-transform optimize model.glb model-final.glb \
--texture-compress basisu --meshopt \
--simplify --simplify-ratio 0.5 --weld --prune
Fiche plateforme
| Plateforme | Texture | Sommet |
|---|---|---|
| Web bureau | WebP / KTX2 | MeshOpt |
| Web mobile | KTX2 obligatoire | MeshOpt |
| VR | KTX2 obligatoire | MeshOpt + LOD |
| Mini Program | KTX2 / WebP | MeshOpt / quantification |
| Grande scène | KTX2 obligatoire | MeshOpt + Draco + LOD |
Rétrospective de la série
Six articles parcourus ; assemblés, ils forment une chaîne complète :
- Pourquoi si lourd : fixer la composition de la taille et la vérité du VRAM
- Les trois armes de la compression des sommets : principes et choix de quantification, MeshOpt, Draco
- Le problème VRAM des textures : pourquoi PNG/JPG sont coupables aux yeux du GPU
- KTX2 en pratique : sélection ETC1S/UASTC, toolchain, chargement moteur
- Guide de sélection : un cadre de décision par plateforme/scénario
- Cet article : pipeline de bout en bout, de Blender à la production
Le cœur tient en une phrase : réfléchissez d'abord au goulot (téléchargement/VRAM/framerate), puis choisissez les outils ; la compression des textures a le meilleur rendement, celle des sommets est la cerise ; plateformes différentes, destins différents — pas de règle universelle.
En suivant le script et la fiche mémo de cet article, emmener votre modèle de 50 Mo à 5 Mo et le VRAM de 520 Mo à 70 Mo devrait être un chemin reproductible. Le reste, c'est juste passer à l'acte.