2D-Spiele und modernes OpenGL

10

Vorurteile

Ok, was ich bisher gesammelt habe, ist Folgendes:

  • Verwenden Sie keine feste Pipeline (veraltet oder veraltet)
  • vbos speichern "Objektmodelle" (meistens n Scheitelpunktdaten)
  • vaos beschreiben, wie Daten abgelegt werden, damit Draw-Aufrufe wissen, welcher Teil jedes vbo für welche Art von Vertex-Informationen bestimmt ist (ein vao kann sich auf mehrere vbos beziehen, das Gegenteil ist etwas schwierig).
  • Jeder Draw-Aufruf sendet auch Vertex-Daten an Shader

Wie ich 3D sehe (optional)

Angesichts dieser Informationen kann ich sehen, wie schön das Zeichnen komplizierter 3D-Objekte mit modernem OpenGL ist. Grundsätzlich laden Sie eine Reihe von Objektmodellen (wahrscheinlich von Blender oder einer ähnlichen Software) in VBOs mit lokalen Koordinaten und geben dann für jede Instanz eines Objekts einfach einen anderen Shader-Parameter (Offset) an, um ihn in den Weltraum zu zeichnen.

Problem / Frage

In 2D sind Probleme und Prioritäten jedoch völlig unterschiedlich. Sie zeichnen nicht viele komplexe Objekte, Sie benötigen keine komplizierten Projektionsmatrizen und so weiter und Shader sind viel einfacher.

Was wäre der beste Weg, um mit modernem OpenGL häufig (wirklich häufig, im Grunde jeden Rahmen) Geometriewechsel zu zeichnen?

Im folgenden Absatz sehen Sie einige Problemideen (das Kreis- und Rechteckproblem), die die Art der Änderungen, an denen ich interessiert bin, besser identifizieren.

Meine Versuche (optional)

Also begann ich zu überlegen, wie ich mit dem Zeichnen grundlegender 2D-Geometrie auf dem Bildschirm umgehen würde:

  • Ein Quadrat: Laden Sie ein [(1, 0), (1, 1), (0, 1), (0, 0)]VBO für die Geometrie eines Quadrats im lokalen Raum und geben Sie dem Shader die tatsächliche Breite des Quadrats sowie die Weltkoordinaten und Farbinformationen an

kühlt ab, sieht einfach aus. Gehen wir zu einem Kreis:

  • ein Kreis: Dreiecksfächer mit ... eh. Wie viel Präzision (Anzahl der Eckpunkte)? Für kleine Kreise muss die Genauigkeit klein sein und für Fehlerkreise muss die Genauigkeit hoch sein. Das eindeutige Laden von 1 VBO kann möglicherweise nicht in alle Fälle passen. Was ist, wenn ich Präzision hinzufügen muss, weil die Größe eines Kreises größer ist?

Weniger cool. Gehen wir zu etwas etwas Einfacherem, einem Rechteck:

  • ein Rechteck: eh. Es gibt keine "allgemeine Rechteckgeometrie". Sie haben nur ein Verhältnis von Breite zu Höhe und das war's, aber jedes Rechteck ist wahrscheinlich anders, wenn sich die Größe ändert.

Wie Sie sehen können, geht es von dort aus bergab. Besonders bei komplexen Polygonen und so weiter.

Keine Code-Richtlinie: P.

Ich brauche nur einen Überblick über die Idee, es ist kein Code erforderlich, insbesondere C- oder C ++ - Code. Sagen Sie einfach Dinge wie: "Erstellen Sie ein VBO mit diesen Scheitelpunktdaten und binden Sie es dann, ...".

Schuh
quelle
Ich glaube, ich verstehe, was Sie fragen, aber vielleicht möchten Sie dieser Frage etwas mehr Richtung geben. Es ist ein bisschen unklar, was gefragt wird - was eigentlich ein enger Grund ist.
Lysol
@AidanMueller Ich bin mir nicht sicher, was du meinst, aber du kannst gerne mehr Anweisungen geben, wenn du das Bedürfnis hast.
Schuh
Die beste Antwort beginnt derzeit mit "Ihre Hauptfrage scheint zu sein". Das zeigt an, dass es unklar ist, was Sie fragen. Vielleicht sollten Sie am Ende Ihrer Frage eine Zusammenfassung dessen geben, was Sie nicht wissen müssen. Dies ist schließlich eine Frage / Antwort, keine Diskussion.
Lysol
@AidanMueller Nicht in diesem Zusammenhang, glaube ich. Es heißt "Ihre Hauptfrage scheint zu sein ..." und dann zitiert er / sie die Frage, die ich gestellt habe. Was tatsächlich darauf hinweist, dass es klar genug ist, um zitiert zu werden. Der Satz zeigt auch nicht an, dass meine Frage unklar ist, sondern dass es eine Hauptfrage und eine weitere Nebenfrage gibt (nämlich: Was ist die Lösung für die spezifischen Fälle, die ich vorgestellt habe). Ich sehe das Problem mit meiner aktuellen Frage wirklich nicht, und anscheinend haben es nicht einmal die Antwortenden getan, da ich beide Antworten sehr nützlich und auf den Punkt gebracht habe.
Schuh
Mit einem Fragment-Shader können Sie einen präzisen Kreis zeichnen.
user253751

