Wie kann ich mit den Rotations- und Skalierungsparametern von Spritebatch einen 3D-ähnlichen Effekt erzielen?

7

Ich arbeite an einem 2D-Spiel mit einer Top-Down-Perspektive, die Secret of Mana und den 2D Final Fantasy-Spielen ähnelt. Ein großer Unterschied besteht darin, dass es sich um ein Action-RPG handelt, das eine dreidimensionale Physik-Engine verwendet.

Ich versuche, eine Zielgrafik (im Grunde ein Pfeil) zu den Füßen meiner Charaktere zu zeichnen, wenn sie auf eine Fernkampfwaffe zielen. Zuerst habe ich nur den Zielvektor des Charakters in Bogenmaß konvertiert und diesen in Spritebatch übergeben, aber es gab ein Problem. Die Position jedes Objekts in meiner Welt wird für die Perspektive skaliert, wenn es auf den Bildschirm gezeichnet wird. Wenn also die Koordinaten der Physik-Engine (1, 0, 1) sind, sind die Bildschirmkoordinaten tatsächlich (1, .707) - die Y- und Z-Achse werden mit einem Perspektivfaktor von .707 skaliert und dann addiert, um den Bildschirm zu erhalten Koordinaten.

Dies bedeutete, dass die Richtung, in die die Zielgrafik zeigte (dank ihres Rotationswerts, der an Spritebatch übergeben wurde), nicht mit der Richtung übereinstimmte, in die sich das Projektil im Laufe der Zeit tatsächlich bewegte. Die Dinge sahen gut aus, als die Charaktere nach links, rechts, oben oder unten feuerten, aber wenn Sie auf einer Diagonale feuerten, stimmte die Perspektive der Physik-Engine nicht mit der simplen Art überein, wie ich die Zielrichtung des Charakters in eine Bildschirmdrehung umwandelte.

Ok, schnell vorwärts bis jetzt: Ich habe die Rotation des Zielers auf den Pfad abgestimmt, den das Projektil tatsächlich nehmen wird. Dazu zerlege ich eine Transformationsmatrix, die ich aus zwei Rotationsmatrizen aufbaue (eine zur Darstellung der Rotation des Zielers). und eine zur Darstellung der 45-Grad-Drehung der Kamera auf der x-Achse). Meine Frage ist, gibt es eine Möglichkeit, nicht nur eine Rotation aus einer Reihe von Matrixtransformationen zu erhalten, sondern auch eine Vector2-Skala, die dem Zieler das Aussehen eines 3D-Objekts verleiht, das durch die Perspektive verzerrt wird? Ich denke, ich möchte eine orthografische Perspektive. Der Zielpfeil würde also länger, wenn er seitwärts zeigt, und kürzer, wenn er nach Norden und Süden zeigt, aufgrund der Perspektive. Gleichzeitig würde es breiter werden, wenn es nach Norden und Süden zeigt, und weniger breit, wenn es nach rechts oder links zeigt.

Ich möchte vermeiden, die Zieltextur tatsächlich in 3D zu zeichnen, da ich zu diesem Zeitpunkt in meinem Projekt noch den Layerdepth-Parameter von Spritebatch verwende und nicht herausfinden möchte, wie ein 3D-Objekt innerhalb der Tiefensortierung gezeichnet wird System habe ich schon.

Ich kann Code und weitere Details bereitstellen, wenn dies als Frage zu vage ist ... Dies ist mein erster Beitrag zum Stapelaustausch. Vielen Dank fürs Lesen!

Hinweis: (Ich denke) Mir ist klar, dass es keine technisch korrekte 3D-Perspektive sein kann, da das Skalierungsargument vector2 des Spritebatch nicht zulässt, dass ein Objekt so verzerrt wird, wie es eigentlich sein sollte. Was mich wirklich interessiert ist, gibt es eine gute Möglichkeit, den Effekt zu fälschen, oder sollte ich ihn einfach fallen lassen und überhaupt nicht skalieren?

Bearbeiten, um ohne die Hilfe eines Bildes zu klären (anscheinend kann ich sie noch nicht posten):

Ich möchte, dass der Zielpfeil so aussieht, als wäre er zu Füßen des Charakters auf den Boden gemalt worden. Daher sollte er auf der Grundebene (in meinem Fall der XZ-Ebene) gezeichnet sein, die in einem Winkel von 45 Grad (um die Ecke) geneigt sein sollte die X-Achse) aus der Betrachtungsperspektive.

Alex

