Comment faire voler les modèles 3D lourds même sur des GPU faibles
Imaginez ceci : vous téléchargez un modèle cool depuis Sketchfab, vous le glissez dans votre moteur, et... les FPS chutent à un chiffre tandis que votre GPU hurle. La géométrie ne semble pas si complexe, mais le GPU « s'étouffe ». Le problème n'est souvent pas le nombre de polygones lui-même, mais la façon dont ces données sont disposées en mémoire et l'ordre dans lequel elles sont transmises au pipeline de rendu.
Je suis tombé sur le dépôt meshoptimizer, qui s'attaque systématiquement à ces problèmes. Ce n'est pas simplement « un autre simplificateur de maillage » mais tout un ensemble d'outils de bas niveau pour préparer la géométrie au rendu réel. L'auteur du projet, Arseny Kaplutkin (zeux), est bien connu dans les cercles de développement de moteurs graphiques, et cette expertise transparaît dans chaque ligne de code.
Quel est le problème fondamental
Un GPU moderne est une bête qui doit être constamment nourrie. Si vous lui donnez des données au hasard, il perd du temps à attendre la mémoire ou à recalculer les mêmes sommets encore et encore.
Typiquement, les données de maillage traversent plusieurs étapes :
- Récupération des index et sommets depuis la mémoire.
- Vertex Shader.
- Rasterization.
- Pixel Shader.
Si vos triangles sont arrangés de façon chaotique dans le tampon, le Vertex Cache fonctionne inefficacement. Le GPU doit re-transformer les sommets qu'il a vus il y a quelques millisecondes à peine. meshoptimizer réordonne les données pour maximiser l'efficacité du cache et minimiser le travail redondant.
Ce que la bibliothèque peut faire
Le projet est un ensemble de fichiers C++ qui s'intègrent facilement dans n'importe quel projet. Pas de dépendances lourdes, juste des maths pures et des algorithmes.
Optimisation du cache de sommets
C'est le fondement. L'algorithme reconstruit l'ordre des triangles pour que les sommets fréquemment utilisés restent plus longtemps dans le cache du GPU. En code, cela semble extrêmement simple :
Après cet appel, l'ACMR (Average Cache Miss Ratio) chute généralement de façon spectaculaire. C'est littéralement un gain de performance gratuit sans modifier le modèle lui-même.
Simplification de maillage
Si vous avez besoin de créer des LOD (Level of Detail), cet outil est une bouée de sauvetage. Il peut réduire les polygones tout en essayant de préserver la silhouette et les détails importants. Il existe même un mode « sale » (simplifySloppy) qui se moque de la topologie mais fonctionne à une vitesse éclair et convient aux objets très éloignés.
Une fonctionnalité intéressante : le simplificateur peut travailler avec des attributs. Il comprend qu'on ne peut pas simplement déplacer les sommets si cela « casserait » les coordonnées de texture ou les normales.
Compression des données
Si votre jeu pèse 100 Go, dont la moitié est de la géométrie, vous allez adorer le codec intégré. Il empaquète les sommets et les index dans un format compact. Ce n'est pas un remplacement pour zstd ou lz4, mais un complément. D'abord vous faites passer vos données à travers meshopt_encodeVertexBuffer, puis vous les compressez avec un archiveur classique. Les résultats sont impressionnants : les données peuvent occuper 2 à 4 fois moins d'espace.
Support des Mesh Shaders
Pour ceux qui vivent à la pointe en utilisant les Mesh Shaders (sur les nouvelles cartes NVIDIA et AMD), la bibliothèque peut diviser un maillage en meshlets. Ce sont de petits morceaux de géométrie qui s'adaptent parfaitement au nouveau modèle de pipeline programmable.
Avantages pratiques
Comment cela peut-il être utile dans la vraie vie ?
- Optimisation du pipeline d'assets. Vous pouvez écrire un petit utilitaire basé sur
gltfpack(inclus dans le package) qui exécutera automatiquement tous vos modèles.gltfà travers l'optimiseur avant la construction. - Streaming de géométrie. Grâce à la compression avancée, les modèles se chargeront plus rapidement, ce qui est critique pour les jeux en monde ouvert.
- Rendu des ombres. La bibliothèque vous permet de créer un tampon d'index séparé pour les positions uniquement (Shadow Indexing). Cela accélère le dessin des ombres puisque le GPU n'a pas besoin de traîner les lourdes données de coordonnées de texture et de normales là où seule la profondeur est nécessaire.
Implémentation technique
La bibliothèque est écrite en C++ mais possède une interface compatible C. Il existe des wrappers pour Rust (crate meshopt) et JavaScript (via WebAssembly).
Ce que j'ai particulièrement aimé :
- Pas d'allocations cachées. Vous allouez la mémoire vous-même, la bibliothèque y écrit simplement.
- C'est très rapide. Le décodage des sommets et des index fonctionne à plusieurs gigaoctets par seconde.
- Un minimum de magie. Tous les algorithmes sont documentés, les fonctions analytiques vous permettent de vérifier immédiatement à quel point votre maillage s'est amélioré (fonctions
meshopt_analyze*).
Qui devrait essayer
Si vous écrivez votre propre moteur, travaillez sur un visualiseur navigateur lourd, ou voulez simplement que votre application ne rame pas sur les graphiques intégrés Intel, meshoptimizer est indispensable.
Le moyen le plus simple de commencer est avec l'utilitaire en ligne de commande gltfpack. Essayez de faire passer n'importe quel modèle lourd à travers et voyez le résultat dans n'importe quel visualiseur. Vous remarquerez probablement la différence en taille de fichier et en fluidité de rendu sans aucune perte de qualité.
Le projet est vivant, activement maintenu, et utilisé dans les principaux moteurs commerciaux. C'est ce cas rare où une petite bibliothèque couvre une énorme couche de problèmes de performance graphique.
Projets similaires