Ich entwickle ein Sprite-basiertes 2D-Spiel für mobile Plattformen und verwende OpenGL (eigentlich Irrlicht) zum Rendern von Grafiken. Zuerst habe ich das Sprite-Rendering auf einfache Weise implementiert: Jedes Spielobjekt wird als Quad mit einem eigenen GPU-Draw-Aufruf gerendert. Wenn ich also 200 Spielobjekte hätte, hätte ich 200 Draw-Aufrufe pro Frame durchgeführt. Natürlich war dies eine schlechte Wahl und mein Spiel war vollständig CPU-gebunden, da bei jedem GPU-Draw-Aufruf ein kleiner CPU-Overhead anfällt. Die GPU blieb die meiste Zeit im Leerlauf.
Jetzt dachte ich, ich könnte die Leistung verbessern, indem ich Objekte in großen Stapeln sammle und diese Stapel mit nur wenigen Zeichenaufrufen rendere. Ich habe Batching implementiert (so dass jedes Spielobjekt mit derselben Textur im selben Batch gerendert wird) und dachte, dass meine Probleme weg sind ... nur um herauszufinden, dass meine Framerate noch niedriger war als zuvor.
Warum? Nun, ich habe 200 (oder mehr) Spielobjekte und sie werden 60 Mal pro Sekunde aktualisiert. Für jeden Frame muss ich eine neue Position (Translation und Rotation) für Scheitelpunkte in der CPU neu berechnen (GPU auf mobilen Plattformen unterstützt keine Instanzierung, daher kann ich dies dort nicht tun) und diese Berechnung 48000 pro Sekunde (200 * 60 * 4 seitdem) durchführen Jedes Sprite hat 4 Eckpunkte) scheint einfach zu langsam zu sein.
Was könnte ich tun, um die Leistung zu verbessern? Alle Spielobjekte bewegen / drehen sich (fast) in jedem Frame, daher muss ich die Scheitelpunktpositionen wirklich neu berechnen. Die einzige Optimierung, die mir einfällt, ist eine Nachschlagetabelle für Rotationen, damit ich sie nicht berechnen muss. Würden Punkt-Sprites helfen? Irgendwelche bösen Hacks? Noch etwas?
Vielen Dank.
quelle
Ich würde empfehlen, ein VBO zu haben, wobei jeder Scheitelpunkt die Position / Drehung jedes gerenderten Objekts enthält und die Stapelung basierend auf der Textur erfolgt, wie Sie es tun. Ich bin mit ogl ES nicht sehr vertraut, daher bin ich mir nicht sicher, welche Version von glsl unterstützt wird, aber Sie können möglicherweise sogar anhand einer Reihe von Texturen stapeln und speichern, welche der vier oder mehr Texturen Sie übergeben in würden Sie innerhalb des Scheitelpunkts verwenden. Punkt-Sprites würden definitiv Ihre Leistung verbessern, da dies die Datenmenge, die Sie senden, drastisch reduzieren würde und das Stapeln niemals die Leistung verringern sollte, wenn Sie es richtig machen. Sie können die Leistung auch ein wenig verbessern, indem Sie die Rotation auf dem Shader berechnen und nur einen int / float-Wert an die Parameter oder innerhalb des Scheitelpunkts selbst übergeben. (Parameter wären schneller,
quelle
Sie erwähnen mobile Plattformen ohne Instanz. Aber Sie haben immer noch Vertex-Shader, nicht wahr?
In diesem Fall können Sie immer noch Pseudo-Instanzen durchführen, was ebenfalls sehr schnell ist. Erstellen Sie ein VBO (GL_STATIC_DRAW) mit den Eckpunkten (relativ zum Mittelpunkt des Sprites, z. B. -1 / -1, 1 / -1, 1/1, -1/1) und allen erforderlichen Texturkoordinaten .
Setzen Sie dann eines der generischen Scheitelpunktattribute für jeden Zeichenaufruf auf den Mittelpunkt des Sprites und zeichnen Sie die beiden Dreiecke mit dem gebundenen Puffer. Lesen Sie im Vertex-Shader das generische Vertex-Attribut und fügen Sie die Koordinaten des Vertex hinzu.
Das erspart Ihnen das Blockieren einer Datenübertragung für jedes Sprite und sollte viel schneller sein. Die tatsächliche Anzahl der Draw Calls ist nicht so schrecklich wichtig, das Blockieren / Abwürgen dazwischen ist.
quelle
Das Problem liegt in der Datenmenge, die Sie in jedem Frame an die GPU senden. Erstellen Sie einfach einen VBO für jeden Stapel und füllen Sie ihn einmal aus. Wenden Sie dann beim Zeichnen der Stapel die entsprechenden Transformationsmatrizen an (über glMultMatrix oder einen Shader, wenn Sie ES 2.0 verwenden).
quelle