Sprites rendus flous avec vitesse

9

Après avoir ajouté de la vélocité à mon jeu, j'ai l'impression que mes textures se contractent. Je pensais que ce n'était que mes yeux, jusqu'à ce que je le capture enfin sur une capture d'écran:

entrez la description de l'image ici

Celui de gauche est ce qui rend dans mon jeu; celui de droite est le sprite d'origine, collé dessus. (Il s'agit d'une capture d'écran de Photoshop, agrandie 6x.)

Notez que les bords sont des alias - cela ressemble presque à un rendu sous-pixel. En fait, si je n'avais pas forcé mes sprites (qui ont la position et la vitesse en pouces) à dessiner en utilisant des valeurs entières, je jurerais que MonoGame dessine avec des valeurs à virgule flottante. Mais ce n'est pas le cas.

Quelle pourrait être la cause de ces choses floues? Cela ne se produit pas sans la vitesse appliquée.

Pour être précis, ma SpriteComponentclasse a un Vector2 Positiondomaine. Lorsque j'appelle Draw, j'utilise essentiellement new Vector2((int)Math.Round(this.Position.X), (int)Math.Round(this.Position.Y))le poste.

J'ai eu un bug avant où même les objets stationnaires tremblaient - c'était dû à moi en utilisant le Positionvecteur droit et sans arrondir les valeurs à ints. Si j'utilise Floor/ Ceilingau lieu de rond, le sprite coule / plane (une différence de pixel dans les deux sens) mais reste toujours flou.

cendres999
la source
1
Cela pourrait-il être lié au filtrage de texture appliqué?
OriginalDaemon
Avez-vous le code de votre shader? Certaines personnes ajoutent un demi-pixel sur les deux axes pour centrer les pixels. Pas sûr cependant, je pense que c'est une seule chose DirectX.
William Mariager
3
La désactivation du filtrage est une solution de contournement et non une solution.
Archy
1
Le rendu ne sait rien de votre vitesse, donc soit la position, la taille ou tout autre chose que vous passez à SpriteBatch.Draw est différent ou l'erreur était présente avant d'ajouter la vitesse. Comment appelez-vous SpriteBatch.Draw exactement?
Archy
1
@ ashes999 avez-vous débogué cet appel et vérifié this.X, this.Y et this.origin? À quoi est ce fichier this.origin? Il n'y a fondamentalement aucun moyen que le résultat du rendu soit différent lorsque cet appel Draw est le même.
Archy

Réponses:

3

Hum, ceci est embarrassant.

Il s'avère que je ne dessinais pas en utilisant des positions entières, mais des positions flottantes. Archy m'a indiqué le bon chemin avec son commentaire@ashes999 did you debug this call and checked this.X, this.Y and this.origin?

Dès que j'ai ajouté une déclaration de trace, j'ai remarqué que rien n'était tracé. Il s'avère que ma SpriteComponentclasse utilisait correctement les valeurs entières, mais mes SpriteSheetComponentvaleurs flottantes toujours utilisées à partir du brut Vector2 Position.

Bien que je n'ai pas essayé le filtrage et le serrage de texture, je soupçonnais que ce n'était pas le bon changement, car je dessinais une image 2D à la même largeur et hauteur que l'image source (pas de mise à l'échelle).

cendres999
la source
1
Terminé, content de l'avoir trouvé!
Archy
2

XNA utilise DirectX9 qui utilise le centre du pixel comme emplacement. Cela est visible lors de l'utilisation des surcharges basées sur Vector2 de la classe draw. Je pense que la soustraction (0,5, 0,5) devrait résoudre votre problème.

Plus d'infos ici.

