Any3DAny3D
·Any3D Team

Première leçon pour mettre votre modèle au régime : les trois armes de la compression de sommets

3d-compressionvertex-compressionmeshoptdracogltf

Dans l'article précédent, nous avons ouvert un fichier GLB et constaté que les textures engloutissent 80 % de la taille, tandis que les sommets n'en représentent que 10-20 %. La compression des sommets semble donc anodine ?

Bien au contraire. Quand les textures d'un modèle ont déjà été compressées en KTX2 et que les sommets sont très denses, les 20 % restants, ce sont les sommets — et ces 20 % peuvent encore être réduits de moitié, voire de 90 %. Plus important encore, la compression des sommets fait partie des rares optimisations quasi gratuites et immédiates : quelques lignes de commande, un changement de décodeur, et le fichier aminci.

Cet article clarifie trois choses : à quoi ressemblent réellement les données de sommets ; le tempérament propre à chacune des trois approches (quantification, MeshOpt, Draco) ; et une conclusion qui vous évitera bien des pièges — il n'y a pas de solution « la meilleure », seulement la solution « la plus adaptée ».

Quelle est la taille d'un sommet

Regardons d'abord ce que contient un sommet. Dans glTF, chaque sommet est composé de plusieurs attributs :

AttributRôlePrécision par défautOctets par sommet
position (position)Coordonnées du sommet dans l'espace3 × float3212
normal (normale)Détermine la direction d'éclairage3 × float3212
tangent (tangente)Calcul des normal maps4 × float3216
texcoord_0 (UV)Coordonnées d'échantillonnage des textures2 × float328
color (couleur de sommet)Ombrage au niveau du sommet4 × float3216

Un sommet doté de tous les attributs PBR représente, pour les seules données géométriques, 48-64 octets. Un modèle de 100 000 sommets représente à lui seul 5-6 Mo rien que pour les sommets.

Notez qu'ici presque tout utilise float32 (flottants 32 bits). C'est la configuration par défaut, et aussi le point d'attaque de la compression des sommets — parce que la grande majorité des attributs n'ont absolument pas besoin d'une précision sur 32 bits.

Première arme : la quantification (Quantization)

La quantification est le principe fondamental de toute la compression des sommets ; Draco et MeshOpt l'utilisent aussi en interne.

L'essence de la quantification (quantization : mapper des flottants haute précision vers des entiers basse précision) tient en ceci : pour le flottant 3.14159265, retenir 3.14 suffit. Pour un ensemble de coordonnées dans un espace donné, au lieu d'enregistrer précisément chaque décimale sur 32 bits, on utilise un entier de plage plus restreinte pour le représenter.

Original :    position.x = 1.234567   (float32, 4 octets)
Quantifié :   position.x = 1234       (int16,   2 octets)  + un scale/offset pour restaurer

Avant vs. après quantification :

Attributoctets float32Quantifié (16 bits)Économie
position12650 %
normal126 (ou 4, en int8 + octahedral)50-67 %
tangent164-850-75 %
texcoord8450 %

Pour ce sommet de 48-64 octets, la quantification le ramène grosso modo à 16-24 octets, soit plus que réduit de moitié.

Quand utiliser la quantification

  • Vous voulez juste réduire la taille, sans viser le ratio de compression ultime
  • Vous voulez zéro dépendance de décodeur — un glTF quantifié utilise l'extension standard KHR_mesh_quantization, prise en charge nativement par les moteurs majeurs, sans librairie de décodeur supplémentaire
  • Votre plateforme cible est sensible à la taille du paquet (par ex. WeChat Mini Programs, où embarquer un décodeur Draco coûte des dizaines de Ko)

Quand ne pas l'utiliser

  • Le modèle est minuscule et le détail est l'argument de vente (par ex. pièces industrielles au millimètre). La quantification se trahit surtout sur les petits modèles — les textures tiennent, mais un déplacement de sommet de 0,1 mm est visible en gros plan.

