XNA Sprite Flash Effect

8

Saya mencari cara untuk membuat setiap piksel non-transparan dalam sprite solid white (untuk 'mem-flash' sprite white saat pemain mengalami kerusakan, dll.). Ini ada di Windows Phone 7.

Saya menggunakan custom shader yang sangat sederhana untuk melakukan ini di bawah XNA 3.1, tetapi WP7 tidak mendukung ini dan sulit menemukan alternatif.

Saya menghargai bantuan atau saran. Saya lebih suka tidak harus secara manual membuat salinan putih solid dari setiap sprite di game saya.

Ryan McD
sumber
1
Oke, saya memang menemukan jalan, tetapi tidak cantik. Biarkan saya membersihkannya sedikit dan saya akan memperbarui jawaban saya.
David Gouveia

Jawaban:

9

Metode 1

Anda tidak harus membuat versi putih solid dari setiap sprite di game Anda secara manual - Anda bisa mengotomatiskan proses pada waktu pengambilan. Dengan kata lain, Anda dapat menggunakan Texture2D.GetData()untuk mengakses piksel tekstur Anda (dan mengambilnya sebagai sederhana Color[]), iterate di atasnya menggantikan setiap piksel non-transparan dengan putih solid, dan kemudian simpan ke tekstur baru menggunakan dan Texture2D.SetData().

Metode 2

Saya mencoba bermain-main dengan BlendStatetetapi tidak bisa menemukan cara untuk membuat semuanya putih, setidaknya tidak dalam batasan profil Jangkauan. Tetapi jika seseorang tahu caranya, beri tahu saya. Apa yang saya temukan, bagaimanapun, adalah cara untuk melakukannya dengan menggunakan buffer stensil dan AlphaTestEffectkelas bawaan. Idenya adalah sebagai berikut:

  1. Buat backbuffer yang memiliki buffer stensil.
  2. Bersihkan buffer stensil ke nol.
  3. Gambarkan sprite yang ingin Anda warnai menjadi putih dan setiap kali mereka lulus uji alpha, atur buffer stensil ke lokasi itu menjadi 1.
  4. Gambarlah quad putih yang menutupi seluruh layar, tetapi hanya di mana nilai buffer stensil adalah 1.

Berikut kode yang saya gunakan:

(Langkah 1) Pertama-tama pastikan backbuffer sedang dibuat dengan ruang untuk buffer stensil:

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

(Langkah 2) Buat tekstur putih 1x1 yang akan diskalakan untuk mengisi seluruh layar:

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

(Langkah 3) Dan sekarang bagian yang sulit - render. Yah, tidak terlalu sulit, tetapi membutuhkan dua DepthStencilStateobjek dan satu AlphaTestEffectobjek. Anda harus membuat ini hanya sekali.

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

Dan hasilnya:

masukkan deskripsi gambar di sini

David Gouveia
sumber
Luar biasa! Terima kasih banyak atas usaha kerasnya dalam hal ini, David. Malu tidak ada solusi yang lebih sederhana, tetapi ini harus melakukan trik dengan baik.
Ryan McD