Compactage d’atlas de sprites : espacement, puissances de deux et débordements
Un atlas de sprites semble simple : placer tous les sprites dans une grande texture plutôt que dans de nombreux fichiers. Mais les détails d’empaquetage déterminent si le jeu s’affiche proprement ou présente de légères franges colorées à chaque contour. Voici le fonctionnement réel d’un atlas, les causes du débordement aux raccords et les réglages précis qui l’évitent.
Pourquoi les atlas existent : les appels de rendu
Chaque fois qu’un GPU passe d’une texture à une autre pour dessiner, ce changement a un coût : cela correspond, conceptuellement, à un nouvel « appel de dessin ». Une scène de cinquante sprites dotés chacun de leur texture peut, avec un rendu naïf, nécessiter cinquante appels de dessin distincts, même si chaque sprite est minuscule. Sur mobile en particulier, ce surcoût s’accumule assez vite pour affecter la fréquence d’images bien avant que le GPU effectue un travail conséquent sur les pixels.
Un atlas de sprites contourne ce problème en réunissant de nombreux sprites sur une texture commune. Tant que tout ce qui est dessiné dans un lot utilise cette même texture, le moteur peut regrouper ces dessins en bien moins d’appels : dans le meilleur cas, un seul appel pour tous les sprites partageant l’atlas et le même matériau. C’est pourquoi les atlas comptent davantage dans les jeux comportant de nombreux petits sprites fréquemment redessinés, comme les particules, icônes d’interface et jeux de tuiles, que pour quelques grandes images de fond, où le nombre d’appels n’était pas le facteur limitant.
Empaquetage : placer les sprites dans une texture
Placer des sprites de tailles variables dans peu d'espace est une version du classique problème de placement dans des conteneurs. La plupart des outils d'atlas emploient l'une de ces deux approches :
- Compactage par étagères : les sprites sont placés de gauche à droite sur une ligne, ou « étagère », jusqu’à ce que l’un ne tienne plus ; une nouvelle ligne commence alors dessous. Simple et rapide, mais cela gaspille de l’espace lorsque les hauteurs varient beaucoup sur une ligne.
- Rectangles maximaux / découpe guillotine : l’outil suit les régions rectangulaires libres après chaque placement et ajuste les nouveaux sprites dans le meilleur espace restant, en divisant les rectangles au fil du travail. Le placement est plus dense et demande plus de calculs par sprite ; c’est la méthode standard de la plupart des outils modernes — TexturePacker, Sprite Atlas d’Unity, exporteur de Godot — dès que le nombre de sprites n’est plus trivial.
La rotation est une optimisation supplémentaire proposée par certains outils : tourner un sprite de 90 degrés peut le faire tenir dans une bande d’espace inutilisée où il ne tiendrait pas autrement. Le compactage est plus dense, mais le rendu devient plus complexe, car les coordonnées UV doivent tenir compte de la rotation. C’est donc généralement une option à activer plutôt qu’un réglage par défaut.
Vous n’avez pas à implémenter vous-même ces mécanismes : les outils des moteurs et les empaqueteurs dédiés s’en chargent. Il est toutefois utile de comprendre l’opposition entre densité d’empaquetage et marges, présentées ensuite. Un empaquetage serré gaspille moins d’espace de texture, mais les marges entre sprites empêchent le débordement décrit ci-dessous. Un empaqueteur trop agressif peut donc réintroduire des défauts visuels pour économiser quelques pour cent de surface.
Débordement de texture : définition et causes
Débordement de texture se produit lorsque le bord rendu d’un sprite montre un fragment de couleur du sprite voisin dans l’atlas : une fine ligne colorée sur un ou plusieurs côtés, sans rapport avec son propre dessin. C’est l’un des bugs d’atlas les plus courants ; il a deux causes distinctes souvent confondues.
Contamination par filtrage. Lorsqu’un sprite est affiché à une échelle différente de 1:1, ou que la caméra le déplace vers une position non alignée sur les pixels, le filtre de texture du GPU échantillonne un petit voisinage de texels autour de chaque point, pas seulement le texel le plus proche. Même avec un filtre ponctuel ou au plus proche défini pour la texture, le filtrage et le mipmapping lors de l’échantillonnage peuvent dépasser légèrement le rectangle UV du sprite. Si la région voisine de l’atlas contient un autre sprite, sa couleur déborde.
Contamination des mipmaps. Les mipmaps sont des versions réduites de la texture complète, utilisées lorsqu’un sprite apparaît petit à l’écran. Leur génération mélange des blocs de la texture en pleine résolution : les couleurs d’un sprite peuvent donc se mêler au niveau de mipmap du voisin avant même que les sprites soient dessinés. C’est pourquoi le débordement apparaît parfois seulement à distance ou à petite échelle, alors que le résultat semble correct en zoomant.
Les deux causes ont la même origine : deux sprites sans rapport placés directement côte à côte dans l’atlas, sans rien entre eux pour absorber l’erreur d’échantillonnage.

