Efecto de flash XNA Sprite

8

Estoy buscando una manera de renderizar cada píxel no transparente en un sprite blanco sólido (para 'flashear' el sprite blanco cuando el jugador recibe daño, etc.). Esto está en Windows Phone 7.

Estaba usando un sombreador personalizado muy simple para hacer esto en XNA 3.1, pero WP7 no los admite y resulta difícil encontrar una alternativa.

Agradecería cualquier ayuda o sugerencia. Sin embargo, prefiero no tener que crear manualmente una copia blanca sólida de cada sprite en mi juego.

Ryan McD
fuente
1
Bien, encontré una manera, pero no es bonita. Déjame limpiarlo un poco y actualizaré mi respuesta.
David Gouveia

Respuestas:

9

Método 1

No tienes que crear una versión blanca sólida de cada sprite en tu juego de forma manual ; también podrías automatizar el proceso en el momento de la carga. En otras palabras, puede usar Texture2D.GetData()para acceder a los píxeles de su textura (y recuperarlos como un simple Color[]), iterar sobre ellos reemplazando cualquier píxel no transparente con blanco sólido y luego guardarlo en una nueva textura usando y Texture2D.SetData().

Método 2

Traté de jugar con, BlendStatepero no pude encontrar una manera de hacer que todo sea blanco, al menos no dentro de las limitaciones del perfil Reach. Pero si alguien sabe una manera, hágamelo saber. Lo que sí encontré, sin embargo, fue una forma de hacerlo utilizando el búfer de plantilla y la AlphaTestEffectclase incorporada . La idea es la siguiente:

  1. Cree un búfer de respaldo que tenga un búfer de plantilla.
  2. Borre el búfer de la plantilla a cero.
  3. Dibuje los sprites que desea teñir de blanco y cada vez que pasen la prueba alfa, configure el búfer de la plantilla en esa ubicación en 1.
  4. Dibuje un quad blanco que cubra toda la pantalla, pero solo donde el valor del búfer de la plantilla es 1.

Aquí está el código que usé:

(Paso 1) Primero asegúrese de que el backbuffer se esté creando con espacio para un búfer de plantilla:

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

(Paso 2) Cree una textura blanca 1x1 que se escalará para llenar toda la pantalla:

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

(Paso 3) Y ahora la parte difícil: representarlo. Bueno, no es realmente difícil, pero requiere dos DepthStencilStateobjetos y un AlphaTestEffectobjeto. Debe crearlos solo una 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();

Y el resultado:

ingrese la descripción de la imagen aquí

David Gouveia
fuente
¡Asombroso! Muchas gracias por poner tanto esfuerzo en esto, David. Es una pena que no haya una solución más simple, pero esto debería funcionar bien.
Ryan McD