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.
graphics = new GraphicsDeviceManager(this) {
PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8
};
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.
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
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.
- StencilFunction menentukan kapan SpriteBatch akan menggambar masing-masing piksel dan kapan mereka akan diabaikan.
- StencilPass menentukan kapan piksel yang ditarik mempengaruhi efek Stensil.
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.
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
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.
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
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.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
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.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();
Di bawah ini adalah keseluruhan kode dalam metode Draw, jangan lupa untuk mengatur PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 dalam konstruktor game.
GraphicsDevice.Clear(ClearOptions.Target
| ClearOptions.Stencil, Color.Transparent, 0, 0);
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();