Sprite che rendono sfocate con la velocità


9

Dopo aver aggiunto velocità al mio gioco, mi sento come se le mie trame si contorcessero. Pensavo fossero solo i miei occhi, fino a quando non l'ho finalmente catturato in uno screenshot:

inserisci qui la descrizione dell'immagine

Quello a sinistra è ciò che rende nel mio gioco; quello a destra è lo sprite originale, incollato sopra. (Questo è uno screenshot di Photoshop, ingrandito 6x.)

Si noti che i bordi sono aliasing: sembra quasi un rendering sub-pixel. In effetti, se non avessi costretto i miei sprite (che hanno posizione e velocità come ints) a disegnare usando valori interi, giurerei che MonoGame sta disegnando con valori in virgola mobile. Ma non lo è.

Quale potrebbe essere la causa di queste cose che appaiono sfocate? Non succede senza la velocità applicata.

Per essere precisi, la mia SpriteComponentclasse ha un Vector2 Positioncampo. Quando chiamo Draw, essenzialmente uso new Vector2((int)Math.Round(this.Position.X), (int)Math.Round(this.Position.Y))per la posizione.

Prima avevo un bug in cui anche gli oggetti fissi si muovevano, ciò era dovuto al fatto che usavo il Positionvettore dritto e non arrotondavo i valori ints. Se uso Floor/ Ceilinginvece di arrotondare, lo sprite affonda / sorvola (una differenza di pixel in entrambi i modi) ma disegna comunque sfocato.


1
Questo potrebbe essere correlato al filtro texture applicato?
OriginalDaemon l'

Hai il codice per il tuo shader? Alcune persone aggiungono mezzo pixel su entrambi gli assi per centrare i pixel. Non sono sicuro, penso che sia l'unica cosa di DirectX.
William Mariager,

3
La disattivazione del filtro è una soluzione alternativa, non una soluzione.
Archy,

1
Il rendering non conosce nulla della tua velocità, quindi la posizione, la dimensione o qualsiasi altra cosa passi a SpriteBatch. Il disegno è diverso o l'errore era presente prima che tu aggiungessi la velocità. Come si chiama esattamente SpriteBatch.Draw?
Archy,

1
@ ashes999 hai eseguito il debug di questa chiamata e verificato this.X, this.Y e this.origin? Su cosa è impostato this.origin? Fondamentalmente non è possibile che il risultato di rendering sia diverso quando questa chiamata Draw è la stessa.
Archy,

Risposte:


3

Beh, questo è imbarazzante.

Si scopre che non stavo disegnando usando posizioni intere, ma posizioni fluttuanti. Archy mi ha indicato la strada giusta con il suo commento@ashes999 did you debug this call and checked this.X, this.Y and this.origin?

Non appena ho aggiunto un'istruzione trace, ho notato che non è stato tracciato nulla. Si scopre che la mia SpriteComponentclasse ha usato correttamente i valori interi, ma i miei SpriteSheetComponentvalori float sono ancora utilizzati dal raw Vector2 Position.

Sebbene non abbia provato a filtrare e bloccare le texture, ero sospettoso che non si trattasse della modifica corretta, poiché stavo disegnando un'immagine 2D con la stessa larghezza e altezza dell'immagine sorgente (senza ridimensionamento).


1
Fatto, felice di averlo trovato!
Archy,

2

XNA utilizza DirectX9 che utilizza il centro del pixel come posizione. Ciò si nota quando si utilizzano i sovraccarichi basati su Vector2 della classe di disegno. Credo che la sottrazione (.5, .5) dovrebbe risolvere il tuo problema.

Maggiori informazioni qui.


Tecnicamente non posso farlo, perché sto passando un Vector2 con int, intcome argomenti. Inoltre, le cose sembrano perfettamente a posto quando non ho oggetti in movimento.
ashes999,

Cosa intendi per oggetto in movimento? XNA non ha alcuna nozione di movimento, disegna cose dove lo dici anche tu. È una serie di istantanee fisse. Prova anche a utilizzare gli overload di Rectangle poiché stai comunque arrotondando un rettangolo.
ClassicThunder

Ho la mia implementazione della velocità. SpriteComponentha una Vector2posizione, che si incrementa come galleggia a seconda della velocità; quando disegno, ne creo una nuova Vector2con versioni intere (arrotondate) delle mie positionX e Y. Questo non è il problema, poiché gli oggetti stazionari senza velocità appaiono benissimo.
ashes999,

Quindi stai dicendo che hai un vettore di posizione p e un vettore di velocità v, aggiungili come p + = v, quindi crea una copia di p usando valori arrotondati. E che questo abbia valori diversi quindi avendo una posizione uguale alla precedente p + = v nonostante le chiamate di disegno siano identiche? Perché non ha senso.
ClassicThunder,

Sì, è quello che dice anche @Archy. Vorrei eseguire il debug e ricontrollare. Aggiungo p += vdurante Updatee eseguo il rendering con new Vector2((int)Math.Round(p.X), (int)Math.Round(p.Y))).
ashes999,

2

Il rendering non sa nulla della tua velocità, quindi la posizione, la dimensione o qualsiasi altra cosa passi a SpriteBatch. Il disegno è diverso o l'errore era presente prima che tu aggiungessi la velocità. Come si chiama esattamente SpriteBatch.Draw?

Hai eseguito il debug di questa chiamata e verificato this.X, this.Y e this.origin? Su cosa è impostato this.origin? Fondamentalmente non è possibile che il risultato di rendering con la velocità sia diverso quando questa chiamata a Draw è la stessa.


1

È probabile che il filtro trama sia attivato. Se non sei sicuro di cosa significhi, considera una situazione in cui un'immagine ha una larghezza di 2 pixel: il primo pixel è nero, il secondo pixel è bianco. Se ingrandisci questa trama, se il filtro trama è attivo, vedrai che diventa sfocato e che l'area tra il pixel bianco e nero utilizza un colore grigio sfumato.

Un classico esempio di giochi con e senza filtro sono Super Mario 64 che aveva un filtro mentre Doom no.

Quando non usi la velocità, è probabile che il tuo Sprite sia posizionato in modo tale che il centro della trama si trovi nel punto di campionamento in cui XNA (o qualsiasi altra API sottostante venga utilizzata) sta afferrando il colore. Quando ti sposti con una velocità variabile, la posizione dello Sprite cambia, quindi il punto di campionamento potrebbe non allinearsi direttamente con il centro di un pixel, quindi il risultato finale è che un colore che è una media dei pixel più vicini viene usato per il rendering.

Puoi verificare che il filtro sia attivato semplicemente rendendo lo Sprite davvero grande sullo schermo. Se è sfocato, allora questo è il problema.

Se devi avere un'accuratezza perfetta dei pixel nel rendering, vorrai avere un valore float per la posizione memorizzata da qualche parte, ma usare valori interi per la posizione dell'oggetto che stai visualizzando ... o ovviamente potresti semplicemente disattivare il filtro se il tuo gioco non ne ha bisogno.

Potresti anche voler leggere questo .


Come ho detto nella mia domanda, sto già usando numeri interi per la mia posizione e la dimensione dell'immagine originale, quando chiamo Draw. Quindi non sono sicuro di come potrebbe essere il caso, ma proverò a eseguire il rendering su larga scala e vedrò se disattivare il filtro delle trame sarà di aiuto.
ashes999,

1

Prova a impostare SamplerState su SamplerState.PointClamp nella chiamata SpriteBatch.Begin.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.