Antworten:

5

Ihre Hauptfrage scheint zu sein:

Was wäre der beste Weg, um mit modernem OpenGL häufig (wirklich häufig, im Grunde jeden Rahmen) Geometriewechsel zu zeichnen?

In den meisten Fällen gibt es keinen großen Unterschied zwischen 2d und 3d OpenGL. Die Grafik-Pipeline hat diese eine zusätzliche Koordinate, Z, die in 2d nicht so häufig verwendet wird, aber das war es auch schon.

Es gibt verschiedene Möglichkeiten, die Geometrie bei jeder Zeichnung zu ändern.

  • Sie können in jedem Frame neue von der CPU bereitgestellte Scheitelpunkte verschieben. (Unter /programming/14155615/opengl-updating-vertex-buffer-with-glbufferdata finden Sie einige Hinweise zur Wiederverwendung von Puffern.)

  • Mit können Sie verschiedene Teile eines vorhandenen Puffers zeichnen glDrawArrays(mode, first, count). Wenn sich die Animation wiederholt, können Sie möglicherweise die vorberechneten Frames mit den verschiedenen Scheitelpunktlisten in einem großen Puffer ablegen und für jeden Frame den entsprechenden Teil des Puffers zeichnen.

  • Sie können die Scheitelpunktliste mit einigen anderen Daten beeinflussen, z. B. einem einheitlichen Array oder einer Textur. Lesen Sie diese Daten in Ihrem Vertex-Shader und wenden Sie sie entsprechend an. Dies sind nur andere Redewendungen für die Darstellung von Daten auf der GPU und werden wahrscheinlich keinen großen Unterschied in der Leistung haben.

  • Wenn Sie viele Instanzen derselben Geometrie haben (möglicherweise durch Attribute beeinflusst), glDrawElementsInstanced()kann dies hilfreich sein

  • Sie können die Scheitelpunktliste algorithmisch in den Scheitelpunkten für Scheitelpunkte, Geometrie oder Tessellation beeinflussen. Wenn die Animation mathematisch beschrieben werden kann, können Sie möglicherweise dieselbe Scheitelpunktliste beibehalten und nur einige Shader-Uniformen pro Frame ändern.

Und vielleicht wird Ihre Animation als reine Textur ausgedrückt, wobei alle Animationen Pixel für Pixel von der CPU ausgeführt oder von der Festplatte vorgerendert werden.

Im Großen und Ganzen würde ich sagen: "Computer sind schnell, machen es so einfach wie möglich, wahrscheinlich indem Sie in jedem Frame neue, von der CPU erstellte Scheitelpunkte festlegen. Überprüfen Sie dann, ob dies gut genug ist. Profilieren Sie die Batterie- / CPU-Auslastung Erstens, Speicherbedarf. "

Ihre andere Frage , umschrieben: "Was ist ein guter Weg, um Kreise und Rechtecke zu zeichnen?"

Kreise.

  • Mit Tessellation - Shadern (oder Geometrie - Shader) Sie könnten Ihre Geometrie dynamisch gestalten.

  • Sie können Quadrate zeichnen und in Ihrem Fragment-Shader nur innerhalb eines Radius undurchsichtig (Alpha = 1,0) und außerhalb des Radius transparent (Alpha = 0,0). Dann ist es jedes Mal pixelgenau. (Machen Sie Ihre quadratischen Scheitelpunkte -1 bis +1 und im Fragment-Shader so etwas wie outColor.a = dot(coord.xy, coord.xy) < 1.0 ? 1.0 : 0.0;. Könnte auch die Kante ein wenig glätten, würde dort gut aussehen ...)

  • Sie könnten einfach immer einen 120-Dreieck-Lüfter verwenden. Wahrscheinlich gut genug.

