Sprite-Atlas-Packung: Abstände, Zweierpotenzen und auslaufende Farben
Ein Sprite-Atlas klingt nach einer einfachen Idee: Alle Sprites kommen auf eine große Textur statt in viele kleine Dateien. Doch die Details ihrer Anordnung bestimmen, ob dein Spiel sauber dargestellt wird oder an jedem Sprite-Rand schwache Farbsäume entstehen. Hier erfährst du, was ein Atlas tatsächlich macht, warum Farben an den Nähten übergreifen und welche konkreten Einstellungen das verhindern.
Warum es Atlanten gibt: Zeichenaufrufe
Jedes Mal, wenn eine GPU vom Zeichnen mit einer Textur zu einer anderen wechselt, verursacht das Kosten – vereinfacht einen neuen „Zeichenaufruf“. Eine Szene mit fünfzig einzeln texturierten Sprites kann bei einfacher Darstellung fünfzig separate Zeichenaufrufe benötigen, selbst wenn jedes Sprite winzig ist. Besonders auf Mobilhardware summiert sich dieser Aufwand so schnell, dass er die Bildrate beeinflusst, lange bevor die GPU nennenswert viele Pixel verarbeitet.
Ein Sprite-Atlas umgeht das, indem er viele Sprites auf einer gemeinsamen Textur unterbringt. Solange alles in einem Batch Gezeichnete dieselbe Textur abtastet, kann der Renderer die Zeichenvorgänge in wesentlich weniger Aufrufen zusammenfassen. Im besten Fall reicht ein Zeichenaufruf für sämtliche Sprites, die denselben Atlas und dasselbe Material verwenden. Deshalb sind Atlanten für Spiele mit vielen kleinen, häufig neu gezeichneten Sprites – Partikeleffekte, UI-Symbole, Kachelsets – wichtiger als für eine Handvoll großer Hintergrundbilder, bei denen die Anzahl der Zeichenaufrufe nie der Engpass war.
Packalgorithmen: Sprites in einer Textur unterbringen
Einen Satz unterschiedlich großer Sprites mit möglichst wenig ungenutztem Platz in einer Textur unterzubringen, ist eine Variante des klassischen Packproblem. Die meisten Atlas-Werkzeuge verwenden eine Variante von einem dieser beiden Ansätze:
- Regalpackung: Sprites werden von links nach rechts in einer Zeile, einem „Regal“, platziert, bis einer nicht mehr hineinpasst. Darunter beginnt dann ein neues Regal. Einfach und schnell, verschwendet aber Platz, wenn die Sprite-Höhen innerhalb einer Zeile stark variieren.
- Maximale Rechtecke / Guillotine-Packverfahren: das Packprogramm verfolgt die nach jeder Platzierung übrigen freien Rechteckbereiche und setzt neue Sprites in den besten verbleibenden Platz. Dabei werden Rechtecke fortlaufend aufgeteilt. Das ergibt dichtere Packung bei höherem Rechenaufwand pro platziertem Sprite und ist für mehr als nur wenige Sprites der Standardansatz der meisten modernen Atlaswerkzeuge wie TexturePacker, Unitys Sprite Atlas und Godots Exporter.
Drehung ist eine weitere Optimierung, die manche Packprogramme anbieten: Ein um 90 Grad gedrehter Sprite passt möglicherweise in einen schmalen Restbereich, in den er ungedreht nicht passen würde. Dadurch wird dichter gepackt, aber das Rendern wird komplexer, weil die UV-Koordinaten die Drehung berücksichtigen müssen. Deshalb muss diese Einstellung meist ausdrücklich aktiviert werden und ist nicht standardmäßig eingeschaltet.
Nichts davon musst du selbst implementieren. Engine-Werkzeuge und spezielle Packprogramme übernehmen das. Verstehen solltest du aber das Spannungsverhältnis zwischen Packdichte und den als Nächstes behandelten Abständen: Dichteres Packen verschwendet weniger Texturfläche. Abstände zwischen Sprites verhindern jedoch die unten beschriebenen Farbübergriffe. Ein zu aggressiv eingestellter Packer kann deshalb visuelle Fehler wieder einführen, um wenige Prozent Texturfläche zu sparen.
Auslaufende Texturfarben: was das ist und warum es passiert
Auslaufende Texturfarben liegt vor, wenn die gerenderte Kante eines Sprites einen Farbstreifen des direkt daneben im Atlas gepackten Sprites zeigt. Das ist eine dünne farbige Linie an einer oder mehreren Seiten, die nichts mit der eigenen Sprite-Grafik zu tun hat. Es ist einer der häufigsten atlasspezifischen Fehler und hat zwei getrennte Ursachen, die oft verwechselt werden.
Farbübergriffe durch Filterung. Wird ein Sprite mit einer anderen Skalierung als 1:1 gezeichnet oder bewegt die Kamera ihn auf eine nicht pixelgenaue Position, tastet der GPU-Texturfilter eine kleine Umgebung von Texeln um jeden Abtastpunkt ab, nicht nur das nächstgelegene einzelne Texel. Selbst bei Punkt-/Nearest-Neighbor-Filterung auf Texturebene können Filterung und Mipmapping bei der Abtastung leicht über das UV-Rechteck des Sprites hinausreichen. Enthält der benachbarte Atlasbereich einen anderen Sprite, fließt dessen Farbe ein.
Farbübergriffe durch Mipmaps. Mipmaps sind vorab verkleinerte Versionen der vollständigen Textur, die verwendet werden, wenn ein Sprite klein auf dem Bildschirm dargestellt wird. Beim Erzeugen einer Mipmap werden Blöcke der Textur in voller Auflösung vermischt. Dadurch können Farben eines Sprites schon vor dem Zeichnen in die Mipmap-Stufe eines Nachbarsprites gelangen. Deshalb erscheinen Farbübergriffe manchmal nur aus der Entfernung oder bei kleiner Skalierung, während vergrößert alles richtig aussieht.
Beide Ursachen gehen auf denselben Grundzustand zurück: Zwei voneinander unabhängige Sprites liegen im Atlas direkt nebeneinander, ohne etwas dazwischen, das den Abtastfehler abfangen könnte.

