Es wird versucht, Schablonen in 2D zu verwenden, während die Ebenentiefe beibehalten wird

7

Dies ist ein Bildschirm, der zeigt, was gerade passiert, damit Sie einen Referenzrahmen erhalten.

Geben Sie hier die Bildbeschreibung ein

Das Problem, auf das ich stoße, ist, dass mein Spiel aufgrund der Menge an Texturtausch, die ich während meines Draw Calls mache, langsamer wird. Da sich Wände, Zeichen, Böden und alle Objekte auf ihrem jeweiligen Sprite-Blatt befinden, das diese Typen enthält, wird die geladene Textur beim Kacheln mindestens 3 bis 5 Mal ausgetauscht, während sie die Sprites zyklisch zeichnet und zeichnet, um sie richtig zu schichten.

Jetzt habe ich versucht, alle gängigen Objekte zusammen in ihre jeweiligen Listen zu werfen und sie dann mithilfe von layerDepth so zu zeichnen, was die Dinge viel besser macht, aber das neue Problem, auf das ich stoße, hat mit der Art und Weise zu tun, wie meine Türen / Fenster funktionieren sind an Wänden gezeichnet. Ich habe nämlich Schablonen verwendet, um einen Block an den Wänden zu entfernen, der in Form der Tür / des Fensters gezeichnet ist, sodass die Wand beim Zeichnen ein Loch in Tür- / Fenstergröße aufweist.

Auf diese Weise wurde meine Zeichnung für Wände eingerichtet, als ich Fliesen für Fliesen ging, anstatt gemeinsame Objekte zu gruppieren.

  1. Zuerst würde überprüft, ob sich an dieser Wand eine Tür / ein Fenster befand. Wenn nicht, würde es alle Schritte überspringen und einfach normal zeichnen. Andernfalls
  2. Beenden Sie das aktuelle SpriteBatch
  3. Löschen Sie die Puffer mit einer transparenten Farbe, um das bereits Gezeichnete zu erhalten
  4. Starten Sie ein neues Spritebatch mit Schabloneneinstellungen
  5. Zeichnen Sie den Türbereich
  6. Beenden Sie das SpriteBatch
  7. Starten Sie ein neues Spritebatch, das die zuvor festgelegte Schablone berücksichtigt
  8. Zeichnen Sie die Wand, die jetzt mit einem Loch gezeichnet wird
  9. Beende das Spritebatch
  10. Starten Sie einen neuen Spritebatch mit den normalen Einstellungen, um mit dem Zeichnen von Kacheln fortzufahren

Beim Zeichnen von Kacheln für Kacheln spielte das Löschen der Tiefen- / Schablonenpuffer keine Rolle, da ich keine Layertiefe verwendete, um zu organisieren, was über was gezeichnet wird.

Jetzt, da ich nicht mehr Kacheln, sondern Kacheln aus Listen gängiger Objekte zeichne, hat dies meinen Zeichnungsaufruf erheblich beschleunigt, aber ich kann anscheinend keine Möglichkeit finden, das Schablonensystem so zu halten, dass der Bereich einer Tür oder eines Fensters ausgeblendet wird wird in eine Wand gezogen. Die Wurzel des Problems liegt darin, dass beim Beenden eines SpriteBatch zum Ändern des DepthStencilState das aktuelle RenderTarget abgeflacht wird und keine Tiefensortierung mehr für weiter unten in der Linie gezeichnete Elemente erfolgt. Dies bedeutet, dass Wände immer über alles gezeichnet werden, unabhängig von Tiefe oder Position in der Spielwelt und sogar übereinander, da die Schablone einmal für jede Wand mit einer Tür oder einem Fenster ausgeführt werden muss.

Kennt jemand einen Weg, um dies zu umgehen? Um es auf den Punkt zu bringen, brauche ich eine Möglichkeit, Dinge nach Schichttiefe sortiert zu zeichnen und gleichzeitig Teile bestimmter Sprites zu schablonieren / zu maskieren.

Steve
quelle
Ich weiß nicht genug über XNA, um eine echte Antwort zu veröffentlichen, aber dies scheint verdächtig: "Wenn ich ein SpriteBatch beende ... wird das aktuelle RenderTarget abgeflacht und es gibt keine Tiefensortierung mehr." Dies sollte nicht passieren, wenn die Sprites tatsächlich in den Tiefenpuffer gezeichnet werden (ich gehe davon aus, dass "layerDepth" dies tut). Das Ändern des Tiefenschablonenstatus muss den Tiefenpuffer nicht löschen. Es könnte sich also lohnen, zu prüfen, ob es eine Möglichkeit gibt, dieses Verhalten zu ändern.
Nathan Reed
Wenn Sie "Start eines neuen Spritebatch" sagen, heißt das nicht, dass Sie eine neue SpriteBatch-Instanz erstellen, oder? Das Erstellen eines neuen Stapels jedes Mal, wenn Sie etwas zeichnen, würde Ihr Spiel erheblich verlangsamen.
Mike Cluck

Antworten:

1

Ich kenne nicht genug XNA, um Ihnen eine richtige Lösung zu geben, aber ich kann Ihnen eine allgemeine Antwort geben.

Das Problem, das Sie haben, ist der Algorithmus des Malers . Insbesondere müssen Sie alle Dinge bestellen, die Sie zeichnen möchten, bevor Sie sie zeichnen können. Der häufigste Weg, um dieses Problem zu vermeiden, ist ein Tiefenpuffer. Interessanterweise wird dies auch als Z-Puffer bezeichnet, da die Z-Werte im Kameraraum gespeichert werden.

Da Sie jedoch kein Z haben (weil Sie ein 2D-Spiel schreiben), können Sie diese Technik nicht verwenden. Oder kannst du?

Beachten Sie Folgendes: Eine orthografische Projektion ändert die Perspektive von Punkten in 3D-Punkten nicht. Dies ist nützlich für Dinge wie Benutzeroberflächenelemente, da Sie immer möchten, dass sie auf die gleiche Weise funktionieren.

Ich schlage vor, dass Sie einen benutzerdefinierten Shader schreiben, der 3D-Matrizen und einen Tiefenwert pro Scheitelpunkt verwendet. Dieser Tiefenwert sollte für die Tiefenpufferung verwendet werden, nicht jedoch für die Projektion.

Im Pseudo-Shadercode:

[vertex shader]
pos_output = TransformOrthographic * TransformView * vec3(pos_vertex.x, pos_vertex.y, 0.0);
depth_output = depth_vertex;

[fragment shader]
depth_output = (depth_input - depth_min) / (depth_max - depth_min);

Sobald Sie dies eingerichtet haben, können Sie aufhören, sich Gedanken darüber zu machen, ob Objekte in der falschen Reihenfolge gerendert werden, und stattdessen ihren Tiefenwert festlegen.

Jetzt sollten Sie in der Lage sein, alles in einem Draw-Aufruf zu rendern, ohne sich Gedanken über das Schablonieren von Bildschirmabschnitten machen zu müssen.

Ritter666
quelle