Rechtecke.

  • Ich denke, Sie haben Ihre eigene Frage dazu beantwortet. Was Sie vorschlagen, wird gut funktionieren!
David Van Rand
quelle
Der Fragment-Shader / Radius ist ziemlich ordentlich, danke. In Bezug auf die Beantwortung meiner eigenen Frage glaube ich nicht zu verstehen, was Sie meinen.
Schuh
Oh, genau wie bei einem Quadrat erwähnen Sie, um die Breite zu steuern (mit Uniform, nehme ich an), und Sie haben geschrieben: "Sie haben nur ein Verhältnis von Breite zu Höhe und das war's, aber jedes Rechteck ist wahrscheinlich anders, wenn sich die Größe ändert." . Machen Sie für ein Rechteck dasselbe wie für ein Quadrat, aber Sie benötigen 4 Werte (x, y, w, h) anstelle von 3 (x, y, w). Oder geben Sie (xlow, xhigh, ylow, yhigh) als vier Uniformen ein. Mit Ihrer Eingabe von (0,0) bis (1,1) reicht der Vertex Shader aus, um das zu tun, was er benötigt.
David van Brink
Oh, ich verstehe, das macht Sinn.
Schuh
Gibt es im modernen GL einen automatischen Lüfter wie GL_TRIANGLE_FAN aus der Pipeline mit festen Funktionen?
John P
5

Ich kann nicht sagen, dass ich Experte für dieses Thema bin, und in meinen Spielprojekten habe ich mich mehr auf die 3D-Seite konzentriert, daher ist meine 2D-Seite im Allgemeinen ziemlich einfach, wenn ich Dinge verwende, die für die 3D-Seite gemacht sind. und natürlich ist meine Perspektive auf der Spieleseite, daher geht es in meiner 2D-Grafik mehr um das Blitting von Sprites als um Geometrie. Aus dieser Perspektive

1) Quadrate und Rechtecke sind ziemlich einfach. Ich habe nur eine einzelne 1x1-Box in einem VBO, mit der ich alles blitze. Ich übergebe MVP-Matrizen mit dieser "Einheitsbox" an den Shader und habe sie mit zusätzlicher Skalierung kombiniert, um die Box auf die richtigen Abmessungen zu skalieren. Wie Sie wissen, können Sie unterschiedliche x- und y-Skalierungen verwenden.

Für meine Zwecke habe ich darüber nachgedacht, von der "Unit Box" zu einer Art Partikel-Engine überzugehen, um 2D-Sprites zu zerstören, aber das ist eine andere Geschichte.

2) Ich habe nicht viel mit Kreisen gearbeitet, ich verwende nur feste VBOs mit einer bestimmten Anzahl von Eckpunkten. Aber ich könnte mir vorstellen, dass ich einige Schritte machen könnte, um die Anzahl der für den Kreis gezeichneten Eckpunkte zu beeinflussen.

Beim Verbinden von VBO-Daten mit Shader-Attributen verwende ich glVertexAttribPointer. Es hat einen Schrittparameter, der für verschachtelte Daten verwendet werden soll (die ich verwende). Aber es könnte möglich sein, es so zu verwenden:

glVertexAttribPointer(..., n * sizeof(VERTEX_DATA), ...);

... um jeden n-ten Scheitelpunkt aus dem Puffer auszuwählen und damit die Anzahl der für den Kreis gezeichneten Scheitelpunkte zu beeinflussen. Ich könnte mehrere VAOs mit demselben VBO mit unterschiedlichen Schritten erstellen, die sich auf die Anzahl der für den Kreis gezeichneten Scheitelpunkte auswirken. Das habe ich nicht versucht, dachte ich.

Im Allgemeinen, ja, die Arbeit mit VBOs und dergleichen macht das Optimieren auf der CPU-Seite etwas komplexer. Deshalb habe ich verschiedene Dinge untersucht, um das Optimieren auf der GPU-Seite (Shader) durchzuführen. Laut diesem Artikel ist die Verwendung von VBOs auf moderner Hardware jedoch effizienter, selbst wenn Sie viele CPU-seitige "Eingriffe" benötigen:

http://www.quelsolaar.com/opengl_performance.txt

Ich hoffe, dies hilft Ihnen ein wenig bei der Gestaltung und Entscheidung Ihrer Richtungen.

MaKo
quelle
2
"Schritt optimieren, um die Anzahl der für den Kreis gezeichneten Scheitelpunkte zu beeinflussen" Super cool!
David van Brink