Ist es in einem Browser am besten, ein großes Spritesheet oder mehrere (10000) verschiedene PNGs zu verwenden?

33

Ich erstelle ein Spiel in jQuery, in dem ich ungefähr 10000 32x32-Kacheln verwende. Bisher habe ich sie alle einzeln verwendet (kein Sprite Sheet). Eine durchschnittliche Karte verwendet ungefähr 2000 Kacheln (manchmal wiederverwendete PNGs, aber alle separaten Divs) und die Leistung reicht von stabil (Chrome) bis etwas verzögert (Firefox). Jede dieser Divs wird absolut mit CSS positioniert. Sie müssen nicht bei jedem Tick aktualisiert werden, nur wenn eine neue Karte geladen wird.

Wäre es für die Leistung besser, Spritesheet-Methoden für die Divs mit CSS-Hintergrundpositionierung zu verwenden, wie dies bei gameQuery der Fall ist?

Danke im Voraus!

Nick
quelle
3
Wo zum Teufel brauchst du 10 000 Kacheln für die Karte? Ich schlage vor, dass Sie nicht alle Karten auf der Benutzerseite hochladen / zeichnen. Zeige nur einen Teil, der sichtbar ist. Wenn sich der Benutzer bewegt, laden Sie den nächsten Abschnitt. So funktioniert jede 3D-Grafik.
Deele
Eine durchschnittliche Karte verwendet 2000 verschiedene Kacheln oder nur 2000 Kacheln insgesamt? Wie groß sind die Karten, die Sie erstellen?
Nick Larsen
Haben Sie darüber nachgedacht, ein oder mehrere größere Bilder als Hintergrund zu verwenden und eine polygonale Kollisionserkennung für Grenzen durchzuführen?
SAHornickel

Antworten:

50

Mein Vorschlag

Zu viele kleine PNGs verursachen einen hohen Netzwerk-Overhead (aufgrund der Größe der HTTP-Anforderungen, aber auch des PNG-Headers und wahrscheinlich, was noch wichtiger ist, der Unfähigkeit, eine effiziente Komprimierung durchzuführen). Andererseits hat eine sehr große PNG den Nachteil, dass das Laden einige Zeit in Anspruch nimmt und dauerhaft im Speicher (40 Megabyte für 10.000 Kacheln) in einem zusammenhängenden Speicherblock verbleiben muss.

Ich empfehle den Mittelweg: mehrere PNGs von angemessener Größe, zum Beispiel 1024 Kacheln der Größe 32 × 32 . Vielleicht nach Themen gruppiert (zum Beispiel eine PNG mit Waldkacheln, eine mit Bergkacheln, eine andere mit Stadtkacheln - ich kenne das Thema Ihres Spiels nicht, aber Sie haben die Idee).

Hinweis zur Cache-Effizienz

Wegen der Effizienz des Speicherzugriffs sollten Sie Ihre Spritesheets niemals zu breit machen. Das Ausschneiden von Kacheln aus einem 128 × 8192-Bild ist immer schneller als das Ausschneiden aus einem 8192 × 128-Bild.

Stellen Sie sich vor, Sie möchten die erste Kachel in einem 8192 × 128-Bild aufteilen. Der Einfachheit halber wird angenommen, dass 1 Pixel 1 Byte ist. Die ersten beiden Pixelzeilen sind so angeordnet (Zellen enthalten ihre Bytenummer im Speicher):

┌────┬────┬───┬────┬──────────┬─────┐
  0   1 │...│ 31    ....    8191 1st line of pixels: bytes 0 to 8191
├────┼────┼───┼────┼──────────┼─────┤
81928193│...│8223   ....   16383 2nd line of pixels: bytes 8192 to 16383
├────┼────┼───┼────┼──────────┼─────┤
 ..  .. │...│ ..    ....    ... 

Also, um das blitten ersten Zeile des ersten Titels, wird der Browser - Engine abrufen Bytes 0zu31 . Um die blitten zweite Zeile , wird es abrufen Bytes 8192auf8223 , und so weiter , bis der 32. Zeile , in Bytes 253952zu253983 werden abgerufen.

Die Gesamtzahl der verarbeiteten Bytes beträgt 32 × 32. Der gesamte Speicherbereich beträgt jedoch mehr als 253984 Byte. Auf einer modernen CPU bedeutet dies 32 oder 33 Cachestände . Im Gegensatz dazu würde der Speicherbereich bei einem Bild von 128 × 8192 nur 4000 Byte betragen, was bedeutet, dass nicht mehr als zwei Cachestände vorhanden sind.

Da die heutigen CPUs sehr schnell sind, sind Cache-Stalls sehr teuer und hängen Berechnungen. Die Verwendung eines 128 × 8192-Bilds anstelle eines 8192 × 128-Bilds ist also theoretisch potenziell mindestens achtmal so schnell. In der Praxis hängt dies davon ab, wie das Blitting implementiert wird: Es ist möglich, dass die zugrunde liegende Engine selbst Bilder in Kacheln aufteilt, um das Problem zu verringern.

Das ist nicht leicht zu erklären und ich habe nicht damit gerechnet, viel näher darauf einzugehen. Ich hoffe es macht Sinn!

sam hocevar
quelle
4
"Beachten Sie auch, dass Sie Ihre Spritesheets aus Gründen der Speicherzugriffseffizienz niemals zu breit machen sollten. Das Blitten von Kacheln aus einem 128 × 8192-Bild ist immer schneller als das Blitten aus einem 8192 × 128-Bild." - Schöne Neugier, würden Sie bitte näher darauf eingehen? :)
Grimshaw
@ DevilWithin: Ich habe versucht, das Problem zu erklären; Lass es mich wissen, wenn ich klar genug bin!
Sam Hocevar
Das Zeug zur Cache-Effizienz ist faszinierend. Haben Sie Zahlen über den Unterschied, den dies in Bezug auf die Framerate macht?
Gregory Avery-Weir
Ob es sich um ein Problem handelt, das implementierungsspezifisch aussieht, aber wenn APIs wie OpenGL auf diese Weise auf Texturen einwirken, ist es sicher wichtig, dies zu berücksichtigen, danke :)
Grimshaw,
2
@ DevilWithin: Was ich geschrieben habe, ist nur für eine CPU gültig - eine GPU, die massiv parallel ist, sehr unterschiedliche Cache-Einstellungen hat und Texturen in ihrem eigenen internen Format speichert, das für den wahlfreien Zugriff optimiert ist. Dies ist der Grund, warum in OpenGL quadratische Texturen mit Zweierpotenzen empfohlen werden, und ich würde diese Regel auch für Kachelsets befolgen.
Sam Hocevar
5

Ein riesiges Spritesheet wird Ihnen (wahrscheinlich) eine bessere Leistung bringen, einfach weil eine der größten Ursachen für Verzögerungen die Hin- und Rückfahrt von der Browseranforderung zum Server zum Browser ist. 10.000 HTTP-Aufrufe werden viel, viel länger dauern als 1 HTTP-Aufruf, der eine Datei zurückgibt, die 10.000 größer ist.

Abhängig von der Struktur des Spiels und dem von Ihnen erstellten HTML-Code gibt es möglicherweise andere Möglichkeiten, um die Verzögerung zu verringern.

thedaian
quelle