Le vrai coût de la perte de précision : dans une scène de joaillerie, un modèle de bague quantifié sur 16 bits a montré de l'aliasing sur les bords métalliques en gros plan. La cause n'était pas un manque de sommets ; l'espace monde était trop petit pour que des entiers 16 bits l'expriment assez finement. La solution : réduire la plage de quantification (réduire la bounding box de position) ou augmenter la profondeur de bits pour les petits modèles.

Deuxième arme : MeshOpt

MeshOpt est l'extension glTF officielle EXT_meshopt_compression, positionnée comme « ratio de compression correct, décodage ultra-rapide ».

Ce qu'elle fait : d'abord quantifier les attributs (comme ci-dessus), puis appliquer une technique appelée codage d'entropie (lossless, sans perte) pour recompresser sans perte les entiers quantifiés. Autrement dit : quantification avec perte + codage d'entropie sans perte = taille plus petite, qualité identique à la quantification seule.

  • Ratio de compression : encore 30-50 % plus petit que la quantification seule
  • Vitesse de décodage : extrêmement rapide, pur C/JS, des dizaines de millions de sommets par seconde sur un thread
  • Taille du décodeur : minuscule (~20-30 Ko gzipé)
  • Compatibilité : prise en charge native par Three.js et Babylon.js, un standard de facto du web

Quand utiliser MeshOpt

  • Vous voulez un ratio de compression plus élevé mais ne pouvez pas accepter un décodage plus lent comme celui de Draco
  • Web, mobile, WebXR au cœur — la vitesse de décodage affecte directement l'expérience du premier rendu
  • Le modèle est décodé fréquemment (par ex. niveaux chargés dynamiquement)

Quand ne pas l'utiliser

  • Votre plateforme cible ne reconnaît même pas EXT_meshopt_compression (rare, vieux moteurs)
  • Vous voulez juste « que ça tourne » et vous fichez de 30 % de différence — alors la quantification pure est plus simple et supprime une dépendance

Troisième arme : Draco

Draco est la solution de compression de Google, positionnée pour « ratio de compression maximal ».

La différence fondamentale avec les deux autres : Draco modifie la connectivité (topologie) des sommets. La quantification ne change que la représentation numérique de chaque sommet ; MeshOpt ajoute un codage sans perte ; Draco réorganise le maillage triangulaire et exprime « quels sommets forment des triangles » de façon plus compacte.

  • Ratio de compression : le plus élevé des trois, souvent 90 %+ de réduction sur les modèles denses en sommets
  • Vitesse de décodage : la plus lente des trois, mais en absolu toujours rapide
  • Taille du décodeur : plus grande (~100-200 Ko, généralement chargée comme wasm séparé)
  • Qualité : réglable, mais aux ratios extrêmes une déformation visible apparaît

Quand utiliser Draco

  • Modèles extrêmement grands et super-denses en sommets (scans à millions de sommets, terrains)
  • Chargement unique, réutilisation longue après décodage (décodage plus lent acceptable)
  • La taille du paquet n'est pas le goulot, la vitesse de téléchargement oui

Quand ne pas l'utiliser

  • Mobile + premier rendu rapide nécessaire — il faut télécharger à la fois le décodeur et le modèle, ce qui ralentit
  • Environnements stricts sur la taille comme les Mini Programs
  • Modèles nécessitant animation squelettique, morph targets — le support de Draco pour cela est faible, une mauvaise configuration pose problème

Les trois côte à côte : un tableau de choix

Les ratios ci-dessous référencent des benchmarks communautaires (tests de DeepKolos + discussions Reddit r/threejs). Les modèles varient, mais les relations relatives sont stables :

OptionRatio de compression (vs float32)Vitesse de décodageTaille du décodeurAvec perte ?Extension glTF
Quantification pure~50 %Native, pas de décodage0Oui (précision)KHR_mesh_quantization
MeshOpt~25-35 %Extrêmement rapide~25 KoOui (précision)EXT_meshopt_compression
Draco~10-20 %Rapide (la plus lente des trois)~100-200 KoOui (précision + topologie)KHR_draco_mesh_compression

