Comment créer un pixel shader «rétro» pour les sprites 2D transformés qui maintient la fidélité des pixels?

10

L'image ci-dessous montre deux sprites rendus avec un échantillonnage de points au-dessus d'un arrière-plan:

entrez la description de l'image ici

  • Le crâne gauche n'a aucune rotation / mise à l'échelle qui lui est appliquée, donc chaque pixel correspond parfaitement à l'arrière-plan.
  • Le crâne droit est pivoté / mis à l'échelle, ce qui entraîne des pixels plus grands qui ne sont plus alignés sur l'axe .

Comment pourrais-je développer un pixel shader qui rendrait le sprite transformé à droite avec des pixels alignés sur les axes de la même taille que le reste de la scène?

Cela pourrait être lié à la façon dont la mise à l'échelle des sprites a été mise en œuvre dans les anciens jeux tels que Monkey Island, car c'est l'effet que j'essaie d'obtenir, mais avec une rotation ajoutée.


Éditer

Conformément aux suggestions de kaoD, j'ai essayé de résoudre le problème en tant que post-processus. L'approche la plus simple consistait à effectuer d'abord le rendu sur une cible de rendu distincte (sous-échantillonnée pour correspondre à la taille de pixel souhaitée), puis à la mettre à l'échelle lors du deuxième rendu. Il a répondu à mes exigences ci-dessus.

J'ai d'abord essayé de le faire Linear -> Pointet le résultat était le suivant:

entrez la description de l'image ici

Il n'y a pas de distorsion mais le résultat semble flou et il perd la plupart des couleurs de reflets. À mon avis, cela brise le look rétro dont j'avais besoin.

La deuxième fois que j'ai essayé Point -> Pointet le résultat était le suivant:

entrez la description de l'image ici

Malgré la distorsion, je pense que cela pourrait être assez bon pour mes besoins, même si cela semble mieux en tant qu'image fixe qu'en mouvement.

Pour le démontrer, voici une vidéo de l'effet, bien que YouTube en ait filtré les pixels:

http://youtu.be/hqokk58KFmI

Cependant, je laisse la question ouverte pendant quelques jours de plus au cas où quelqu'un trouverait une meilleure solution d'échantillonnage qui maintiendrait l'aspect net tout en diminuant la quantité de distorsion lors du déplacement.

David Gouveia
la source
C'est censé être un crâne ...?
DeadMG
@DeadMG Un crâne de bœuf, je suppose?
David Gouveia
Bel effet, plus beau que je ne le pensais (je l'ai essayé sur EXTREMELY low res and palette, 40x30 EGA.) C'est à peu près le look que vous obtiendrez en créant votre propre shader postfx. BTW, je doute qu'il existe une meilleure solution d'échantillonnage qui conserve l'effet comme vous le souhaitez. NN est à peu près ce qui donne ce look net, tout autre échantillonnage rendra l'image finale floue (
devinez quand même
@kaoD Mais n'oubliez pas que j'applique deux passes. Le deuxième passage qui suréchantillonne l'image sera toujours le plus proche voisin pour préserver la sensation rétro. Mais je pense qu'il pourrait être avantageux d'essayer différentes techniques d'échantillonnage pour la première passe. J'examine actuellement Scale2x!
David Gouveia
@kaoD Nah, j'abandonne. Changer les paramètres du shader entre chaque appel de sprite avec SpriteBatchme oblige à utiliser le mode immédiat, donc ça ne vaut pas la peine. J'irai avec ça :)
David Gouveia

Réponses:

3

Vous devez appliquer votre shader APRÈS que votre sprite a été tourné.

Si la scène entière n'a pas encore été ombrée et que vos sprites sont réellement pixélisés, ce dont vous avez besoin est une sorte de filtre post-FX pour toute votre scène. La moyenne des régions de pixels fonctionnera correctement. Ce n'est pas exactement ce que vous avez l'intention (cela semblera un peu tordu lors du déplacement / rotation), mais cela pourrait faire l'affaire.

La seule façon de garder ce look rétro fidèle à ce que vous voulez est de dessiner vous-même vos rotations de sprites. Cela n'a rien à voir avec la façon dont la mise à l'échelle a été mise en œuvre: la résolution était en fait médiocre, en parlant de cela, avez-vous essayé avec des résolutions extrêmement basses? Cela pourrait aussi faire l'affaire et sembler plus naturel car, bien, c'est en fait ce qui a causé l'effet que vous recherchez. Et c'est pas cher! Vraiment pas cher! En fait, ce sera moins cher que ce que vous avez déjà (moins d'exécutions de shaders de fragments.)

L'effet est ruiné dans votre exemple d'image car votre résolution est élevée par rapport à vos sprites, ce qui vous permet de voir les vrais pixels de la scène.

kaoD
la source
Oui, je n'utilise pas encore de shaders. Ce sont juste des sprites réguliers avec des textures à très basse résolution, rendus avec la valeur SpriteBatchpar défaut de XNA avec l'échantillonnage de points activé. Mais un post-fx pourrait vraiment fonctionner. Pour commencer, j'essaierai d'effectuer un rendu avec échantillonnage linéaire sur une cible de rendu, puis de rendre l'intégralité de la cible de rendu sur le backbuffer avec un échantillonnage ponctuel.
David Gouveia
@DavidGouveia ne manquez pas l'occasion de sous-estimer votre résolution. Si vous voulez vraiment obtenir l'effet d'origine, c'est votre meilleure photo. Si vous avez besoin de votre haute résolution (si une partie de votre GFX est haute résolution ou si vous souhaitez correspondre à des résolutions natives), vous pouvez toujours effectuer un rendu sur un tampon hors écran basse résolution, puis le peindre dans votre tampon d'image haute résolution en tant que plein -écran quad avec filtrage désactivé. Gardez à l'esprit que vous devez faire correspondre les proportions pour éviter les pixels rectangulaires, bien sûr.
kaoD
Vérifiez mon montage :) Je pense que cela a résolu la plupart du problème, même si je suis toujours curieux de savoir s'il existe une meilleure solution d'échantillonnage que le voisin le plus proche pour ce problème. Je vais laisser la question tourner encore un peu.
David Gouveia