Alic44
quelle
4
Sie müssen MS-Farbe auspeitschen und dort einige Bilder zeichnen, Kumpel. Zu viel erzählen, nicht genug zeigen.
Ingenieur
Ja, zeichnen Sie, was Sie brauchen, es ist sehr verwirrend. Aber ja, es ist zum Beispiel möglich, einen Vertex-Shader zu verwenden, um Ihr Sprite zu drehen.
David Gouveia
Dadurch kann das Sprite so verzerrt werden, wie es mit dem Skalierungsparameter nicht möglich wäre, wie in diesem Beispiel .
David Gouveia
1
David, das würde es tun. Ich werde nach Vertex-Shadern suchen (habe sie noch nicht verwendet). Ich arbeite an einer Visualisierung. Der erste Entwurf ... es könnte die schlimmste MS-Farbkreation sein, die jemals vom Menschen getragen wurde. Vielleicht kann ich meine Freundin dazu bringen, etwas zu zeichnen.
Alic44
Ich werde dann das kleine Code-Snippet veröffentlichen, das ich gerade für diesen Screenshot geschrieben habe, damit Sie es versuchen können. Obwohl ich nicht sicher bin, ob ich etwas falsch mache, scheint es zu funktionieren.
David Gouveia

Antworten:

5

Dies kann in zwei einfachen Schritten erfolgen:

  • Übergeben Sie Ihre benutzerdefinierte Transformation an SpriteBatch.Beginaber ...
  • Bringen Sie Matrix.CreateScale(1,1,0)am Ende ein an, um das Quad zu glätten und sicherzustellen, dass es vollständig sichtbar ist.

Beachten Sie jedoch, dass die Transformationsmatrix relativ zum Weltursprung und nicht zum Ursprung des Sprites ist. Daher müssen möglicherweise einige Anpassungen vorgenommen werden, um das Ergebnis an die richtige Position zu bringen.

Matrix matrix = Matrix.CreateRotationX(MathHelper.ToRadians(60)) * 
                Matrix.CreateRotationY(MathHelper.ToRadians(30)) * 
                Matrix.CreateScale(1,1,0);

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, matrix);

Geben Sie hier die Bildbeschreibung ein

Ich habe die alte Antwort hierher verschoben .

PS: Danke an Andrew Russel, der mich zum Nachdenken gebracht hat .

David Gouveia
quelle
David, das ist sehr cool. Ich bin nicht sicher, ob ich es zum
Laufen
Genau so, wie ich es möchte, weil ich mit Spritebatch keinen neuen Stapel starten und trotzdem Texturen sortieren kann, die nach dem Parameter layerdepth gezeichnet werden sollen. Aber ich werde wahrscheinlich irgendwann selbst auf die Bestellung von Draw Calls umsteigen, und deshalb werde ich das jetzt versuchen, da es nach einer wirklich guten Lösung aussieht.
Alic44
Sollten Sie dies nicht mit dem integrierten SpriteBatchShader tun können, an den eine benutzerdefinierte Transformationsmatrix übergeben wurde Begin?
Andrew Russell
@ AndrewRussell Du hast recht, es ist mit einem Trick möglich. Ich habe es anfangs versucht, aber es hat nicht funktioniert, da das gedrehte Quad durch die standardmäßige Nah-Fern-Ebenen-Kombination von 0 zu 1 abgeschnitten wird. Meine erste Lösung beinhaltete einen Vertex-Shader zum Drehen, ohne das Z zu berühren. Meine zweite Lösung bestand darin, die Projektionsmatrix zu ändern eine größere Tiefe haben. Aber ich habe gerade einen Weg gefunden, wie es mit der regulären Matrix funktioniert: Fügen Sie eine Skalierungsmatrix hinzu, die die Z-Koordinate nach der Drehung abflacht .
David Gouveia
Hey, tut mir leid, ich habe eine Weile gebraucht, um zu akzeptieren! Dies ist eine großartige Antwort, und ich habe gerade meinen Code umstrukturiert, um meine Zeichnung so weit zu trennen, dass ich spriteBatch.Begin für einzelne Objekte aufrufen und trotzdem eine Tiefensortierung (dumme Ebenentiefe) durchführen kann. Dieser Prozess hat tatsächlich auch zu einigen wirklich großen unvorhergesehenen Gewinnen geführt, was immer schön ist. Vielen Dank für die Zeit, die Sie damit verbracht haben, Ihre Antwort zu erstellen und zu überarbeiten.
Alic44