Sprites machen mit der Geschwindigkeit verschwommen

9

Nachdem ich meinem Spiel Geschwindigkeit hinzugefügt habe, habe ich das Gefühl, dass meine Texturen zucken. Ich dachte, es wären nur meine Augen, bis ich es schließlich in einem Screenshot festhielt:

Geben Sie hier die Bildbeschreibung ein

Der linke ist das, was in meinem Spiel gerendert wird. Das rechte ist das ursprüngliche Sprite, das eingefügt wurde. (Dies ist ein Screenshot aus Photoshop, 6-fach vergrößert.)

Beachten Sie, dass die Kanten Aliasing sind - es sieht fast wie Subpixel-Rendering aus. Wenn ich meine Sprites (die Position und Geschwindigkeit als Ints haben) nicht gezwungen hätte, mit ganzzahligen Werten zu zeichnen, würde ich schwören, dass MonoGame mit Gleitkommawerten zeichnet. Aber es ist nicht so.

Was könnte die Ursache dafür sein, dass diese Dinge verschwommen erscheinen? Es passiert nicht ohne angewendete Geschwindigkeit.

Um genau zu sein, meine SpriteComponentKlasse hat ein Vector2 PositionFeld. Wenn ich anrufe Draw, benutze ich im Wesentlichen new Vector2((int)Math.Round(this.Position.X), (int)Math.Round(this.Position.Y))für die Position.

Ich hatte vorher einen Fehler, bei dem sogar stationäre Objekte zitterten - das lag daran, dass ich den geraden PositionVektor verwendete und die Werte nicht auf rundete ints. Wenn ich Floor/ Ceilinganstelle von rund verwende, sinkt / schwebt das Sprite (ein Pixel Unterschied in beide Richtungen), zeichnet aber immer noch verschwommen.

Asche999
quelle
1
Könnte dies mit der angewendeten Texturfilterung zusammenhängen?
OriginalDaemon
Hast du den Code für deinen Shader? Einige Leute fügen ein halbes Pixel auf beiden Achsen hinzu, um die Pixel zu zentrieren. Ich bin mir nicht sicher, aber ich denke, das ist nur eine DirectX-Sache.
William Mariager
3
Das Deaktivieren der Filterung ist eine Problemumgehung und keine Lösung.
Archy
1
Das Rendern weiß nichts über Ihre Geschwindigkeit, daher ist entweder die Position, Größe oder etwas anderes, das Sie an SpriteBatch weitergeben, anders oder der Fehler war vorhanden, bevor Sie die Geschwindigkeit hinzugefügt haben. Wie nennt man SpriteBatch.Draw genau?
Archy
1
@ ashes999 hast du diesen Aufruf debuggt und this.X, this.Y und this.origin überprüft? Was ist this.origin eingestellt? Grundsätzlich gibt es keine Möglichkeit, dass das Renderergebnis anders ist, wenn dieser Draw-Aufruf identisch ist.
Archy

Antworten:

3

Nun, das ist peinlich.

Es stellt sich heraus, dass ich nicht mit ganzzahligen Positionen, sondern mit Gleitkommazahlen gezeichnet habe. Archy zeigte mir mit seinem Kommentar den richtigen Weg@ashes999 did you debug this call and checked this.X, this.Y and this.origin?

Sobald ich eine Trace-Anweisung hinzufügte, bemerkte ich, dass nichts zurückverfolgt wurde. Es stellt sich heraus, dass meine SpriteComponentKlasse korrekt ganzzahlige Werte verwendet hat, aber meine SpriteSheetComponentnoch verwendeten Gleitkommawerte aus dem Rohwert Vector2 Position.

Obwohl ich nicht versucht habe, Texturen zu filtern und zu klemmen, war ich misstrauisch, dass dies nicht die richtige Änderung war, da ich ein 2D-Bild mit der gleichen Breite und Höhe wie das Quellbild gezeichnet habe (keine Skalierung).

Asche999
quelle
1
Fertig, ich bin froh, dass du es gefunden hast!
Archy
2

XNA verwendet DirectX9, das die Mitte des Pixels als Position verwendet. Dies macht sich bei Verwendung der Vector2-basierten Überladungen der Draw-Klasse bemerkbar. Ich glaube, dass das Subtrahieren (.5, .5) Ihr Problem beheben sollte.

Mehr Infos hier.

