Effet Flash XNA Sprite

8

Je cherche un moyen de rendre chaque pixel non transparent dans un blanc solide de sprite (pour «flasher» le blanc de sprite lorsque le joueur subit des dégâts, etc.). C'est sur Windows Phone 7.

J'utilisais un shader personnalisé très simple pour le faire sous XNA 3.1, mais WP7 ne les prend pas en charge et il est difficile de trouver une alternative.

J'apprécierais toute aide ou suggestion. Je préfère ne pas avoir à créer manuellement une copie blanche solide de chaque image-objet de mon jeu.

Ryan McD
la source
1
D'accord, j'ai trouvé un moyen, mais ce n'est pas joli. Permettez-moi de nettoyer un peu et je mettrai à jour ma réponse.
David Gouveia

Réponses:

9

Méthode 1

Vous n'avez pas à créer manuellement une version blanche solide de chaque image-objet de votre jeu - vous pourriez tout aussi bien automatiser le processus au moment du chargement. En d'autres termes, vous pouvez utiliser Texture2D.GetData()pour accéder aux pixels de votre texture (et les récupérer de manière simple Color[]), les parcourir en remplaçant tout pixel non transparent par du blanc uni, puis l'enregistrer dans une nouvelle texture à l'aide de et Texture2D.SetData().

Méthode 2

J'ai essayé de jouer avec, BlendStatemais je n'ai pas trouvé de moyen de le rendre tout blanc, du moins pas dans les limites du profil Reach. Mais si quelqu'un connaît un moyen, faites-le moi savoir. Ce que j'ai trouvé, cependant, était un moyen de le faire en utilisant le tampon de gabarit et la AlphaTestEffectclasse intégrée . L'idée est la suivante:

  1. Créez un backbuffer doté d'un tampon de gabarit.
  2. Videz le tampon du pochoir à zéro.
  3. Dessinez les sprites que vous souhaitez colorer en blanc et chaque fois qu'ils passent le test alpha, définissez le tampon de pochoir à cet endroit sur 1.
  4. Dessinez un quadrilatère blanc couvrant la totalité de l'écran, mais uniquement là où la valeur du tampon de gabarit est 1.

Voici le code que j'ai utilisé:

(Étape 1) Assurez-vous d'abord que le backbuffer est créé avec de la place pour un tampon de pochoir:

graphics = new GraphicsDeviceManager(this) { PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 };

(Étape 2) Créez une texture blanche 1x1 qui sera mise à l'échelle pour remplir tout l'écran:

private Texture2D pixel;
pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new[] { Color.White });

(Étape 3) Et maintenant la partie difficile - le rendre. Eh bien, pas vraiment difficile, mais nécessite deux DepthStencilStateobjets et un AlphaTestEffectobjet. Vous ne devez les créer qu'une seule fois.

// Clear stencil buffer
GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0f, 0);

// Prepare the alpha test effect object (create it only once on initilization)
AlphaTestEffect alphaTestEffect = new AlphaTestEffect(GraphicsDevice)
{
    DiffuseColor = Color.White.ToVector3(), 
    AlphaFunction = CompareFunction.Greater, 
    ReferenceAlpha = 0, World = Matrix.Identity, 
    View = Matrix.Identity, 
    Projection = Matrix.CreateTranslation(-0.5f, -0.5f, 0) * 
    Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1)
};

// Prepare the first DepthStencilState (create only once, or put it in a static class)
DepthStencilState beforeDepthStencilState = new DepthStencilState
{
    StencilEnable = true, 
    StencilFunction = CompareFunction.Always,
    StencilPass = StencilOperation.Replace, 
    ReferenceStencil = 1
};

// Draw your sprites using the structures above
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, beforeDepthStencilState, null, alphaTestEffect);
spriteBatch.Draw(sprite, new Vector2(300, 150), Color.White);
spriteBatch.End();

// Prepare the second DepthStencilState (create only once, or put it in a static class)
DepthStencilState afterDepthStencilState = new DepthStencilState
{
    StencilEnable = true, 
    StencilFunction = CompareFunction.Equal, 
    ReferenceStencil = 1
};

// Draw a full screen white quad with the structure above
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, afterDepthStencilState, null);
spriteBatch.Draw(pixel, GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();

Et le résultat:

entrez la description de l'image ici

David Gouveia
la source
Incroyable! Merci beaucoup d'avoir consacré autant d'efforts à cela, David. Dommage qu'il n'y ait pas de solution plus simple, mais cela devrait bien faire l'affaire.
Ryan McD