Farbübergriffe beheben: Abstand und Randerweiterung
Die übliche Lösung ist Randabstand – lasse zwischen allen Sprites im Atlas einige transparente oder kopierte Randpixel frei. So landen abweichende Abtastungen in der Lücke statt auf dem Inhalt des Nachbarsprites. Ein bis zwei Pixel Abstand genügen in den meisten Fällen bei nativer Auflösung. Wird der Sprite beim Rendern deutlich vergrößert oder sind Mipmaps aktiviert, bietet mehr Abstand mehr Fehlertoleranz.
Einfacher transparenter Abstand verhindert, dass Farben benachbarter Sprites einfließen, bringt aber ein kleineres eigenes Problem mit sich: Direkt an der Sprite-Kante kann die Filterung nun die eigene Kantenfarbe mit dem transparenten Rand mischen. Dadurch entsteht unmittelbar an der Sprite-Grenze eine leichte Verdunkelung oder ein Saum statt einer vollständig sauberen Kante. Randerweiterung (manchmal auch Randerweiterung genannt) behebt das, indem der Abstand mit nach außen verlängerten Kopien der eigenen Randpixel des Sprites gefüllt wird, statt transparent zu bleiben. Das Problem benachbarter Sprites wird genauso gelöst – zwischen verschiedenen Sprites bleibt ein Abstand –, aber der eigene Rand des Sprites wird mit weiteren eigenen Pixeln vermischt statt mit leerer Transparenz.
Die meisten Atlas-Werkzeuge – TexturePacker, Unitys Sprite-Atlas-Packer, Godots Atlas-Export – bieten Abstand und Randerweiterung direkt in ihren Einstellungen an. Selten gibt es einen Grund, den Abstand auf null zu lassen. Ein oder zwei Pixel pro Sprite-Rand kosten wenig Texturplatz verglichen mit der Fehlersuche nach gelegentlichen Nahtartefakten, die nur bei bestimmten Zoomstufen auftreten.
Sind Zweierpotenzen noch wichtig?
Früher verlangten GPUs Texturabmessungen als Zweierpotenzen (256, 512, 1024, 2048…), um Mipmapping und bestimmte Wiederholungsmodi effizient zu unterstützen. Texturen mit anderen Abmessungen funktionierten entweder gar nicht oder nutzten einen langsameren Darstellungsweg. Moderne GPUs und APIs (OpenGL ES 3+, Metal, Vulkan, DirectX 11+) unterstützen solche Texturen nativ ohne nennenswerte Leistungseinbußen bei einfacher 2D-Darstellung. Die zwingende Anforderung entfällt deshalb auf Zielgeräten der aktuellen Generation weitgehend.
In bestimmten Situationen ist es weiterhin wichtig:
- Mipmapping. Manche Plattformen und ältere APIs benötigen weiterhin Abmessungen als Zweierpotenzen, um eine vollständige Mipmap-Kette sauber zu erzeugen. Wenn dein Atlas Mipmaps verwendet, prüfe die tatsächlichen Vorgaben deiner Zielplattform, statt sie einfach anzunehmen.
- Ältere oder leistungsschwache Hardware. Einfache Mobilgeräte, WebGL-1-Kontexte und manche eingebetteten Zielsysteme profitieren weiterhin von Größen als Zweierpotenzen oder benötigen sie.
- Speicherausrichtung und Kompressionsformate. Blockkompressionsformate, die besonders auf Mobilgeräten verbreitet sind, komprimieren in Blöcken fester Größe. Nicht passende Abmessungen werden manchmal ohnehin auf die nächste gültige Größe aufgefüllt. Wenn du von Anfang an eine Zweierpotenz wählst, vermeidest du, dass diese unbemerkte Auffüllung unnötig Speicher kostet.
Praktisch gilt: Für aktuelle Desktop-, Konsolen- oder moderne Mobilhardware mit einer üblichen 2D-Pipeline sind Atlas-Abmessungen ohne Zweierpotenzen in Ordnung. Für WebGL 1, ältere Mobilgeräte oder eingebettete Systeme bleiben Zweierpotenzen die sicherere Voreinstellung und verursachen wenig Mehraufwand. Die meisten Packprogramme runden die Atlasgröße bei aktivierter Einstellung automatisch auf die nächste Zweierpotenz auf.
Randbeschnitt und Drehpunkte
Randbeschnitt bedeutet, dass das Packprogramm jeden Sprite vor dem Platzieren im Atlas auf seinen tatsächlichen deckenden Inhalt beschneidet und den transparenten Rand entfernt. Das verbessert die Packdichte fast immer. Ein Sprite mit viel transparentem Rand um eine kleine Figur belegt beschnitten deutlich weniger Atlasplatz als unbeschnitten.
Der Haken ist, dass der Beschnitt die tatsächliche Sprite-Größe und den Versatz verändert. Das ist wichtig, wenn deine Spiellogik oder dein Animationssystem für jedes Einzelbild dieselben Abmessungen und denselben Drehpunkt relativ zur ursprünglichen Arbeitsfläche erwartet. Ein Gehzyklusbild mit nach links geneigter Figur hat andere deckende Grenzen als eines mit nach rechts geneigter Figur. Werden beide unabhängig beschnitten, haben sie unterschiedliche Größen. Ein einfaches Wechseln zwischen ihnen verschiebt die scheinbare Figurenposition von Einzelbild zu Einzelbild.
Jedes Atlas-Werkzeug mit Beschnittunterstützung speichert genau dafür neben den beschnittenen Daten auch die ursprüngliche, unbeschnittene Größe und den Versatz. Die Engine stellt das beschnittene Sprite wieder an seiner richtigen Position innerhalb der ursprünglichen Einzelbildgrenzen dar. Der Pivot bleibt dadurch optisch konsistent, obwohl weniger Texturplatz für transparente Pixel verwendet wird. Unitys Sprite Atlas und Godots Importer erledigen das automatisch, solange das Beschneiden im Werkzeug aktiviert wird und nicht zuvor von Hand erfolgt. Wer Sprites vor dem Packen selbst beschneidet, verwirft die Versatzmetadaten, die die Engine für die korrekte Positionierung benötigt.
Ein Atlas oder mehrere?
Alles in einen einzigen Mega-Atlas zu stopfen, ist nicht automatisch besser. Einige praktische Gründe, stattdessen mehrere Atlanten zu verwenden:
- Belegung des Speichers. Wenn ein Level nur einen Teil deiner Sprites nutzt, verhindert ein Atlas pro Level oder Szene, dass ungenutzte Sprite-Daten für Inhalte im GPU-Speicher bleiben, in deren Nähe sich der Spieler gerade nicht befindet.
- Texturgrößenlimits. Die Hardware setzt eine maximale Texturabmessung fest, bei modernen Zielgeräten häufig 4096 oder 8192 und bei älterer Mobilhardware weniger. Ein ausreichend großer Sprite-Satz passt unabhängig von der Packeffizienz nicht in einen einzigen Atlas.
- Änderungshäufigkeit. Häufig geänderte Sprites, etwa in einer schnell weiterentwickelten Benutzeroberfläche, profitieren von einem eigenen Atlas, getrennt von stabilen, selten bearbeiteten Grafiken. So erzwingt eine kleine Änderung nicht den vollständigen Neubau und erneuten Upload des gesamten Atlas.
- Materialunterschiede. Sprites mit unterschiedlichen Shadern oder Mischmodi können unabhängig vom Atlas nicht gemeinsam gebündelt werden. Sie zusammenzupacken bietet daher keinen Vorteil für das Batching.
Ein sinnvoller Standard ist die Gruppierung nach Verwendung: ein Atlas für die Umgebungskacheln eines Levels, einer für seine Figuren und einer für die Benutzeroberfläche. Führe sie nur weiter zusammen, wenn Leistungsmessungen zeigen, dass Zeichenaufrufe auf deiner Zielhardware tatsächlich ein Engpass sind.
Häufig gestellte Fragen
Wie viel Abstand brauche ich tatsächlich?
Ein bis zwei Pixel reichen in den meisten Fällen bei nativer Anzeigegröße und deaktivierten Mipmaps aus. Werden Sprites zur Laufzeit deutlich vergrößert oder sind Mipmaps aktiviert, erhöhe den Wert. Es gibt keine allgemein richtige Zahl. Teste deinen konkreten Atlas deshalb mit den Skalierungen und Zoomstufen, die das Spiel tatsächlich verwendet.
Warum erscheinen auslaufende Farben nur bei bestimmten Zoomstufen?
Dieses Muster deutet eher auf auslaufende Farben in Mipmaps als auf Filterungsprobleme bei der Grundauflösung hin. Die bei dieser Entfernung abgetastete Mipmap-Stufe wurde aus einer Mischung erstellt, die eine Sprite-Grenze überschritt. Extrusion und ausreichende Abstände helfen gegen beide Ursachen. Ist das Problem aber mipmapspezifisch, prüfe, ob dein Abstand breit genug ist, um die Verkleinerung über mehrere Mipmap-Stufen hinweg zu überstehen, nicht nur in der Basistextur.
Muss ich das beachten, wenn ich keine Mipmaps verwende und Sprites nicht skaliere?
Weniger, aber nicht gar nicht. Selbst bei pixelgenauer 1:1-Darstellung mit Point-Filterung können Kamerapositionen zwischen Pixeln oder nicht ganzzahlige Sprite-Positionen dazu führen, dass die GPU ein anteiliges Pixel über einer Grenze abtastet. Ein kleiner Zwischenabstand ist auch in einem rein pixelgenauen 2D-Setup eine günstige Absicherung.
Beeinflusst das Beschneiden Hitboxen oder Kollisionsformen?
Nicht, wenn deine Kollisionsformen unabhängig definiert sind, wie es üblich ist. Leitet dein Projekt Kollisionsgrenzen automatisch aus Sprite-Abmessungen ab, prüfe, ob es die beschnittene oder ursprüngliche unbeschnittene Größe liest. Die direkte Verwendung der beschnittenen Größe kann bei Einzelbildern mit viel transparentem Rand eine Hitbox unerwartet verkleinern.
Erstellst du Sprites für einen Atlas?
Sprite Gen kombiniert einzelne Bilder zu einem Sheet und ordnet sie zeilenweise mit dem von dir eingestellten Abstand an. Es verwendet also die oben beschriebene Regalpackung statt einer Variante mit maximalen Rechtecken, was für die meisten Symbol- und Einzelbildsets ausreicht. Wenn deine Quell-Sprites noch in einem gemeinsamen Sheet vorliegen, das zuerst aufgeteilt werden muss, schneidet das Sprite-Sheet-Schneidewerkzeug es in einzelne Einzelbilder. Beide laufen vollständig im Browser, ohne Upload.
Sprite Gen öffnen