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.

Ryan McD
fonte
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

David Gouveia
fonte
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