ClassicThunder
la source
Je ne peux pas faire cela techniquement, car je passe un Vector2 avec int, intcomme arguments. En plus de cela, les choses semblent parfaitement bien quand je n'ai aucun objet en mouvement.
ashes999
Que voulez-vous dire par l'objet en mouvement? XNA n'a aucune notion de mouvement, il dessine des choses là où vous le dites aussi. C'est une série de clichés fixes. Essayez également d'utiliser les surcharges Rectangle car vous arrondissez de toute façon à un rectangle.
ClassicThunder
J'ai ma propre implémentation de la vitesse. SpriteComponenta une Vector2position, qui augmente en tant que flotteurs en fonction de la vitesse; quand je dessine, je crée un nouveau Vector2avec des versions entières (arrondies) de mes positionX et Y. Ce n'est pas le problème, car les objets stationnaires sans vitesse semblent bien.
ashes999
Donc, vous dites que vous avez un vecteur de position p et un vecteur de vitesse v, ajoutez-les tels que p + = v, puis créez une copie de p en utilisant des valeurs arrondies. Et que ce yeild différentes valeurs ayant alors une position qui est la même que la précédente p + = v malgré les appels de tirage étant identiques? Parce que cela n'a aucun sens.
ClassicThunder
Oui, c'est aussi ce que dit @Archy. Permettez-moi de déboguer et de vérifier à nouveau. J'ajoute p += vpendant Updateet rend avec new Vector2((int)Math.Round(p.X), (int)Math.Round(p.Y))).
ashes999
2

Le rendu ne sait rien de votre vitesse, donc soit la position, la taille ou tout autre chose que vous passez à SpriteBatch.Draw est différent ou l'erreur était présente avant d'ajouter la vitesse. Comment appelez-vous SpriteBatch.Draw exactement?

Avez-vous débogué cet appel et vérifié this.X, this.Y et this.origin? À quoi est ce fichier this.origin? Il n'y a fondamentalement aucun moyen que le résultat du rendu avec la vélocité soit différent lorsque cet appel Draw est le même.

Archy
la source
1

Le problème est probablement que le filtrage de texture est activé. Si vous n'êtes pas sûr de ce que cela signifie, envisagez une situation où vous avez une image de 2 pixels de large: le premier pixel est noir, le second pixel est blanc. Si vous zoomez sur cette texture, si le filtrage de texture est activé, vous verrez qu'elle devient floue et que la zone entre le pixel noir et blanc utilise une couleur gris dégradé.

Un exemple classique de jeux avec et sans filtrage est Super Mario 64 qui avait un filtrage alors que Doom n'en avait pas.

Lorsque vous n'utilisez pas la vélocité, votre Sprite est probablement positionné de sorte que le centre de la texture se trouve au point d'échantillonnage où XNA (ou toute autre API sous-jacente utilisée) saisit la couleur. Lorsque vous vous déplacez avec une vitesse flottante, la position de votre Sprite change, donc le point d'échantillonnage peut ne pas s'aligner directement avec le centre d'un pixel, donc le résultat final est qu'une couleur qui est une moyenne des pixels les plus proches est utilisé pour le rendu.

Vous pouvez vérifier que le filtrage est activé en rendant simplement votre Sprite vraiment grand à l'écran. Si c'est flou, c'est bien le problème.

Si vous devez avoir une précision au pixel près dans le rendu, vous voudrez avoir une valeur flottante pour la position stockée quelque part, mais utilisez des valeurs entières pour la position de l'objet que vous rendez ... ou bien sûr, vous pouvez simplement désactiver le filtrage si votre jeu n'en a pas besoin.

Vous pouvez également lire ceci .

Victor Chelaru
la source
Comme je l'ai mentionné dans ma question, j'utilise déjà des entiers pour mon emplacement et la taille de l'image d'origine lorsque j'appelle Draw. Je ne sais donc pas comment cela pourrait être le cas - mais je vais essayer de rendre à grande échelle et de voir si la désactivation du filtrage de texture aidera.
ashes999
1

Essayez de définir votre SamplerState sur SamplerState.PointClamp dans l'appel SpriteBatch.Begin.

jeux d'artisanat
la source