Décodeurs et compatibilité de plateforme :

PlateformeQuantification pureMeshOptDraco
Web bureau✅ Natif✅ Natif✅ Config décodeur requise
Web mobile✅ Natif✅ Natif⚠️ Décodeur lourd
WebXR/VR✅ Natif✅ Recommandé⚠️ Avec prudence
WeChat Mini Program✅ Recommandé✅ Recommandé❌ Éviter si possible

En une phrase : facile et sans dépendance → quantification pure ; équilibré → MeshOpt ; ratio max et on peut attendre → Draco.

Pratique : quantification et MeshOpt avec gltfpack

gltfpack est l'outil glTF officiel ; une seule commande gère quantification et MeshOpt.

D'abord installer (binaires depuis les versions de gltfpack) :

# Quantifier model.glb sur 16 bits et ajouter la compression MeshOpt
gltfpack -i model.glb -o model-packed.glb -cc

# -cc = compress (ajoute EXT_meshopt_compression sur la quantification par défaut)

Paramètres courants :

# Quantifier seulement, sans MeshOpt (le plus léger, zéro dépendance de décodeur)
# gltfpack quantifie les sommets sur 16 bits (KHR_mesh_quantization) par défaut,
# aucun flag supplémentaire n'est nécessaire
gltfpack -i model.glb -o model-quant.glb

# Quantifier et activer MeshOpt
gltfpack -i model.glb -o model-meshopt.glb -cc

# Avec beaucoup de sommets, on peut aussi simplifier (réduit le nombre de sommets, modifie le modèle)
gltfpack -i model.glb -o model-simplify.glb -cc -si 0.5
# -si 0.5 signifie simplifier à environ 50 % des sommets

À propos de -cc : c'est le commutateur « compress » qui applique en plus EXT_meshopt_compression.Sans -cc, gltfpack quantifie par défaut — c'est-à-dire que gltfpack -i in.glb -o out.glb seul est déjà « quantification pure, zéro dépendance de décodeur ». (-v est le flag de log verbeux — ne pas confondre.)

Résultats typiques (un modèle PBR de 5 Mo, 120k sommets, pour référence) :

TraitementTaille du fichierNotes
Original (float32)5.0 MoBase
Quantification pure (par défaut)2.6 MoRéduit de moitié, aucune différence visible
MeshOpt (-cc)1.7 MoEncore 35 % d'économie, chargement un peu plus rapide

Note : la simplification -si est une opération avec perte qui modifie la géométrie ; ce n'est pas la même chose que la compression. La compression essaie de préserver la fidélité visuelle ; la simplification supprime activement du détail. Les deux se cumulent, mais selon que la scène le permet.

Pièges courants

  • Direction des normales modifiée après quantification : souvent une précision trop faible. Utiliser au moins 16 bits pour les normales, ou un codage octaédrique sur 8 bits.
  • Matériaux perdus après décodage Draco : Draco ne compresse que les maillages ; matériaux et textures doivent être traités séparément. Au chargement, il faut configurer à la fois le décodeur Draco et les extensions KHR.
  • Draco ne se charge pas dans un Mini Program : le wasm du décodeur est restreint dans certains runtimes ; passer à MeshOpt règle généralement le problème.
  • Le modèle « dérive » après quantification : quand le modèle est loin de l'origine, la précision 16 bits ne peut exprimer à la fois de grandes coordonnées et de petits détails. Solution : rapprocher le modèle de l'origine avant quantification, ou augmenter la profondeur de bits.

Étape suivante

Les sommets sont compressés — ne fêtons pas trop tôt. Comme indiqué, les textures représentent 80 % de la taille du modèle. Ensuite nous changeons de champ de bataille et voyons pourquoi le PNG/JPG traditionnel est un « glouton de VRAM » aux yeux du GPU, et comment les formats de texture natifs GPU le résolvent.

Nous soutenir