Any3DAny3D
·Any3D Team

De Blender à la production : un walkthrough de compression de bout en bout

3d-compressionpipelinetexture-compressionvertex-compressiongltf

À 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 initialeValeur
Fichier source Blender~120 Mo (incl. high-poly non exporté)
GLB exporté (float32 + PNG)~50 Mo
Nombre de sommets~180k
Maps6 × 4096×4096 (albedo, normal, roughness, metallic, AO, emissive)
Utilisation VRAM (6 entièrement décompressées)~520 Mo
ObjectifFichier ≤ 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 : Automatic ou JPEG (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 Orphans et 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 :

OutilForceFaiblesseBon pour
gltf-transformPolyvalent, textures + sommets d'un coup ; API-able, scriptableRatio max inférieur aux outils dédiésOutil principal recommandé pour la plupart des scénarios
gltfpackPro de la compression des sommets, MeshOpt natifCompression des textures faibleDense en sommets, contrôle fin de MeshOpt
toktxOutil de textures le plus professionnel, le plus de paramètresSeulement les textures, pas les modèles entiersRéglage fin d'une texture unique
gltf-pipelineVétéran, prend en charge DracoMaintenance inactive, peu de fonctionsProjets legacy Draco existants
Outils en ligne (gltf.report)Zéro installationPas pour l'automatisation/masseExpé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
ÉtapeTaille fichierVRAMChangement
Base50 Mo~520 Mo
Step 1 déduplication45 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.

ÉtapeTaille fichierVRAMChangement
Step 145 Mo~520 Mo
Step 2 + MeshOpt30 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.

ÉtapeTaille fichierVRAMChangement
Step 230 Mo~520 Mo
Step 3 + KTX26 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.

ÉtapeTaille fichierVRAMChangement
Step 36 Mo~70 Mo
Step 4 + simplification 0.54.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) :

ÉtapeTaille fichierVRAMRéduction cumulée
Base (float32 + PNG)50 Mo~520 Mo
+ déduplication et soudure45 Mo~520 Mo-10 %
+ sommets MeshOpt30 Mo~520 Mo-40 %
+ textures KTX26 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 --srgb sur 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-ratio trop 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 fallback de KHR_texture_basisu comme filet.

Fiche mémo de la série

L'essence des six articles condensée en un tableau — à bookmarker.

Composition de la taille

ComposantPartOutil d'optimisation
Maps de texture70-85 %KTX2 (gain le plus grand)
Données de sommets10-20 %MeshOpt / quantification / Draco
Données d'animation0-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énarioRecommandation
Zéro dépendance, le plus simpleQuantification pure (KHR_mesh_quantization)
Équilibré, premier choix webMeshOpt
Ratio max, peut attendre le décodageDraco
Mini Program / sensible au paquetQuant. pure / MeshOpt ; éviter Draco

Sélection de compression des textures

Type de mapEncodage recommandé
albedo / emissive (couleur)KTX2 ETC1S
normal / roughness / metallic / AO (données)KTX2 UASTC
Web bureau, vitesse de téléchargementWebP / 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

PlateformeTextureSommet
Web bureauWebP / KTX2MeshOpt
Web mobileKTX2 obligatoireMeshOpt
VRKTX2 obligatoireMeshOpt + LOD
Mini ProgramKTX2 / WebPMeshOpt / quantification
Grande scèneKTX2 obligatoireMeshOpt + Draco + LOD

Rétrospective de la série

Six articles parcourus ; assemblés, ils forment une chaîne complète :

  1. Pourquoi si lourd : fixer la composition de la taille et la vérité du VRAM
  2. Les trois armes de la compression des sommets : principes et choix de quantification, MeshOpt, Draco
  3. Le problème VRAM des textures : pourquoi PNG/JPG sont coupables aux yeux du GPU
  4. KTX2 en pratique : sélection ETC1S/UASTC, toolchain, chargement moteur
  5. Guide de sélection : un cadre de décision par plateforme/scénario
  6. 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.

Nous soutenir