Corriger la contamination : espacement et extrusion
La correction standard est espacement — laisse quelques pixels transparents ou de contours dupliqués entre chaque sprite de l’atlas, afin que les échantillonnages parasites tombent dans cet espace plutôt que dans le contenu du sprite voisin. Un à deux pixels suffisent généralement à la résolution native ; si le sprite est fortement agrandi au rendu ou si les mipmaps sont activés, davantage d’espacement augmente la tolérance.
Un simple espace transparent résout le problème de débordement du sprite voisin, mais en crée un autre, plus discret : au bord du sprite, le filtrage peut maintenant mélanger sa propre couleur de contour avec l’espace transparent, produisant un léger assombrissement ou une frange à la limite au lieu d’un bord parfaitement net. Extrusion (parfois appelée extension des bords) corrige cela en remplissant la marge avec une copie des pixels du bord du sprite, étirés vers l’extérieur, plutôt qu’en la laissant transparente. Le problème des voisins est résolu de la même façon : un espace demeure entre les sprites distincts. Mais le contour du sprite se mélange à ses propres couleurs prolongées plutôt qu’à une transparence vide.
La plupart des outils d’atlas (TexturePacker, l’empaqueteur Sprite Atlas de Unity, l’export d’atlas de Godot) proposent directement une taille de marge et une option d’extrusion dans leurs réglages. Il est rarement justifié de laisser la marge à zéro : un ou deux pixels par bord de sprite coûtent peu d’espace de texture, comparé au temps passé à diagnostiquer des raccords intermittents visibles seulement à certains niveaux de zoom.
Les puissances de deux comptent-elles encore ?
Historiquement, les GPU exigeaient des textures dont les dimensions étaient des puissances de deux (256, 512, 1024, 2048…) pour gérer efficacement les mipmaps et certains modes de répétition. Les autres textures pouvaient échouer complètement ou utiliser un rendu plus lent. Les GPU et API modernes (OpenGL ES 3+, Metal, Vulkan, DirectX 11+) les prennent en charge nativement, sans pénalité significative pour un rendu 2D de base. Cette obligation a donc largement disparu sur les plateformes actuelles.
Cela compte dans certains cas :
- Mipmapping. Certaines plateformes et anciennes API exigent encore des dimensions en puissances de deux pour générer proprement une chaîne complète de mipmaps. Si votre atlas utilise des mipmaps, vérifiez la contrainte réelle de la plateforme visée plutôt que de supposer.
- Matériel ancien ou limité Mobiles anciens, WebGL 1 et systèmes intégrés bénéficient ou exigent puissances de deux.
- Alignement mémoire et formats de compression. Les formats de compression par blocs, très utilisés sur mobile, travaillent sur des blocs de taille fixe et complètent parfois les dimensions non conformes jusqu’à la prochaine taille valide. Choisir dès le départ une puissance de deux évite que ce remplissage discret consomme inutilement de la mémoire.
En pratique : si vous ciblez les ordinateurs actuels, les consoles ou les appareils mobiles modernes avec une chaîne 2D standard, des dimensions d’atlas qui ne sont pas des puissances de deux conviennent. Pour WebGL 1, les anciens mobiles ou les systèmes embarqués, les puissances de deux restent un choix par défaut plus sûr et peu coûteux ; la plupart des outils arrondissent automatiquement la taille de l’atlas à la puissance de deux supérieure lorsque ce réglage est activé.
Rognage et pivots
Rognage signifie que l’outil de placement rogne chaque sprite à son contenu réellement opaque avant de le placer dans l’atlas, en supprimant la marge transparente autour. Cela améliore presque toujours la densité : un petit personnage entouré de beaucoup de transparence prend bien moins de place une fois rogné.
Le problème est que le rognage modifie la taille effective et le décalage du sprite, ce qui compte si la logique du jeu ou le système d’animation exige que toutes les images aient les mêmes dimensions et le même pivot par rapport au canevas d’origine. Dans un cycle de marche, une image où le personnage penche à gauche possède des limites opaques différentes de celle où il penche à droite. Rognées indépendamment, les deux images ont des tailles différentes ; les alterner naïvement déplace alors la position apparente du personnage d’une image à l’autre.
Tout outil d’atlas prenant en charge le rognage conserve aussi la taille d’origine non rognée et le décalage, précisément pour résoudre ce problème. Le moteur replace le sprite rogné à sa position correcte dans le cadre d’origine : le pivot reste donc visuellement cohérent, même si moins d’espace de texture est consacré aux pixels transparents. Le Sprite Atlas de Unity et l’importateur de Godot gèrent cela automatiquement lorsque le rognage est activé dans l’outil, plutôt qu’effectué à la main avant l’empaquetage. Rogner vous-même les sprites avant de les empaqueter supprime les métadonnées de décalage dont le moteur a besoin pour les repositionner correctement.
Un atlas ou plusieurs ?
Un méga-atlas unique n'est pas toujours meilleur. Raisons pratiques d'en séparer plusieurs :
- Occupation mémoire. Si un niveau n’utilise qu’une partie de vos sprites, charger un atlas par niveau ou scène évite de conserver en mémoire GPU des données inutilisées pour du contenu éloigné du joueur.
- Limites de taille de texture. Le matériel impose une dimension maximale de texture, généralement 4096 ou 8192 sur les plateformes modernes, moins sur les anciens appareils mobiles. Un ensemble de sprites suffisamment grand ne tient pas dans un seul atlas, quelle que soit l’efficacité de l’empaquetage.
- Fréquence de mise à jour. Les sprites souvent modifiés, comme une interface en itération rapide, gagnent à avoir leur propre atlas séparé des images stables et rarement retouchées, pour qu’un petit changement n’impose pas de reconstruire et téléverser tout l’atlas.
- Différences de matériau. Les sprites nécessitant des shaders ou modes de fusion différents ne peuvent pas être regroupés au rendu, quel que soit l’atlas ; les réunir n’offre donc aucun avantage de compactage.
Un choix raisonnable consiste à regrouper par contexte d’usage : un atlas pour les tuiles du décor d’un niveau, un pour ses personnages et un pour l’interface. Ne les fusionnez davantage que si le profilage montre que les appels de dessin limitent réellement les performances sur votre matériel cible.
Questions fréquentes
Quel espacement faut-il réellement ?
Un à deux pixels suffisent dans la plupart des cas à l’échelle d’affichage native, avec les mipmaps désactivés. Si les sprites sont fortement agrandis à l’exécution ou si les mipmaps sont activés, augmentez la marge. Il n’existe pas de valeur universelle ; testez votre atlas aux échelles et niveaux de zoom réellement utilisés par le jeu.
Pourquoi le débordement n’apparaît-il qu’à certains niveaux de zoom ?
Ce motif indique un débordement de mipmap plutôt qu’un débordement par filtrage à la résolution de base : le niveau échantillonné à cette distance a été construit à partir d’un mélange traversant une limite de sprite. L’extrusion et un espacement suffisant corrigent les deux causes, mais si le problème est propre aux mipmaps, assurez-vous que l’espace résiste à plusieurs réductions de niveau, pas seulement à la texture de base.
Faut-il s'en soucier sans mipmaps ni changement d'échelle ?
Moins, mais pas complètement. Même avec un rendu pixel-perfect 1:1 et un filtrage par points, une position de caméra sous-pixel ou un placement de sprite non entier peut conduire le GPU à échantillonner un pixel fractionnaire traversant une limite. Une petite marge constitue une précaution peu coûteuse, même dans une configuration 2D entièrement pixel-perfect.
Rogner affecte-t-il les collisions ?
Non, si vos formes de collision sont définies indépendamment, comme c’est généralement le cas. Si le projet déduit automatiquement les limites de collision des dimensions du sprite, vérifiez s’il lit la taille rognée ou la taille originale non rognée. Utiliser directement la taille rognée peut réduire involontairement une hitbox sur les images ayant beaucoup de marge transparente.
Vous créez des sprites à réunir dans un atlas ?
Sprite Gen réunit les images individuelles dans une planche, disposées en lignes avec l’espacement choisi : le compactage par étagères décrit ci-dessus plutôt qu’une variante à rectangles maximaux, ce qui suffit pour la plupart des ensembles d’icônes et d’images. Si vos sprites sources sont encore dans une planche à séparer, le Découpeur de planches de sprites la divise en images individuelles. Les deux fonctionnent entièrement dans le navigateur, sans téléversement.
Ouvrir le générateur de sprites