Saat ini saya mencoba untuk menutupi beberapa sprite. Daripada menjelaskannya dengan kata-kata, saya membuat beberapa contoh gambar:
Area untuk menutupi (putih)
Sekarang, sprite merah yang perlu dipotong.
Hasil akhir.
Sekarang, saya sadar bahwa di XNA Anda dapat melakukan dua hal untuk mencapai ini:
- Gunakan Buffer Stensil.
- Gunakan Pixel Shader.
Saya telah mencoba melakukan pixel shader, yang pada dasarnya melakukan ini:
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
float4 tex = tex2D(BaseTexture, texCoord);
float4 bitMask = tex2D(MaskTexture, texCoord);
if (bitMask.a > 0)
{
return float4(tex.r, tex.g, tex.b, tex.a);
}
else
{
return float4(0, 0, 0, 0);
}
}
Ini tampaknya memangkas gambar (meskipun, tidak benar setelah gambar mulai bergerak), tetapi masalah saya adalah bahwa gambar terus bergerak (tidak statis), jadi pemangkasan ini harus dinamis.
Apakah ada cara saya bisa mengubah kode shader untuk memperhitungkan posisinya?
Atau, saya pernah membaca tentang menggunakan Buffer Stensil, tetapi sebagian besar sampel tampaknya bergantung pada menggunakan rendertarget, yang saya benar-benar tidak ingin lakukan. (Saya sudah menggunakan 3 atau 4 untuk sisa permainan, dan menambahkan satu lagi di atasnya tampaknya berlebihan)
Satu-satunya tutorial yang saya temukan yang tidak menggunakan Rendertarget adalah satu dari blog Shawn Hargreaves di sini. Masalah dengan yang itu, meskipun adalah bahwa itu untuk XNA 3.1, dan tampaknya tidak menerjemahkan dengan baik ke XNA 4.0.
Menurut saya pixel shader adalah jalan yang harus ditempuh, tetapi saya tidak yakin bagaimana cara mendapatkan posisi yang benar. Saya percaya saya harus mengubah koordinat layar saya (sekitar 500, 500) menjadi antara 0 dan 1 untuk koordinat shader. Satu-satunya masalah saya adalah mencoba mencari cara menggunakan koordinat yang diubah dengan benar.
Terima kasih sebelumnya atas bantuannya!
Jawaban:
Anda dapat menggunakan pendekatan pixel shader Anda tetapi tidak lengkap.
Anda juga perlu menambahkan beberapa parameter yang menginformasikan pixel shader di mana Anda ingin stensil Anda berada.
Dalam kode C # Anda memasukkan variabel ke pixel shader sebelum
SpriteBatch.Draw
panggilan seperti ini:sumber
maskCoord
perhitungan, salah satu dari X seharusnya adalah Y. Saya telah mengedit jawaban awal saya dengan perbaikan dan termasuk pengaturan penjepit UV yang Anda perlukan untuk AndaMaskTexture sampler
.Langkah pertama adalah memberi tahu kartu grafis bahwa kita memerlukan buffer stensil. Untuk melakukan ini ketika Anda membuat GraphicsDeviceManager kami mengatur PreferredDepthStencilFormat ke DepthFormat.Depth24Stencil8 sehingga sebenarnya ada stensil untuk menulis.
AlphaTestEffect digunakan untuk mengatur sistem koordinat dan memfilter piksel dengan alpha yang lulus uji alpha. Kami tidak akan mengatur filter apa pun dan mengatur sistem koordinat ke port tampilan.
Selanjutnya kita perlu mengatur dua DepthStencilStates. Status ini menentukan kapan SpriteBatch merender ke stensil dan ketika SpriteBatch merender ke BackBuffer. Kami terutama tertarik pada dua variabel StencilFunction dan StencilPass.
Untuk DepthStencilState pertama kita mengatur StencilFunction ke CompareFunction. Ini menyebabkan StencilTest berhasil dan ketika StencilTest SpriteBatch membuat piksel itu. StencilPass diatur ke StencilOperation. Ganti artinya bahwa ketika StencilTest berhasil, piksel tersebut akan ditulis ke StencilBuffer dengan nilai ReferenceStencil.
Singkatnya StencilTest selalu berlalu, gambar ditarik ke layar normal, dan untuk piksel yang ditarik ke layar nilai 1 disimpan dalam StencilBuffer.
DepthStencilState kedua sedikit lebih rumit. Kali ini kami hanya ingin menggambar ke layar ketika nilai di StencilBuffer adalah. Untuk mencapai ini, kita mengatur StencilFunction ke CompareFunction.LessEqual dan ReferenceStencil ke 1. Ini berarti bahwa ketika nilai dalam buffer stensil adalah 1, StencilTest akan berhasil. Pengaturan StencilPass ke StencilOperation. Keep menyebabkan StencilBuffer tidak memperbarui. Ini memungkinkan kita untuk menggambar beberapa kali menggunakan topeng yang sama.
Singkatnya, StencilTest hanya lewat ketika StencilBuffer kurang dari 1 (piksel alpha dari topeng) dan tidak mempengaruhi StencilBuffer.
Sekarang kita sudah mengatur DepthStencilStates kita. Kita sebenarnya bisa menggambar menggunakan topeng. Cukup gambar topeng menggunakan DepthStencilState pertama. Ini akan mempengaruhi BackBuffer dan StencilBuffer. Sekarang bahwa penyangga stensil memiliki nilai 0 di mana Anda menutupi memiliki transparansi dan 1 di mana itu berisi warna kita dapat menggunakan StencilBuffer untuk menutupi gambar kemudian.
SpriteBatch kedua menggunakan DepthStencilStates kedua. Apa pun yang Anda gambar, hanya piksel di mana StencilBuffer diatur ke 1 yang akan lulus uji stensil dan ditarik ke layar.
Di bawah ini adalah keseluruhan kode dalam metode Draw, jangan lupa untuk mengatur PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 dalam konstruktor game.
sumber
Dalam jawaban di atas , beberapa hal aneh terjadi ketika saya melakukan persis seperti yang dijelaskan.
Satu-satunya yang saya butuhkan adalah keduanya
DepthStencilStates
.Dan undian tanpa
AlphaTestEffect
.Dan semuanya baik-baik saja seperti yang diharapkan.
sumber