Optimale OpenGL 2D Sprite-Stapelverarbeitung (Best Practice)

7

Ich arbeite an einer einfachen 2D-Engine mit OpenGL (3.3+) zum Rendern und habe mich gefragt, wie die optimale Methode für das Sprite-Batching aussehen würde. Ich plane, alle Sprites in einen (oder weniger) Texturatlanten zu setzen. Es überrascht nicht, dass jedes Sprite aus 2 Dreiecken und 4 Texturkoordinaten besteht. Nehmen wir der Einfachheit halber an, dass nur die Sprites vorerst nicht animiert sind.

Nun zu meiner Frage, ich weiß nicht, wie ich sie am besten zeichnen könnte. Soweit ich graben konnte, habe ich zwei Möglichkeiten:

  1. Zeichnen Sie jedes Sprite separat, um die Position / Drehung / Skalierung jedes Sprites im Shader über MVP-Matrizen zu ändern. Dies bedeutet auch, dass ich die Sprite-Datenpuffer (Vertex Pos. & Tex. Coords) auf der GPU nicht aktualisieren müsste.

  2. Füllen Sie alle Sprites-Daten in einem einzigen VBO und zeichnen Sie sie alle mit einem glDrawElementsAufruf (vorausgesetzt, sie verwenden denselben Texturatlas und Shader). Dann müsste ich jedoch den VBO in jedem Frame aktualisieren (oder zumindest die geänderten Teile, was auch bedeutet, dass ich den Status jedes Sprites beobachten müsste).

Welche dieser Optionen ist aus praktischer Sicht besser? Oder gibt es eine andere Methode, um das zu erreichen, was ich versuche?

user53681
quelle

Antworten:

3

"Welche dieser Optionen ist aus praktischer Sicht besser ?"

Ich werde das Wort "praktisch" hier so interpretieren, dass es sich von "theoretisch höchster Leistung auf einem Computer" unterscheidet ...

Bei zwei Dreiecken pro Sprite ist die Neuberechnung aller Scheitelpunkte auf der Host-CPU nicht so teuer und leicht zu überlegen.

Da alle Geometrien gleich sind (zwei Dreiecke), können Sie möglicherweise auch glDrawElementsInstanced () verwenden, das dem Ansatz von @ Nox ähnelt.

Aber wirklich ("praktisch") beginnen Sie mit jeder Technik, die Sie mögen, und wenn sie auch nur ein wenig funktioniert, fahren Sie fort. Stellen Sie sicher, dass sich irgendwo in Ihrem Code die Abstraktion auf hoher Ebene befindet, z. B. sprite-> setPositionAndRotation (x, y, theta) oder was auch immer. Weil es wichtiger ist, Ihr Spiel zum Laufen zu bringen. Später kann dieses eine Detail bei Bedarf optimiert werden.

Ich verwende eine Variation der Antwort von @ Nox, um> 10000 50ish-Dreiecksobjekte (jeweils unterschiedlich) in 3d zu verschieben. Eigentlich verwende ich eher eine Textur als ein einheitliches Array, aber die gleiche Idee mit "Instanz-ID". Aber ich begann damit, viele Draw-Aufrufe zu verwenden (ok, bis zu 1000 Draws) und dann die Scheitelpunktpositionen direkt in einem großen Puffer zu manipulieren, was in Ordnung war, bis ich in den vielen Tausenden aufstand ...

David Van Rand
quelle
2

Sie sind nicht darauf beschränkt, nur einen MVP pro VBO zu haben. Sie müssten das VBO also nicht in jedem Frame aktualisieren, nur weil Sie alle Ihre Sprites in einem einzigen VBO speichern. Ich speichere eine Instanz-ID mit jedem Scheitelpunkt, der sich nur pro Modell ändert, und verwende diese Instanz-IDs, um sie in ein einheitliches Array von mat4 zu indizieren, eine für jede "Instanz".

Nox
quelle