ClassicThunder
quelle
Ich kann dies technisch nicht tun, da ich einen Vector2 mit int, intden Argumenten übergebe. Außerdem sieht es ganz gut aus, wenn ich keine Objekte in Bewegung habe.
Asche999
Was meinst du mit dem Objekt in Bewegung? XNA hat keine Vorstellung von Bewegung, es zeichnet Dinge, wo Sie es auch sagen. Es ist eine Reihe von stationären Schnappschüssen. Versuchen Sie auch, die Rechtecküberladungen zu verwenden, da Sie sowieso auf ein Rechteck runden.
ClassicThunder
Ich habe meine eigene Implementierung von Geschwindigkeit. SpriteComponenthat eine Vector2Position, die sich je nach Geschwindigkeit als Float erhöht; Wenn ich zeichne, erstelle ich eine neue Vector2mit ganzzahligen (gerundeten) Versionen meines positionX und Y. Dies ist nicht das Problem, da stationäre Objekte ohne Geschwindigkeit in Ordnung erscheinen.
Asche999
Wenn Sie also sagen, dass Sie einen Positionsvektor p und einen Geschwindigkeitsvektor v haben, fügen Sie diese wie p + = v hinzu und erstellen Sie dann eine Kopie von p mit gerundeten Werten. Und dass dies unterschiedliche Werte ergibt, die dann eine Position haben, die mit der vorherigen p + = v identisch ist, obwohl die Draw-Aufrufe identisch sind? Weil das keinen Sinn macht.
ClassicThunder
Ja, das sagt auch @Archy. Lassen Sie mich debuggen und erneut überprüfen. Ich füge p += vwährend hinzu Updateund rendere mit new Vector2((int)Math.Round(p.X), (int)Math.Round(p.Y))).
Asche999
2

Das Rendern weiß nichts über Ihre Geschwindigkeit, daher ist entweder die Position, Größe oder irgendetwas anderes, das Sie an SpriteBatch weitergeben. Draw ist anders oder der Fehler war vorhanden, bevor Sie die Geschwindigkeit hinzugefügt haben. Wie nennt man SpriteBatch.Draw genau?

Haben Sie diesen Aufruf debuggt und this.X, this.Y und this.origin überprüft? Was ist this.origin eingestellt? Grundsätzlich ist das Renderergebnis mit der Geschwindigkeit nicht unterschiedlich, wenn dieser Draw-Aufruf identisch ist.

Archy
quelle
1

Das Problem ist wahrscheinlich, dass die Texturfilterung aktiviert ist. Wenn Sie sich nicht sicher sind, was dies bedeutet, stellen Sie sich eine Situation vor, in der Sie ein Bild mit einer Breite von 2 Pixel haben: Das erste Pixel ist schwarz, das zweite Pixel ist weiß. Wenn Sie diese Textur vergrößern und die Texturfilterung aktivieren, werden Sie feststellen, dass sie unscharf wird und der Bereich zwischen dem schwarzen und dem weißen Pixel eine graue Farbverlaufsfarbe verwendet.

Ein klassisches Beispiel für Spiele mit und ohne Filterung ist Super Mario 64, das gefiltert wurde, Doom jedoch nicht.

Wenn Sie keine Geschwindigkeit verwenden, ist Ihr Sprite wahrscheinlich so positioniert, dass sich die Mitte der Textur an dem Abtastpunkt befindet, an dem XNA (oder die zugrunde liegende API) die Farbe erfasst. Wenn Sie sich mit einer Gleitgeschwindigkeit bewegen, ändert sich die Position Ihres Sprite, sodass der Abtastpunkt möglicherweise nicht direkt mit der Mitte eines Pixels ausgerichtet ist. Das Endergebnis ist also, dass eine Farbe vorliegt, die ein Durchschnitt der nächsten Pixel ist verwendet, um zu rendern.

Sie können überprüfen, ob die Filterung aktiviert ist, indem Sie Ihr Sprite einfach auf dem Bildschirm sehr groß machen. Wenn es verschwommen ist, dann ist das das Problem.

Wenn Sie beim Rendern eine pixelgenaue Genauigkeit benötigen, möchten Sie einen Gleitkommawert für die Position irgendwo speichern, aber ganzzahlige Werte für die Position des Objekts verwenden, das Sie rendern ... oder Sie können natürlich einfach die Filterung deaktivieren wenn dein Spiel es nicht braucht.

Sie können auch lesen wollen dies .

Victor Chelaru
quelle
Wie ich in meiner Frage erwähnt habe, verwende ich beim Aufruf bereits Ganzzahlen für meinen Standort und die ursprüngliche Bildgröße Draw. Ich bin mir also nicht sicher, wie das der Fall sein könnte - aber ich werde versuchen, in großem Maßstab zu rendern und zu prüfen, ob das Deaktivieren der Texturfilterung hilfreich ist.
Asche999
1

Versuchen Sie, Ihren SamplerState im SpriteBatch.Begin-Aufruf auf SamplerState.PointClamp zu setzen.

Handwerksspiele
quelle