Efeito Flash de Sprite XNA


8

Estou procurando uma maneira de renderizar todos os pixels não transparentes em um sprite em branco sólido (para "piscar" o sprite em branco quando o jogador sofrer danos, etc.). Este é no Windows Phone 7.

Eu estava usando um sombreador personalizado muito simples para fazer isso no XNA 3.1, mas o WP7 não oferece suporte a eles e é difícil encontrar uma alternativa.

Agradeço qualquer ajuda ou sugestão. Eu prefiro não ter que criar manualmente uma cópia branca sólida de cada sprite no meu jogo.


11
Ok, eu encontrei um caminho, mas não é bonito. Deixe-me limpar um pouco e atualizarei minha resposta.
David Gouveia

Respostas:


9

Método 1

Você não precisa criar uma versão branca sólida de todos os sprites do seu jogo manualmente - você também pode automatizar o processo no tempo de carregamento. Em outras palavras, você pode usar Texture2D.GetData()para acessar os pixels de sua textura (e recuperá-los como simples Color[]), iterar sobre eles substituindo qualquer pixel não transparente por branco sólido e salvá-lo em uma nova textura usando e Texture2D.SetData().

Método 2

Tentei brincar, BlendStatemas não consegui encontrar uma maneira de tornar tudo branco, pelo menos não dentro das limitações do perfil Reach. Mas se alguém souber uma maneira, me avise. O que encontrei, no entanto, foi uma maneira de fazer isso usando o buffer de estêncil e a AlphaTestEffectclasse interna. A ideia é a seguinte:

  1. Crie um backbuffer que tenha um buffer de estêncil.
  2. Limpe o buffer de estêncil para zero.
  3. Desenhe os sprites que você deseja pintar de branco e, sempre que eles passarem no teste alfa, defina o buffer de estêncil nesse local como 1.
  4. Desenhe um quad branco cobrindo a tela inteira, mas apenas onde o valor do buffer de estêncil é 1.

Aqui está o código que eu usei:

(Etapa 1) Primeiro verifique se o backbuffer está sendo criado com espaço para um buffer de estêncil:

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

(Etapa 2) Crie uma textura branca 1x1 que será dimensionada para preencher a tela inteira:

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

(Etapa 3) E agora a parte mais difícil - renderizar. Bem, não é muito difícil, mas requer dois DepthStencilStateobjetos e um AlphaTestEffectobjeto. Você deve criá-los apenas uma vez.

// 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();

E o resultado:

insira a descrição da imagem aqui


Surpreendente! Muito obrigado por colocar tanto esforço nisso, David. Pena que não há uma solução mais simples, mas isso deve funcionar bem.
Ryan McD
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.