İlk adım, grafik kartına şablon tamponuna ihtiyacımız olduğunu söylemek. GraphicsDeviceManager'ı oluştururken bunu yapmak için PreferredDepthStencilFormat öğesini DepthFormat.Depth24Stencil8 olarak ayarladık, böylece aslında yazılacak bir şablon var.
graphics = new GraphicsDeviceManager(this) {
PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8
};
AlphaTestEffect, koordinat sistemini ayarlamak ve alfa testinden geçen alfa ile pikselleri filtrelemek için kullanılır. Herhangi bir filtre ayarlamayacağız ve koordinat sistemini görüntüleme portuna ayarlamayacağız.
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
Daha sonra iki adet DepthStencilStates kurmamız gerekiyor. Bu durumlar, SpriteBatch şablona işlediğinde ve SpriteBatch, BackBuffer'a işlendiğinde belirlenir. Öncelikle iki değişken StencilFunction ve StencilPass ile ilgileniyoruz.
- StencilFunction, SpriteBatch'un ne zaman ayrı pikseller çizeceğini ve ne zaman dikkate alınmayacağını belirler.
- StencilPass, çizilen piksel piksellerinin Stencil'i etkilediğinde dikte eder.
İlk DepthStencilState için StencilFunction öğesini CompareFunction olarak ayarladık. Bu StencilTest'in başarılı olmasına ve StencilTest SpriteBatch'in o pikseli oluşturmasına neden olur. StencilPass, StencilOperation olarak ayarlanmıştır. StencilTest, o pikselin StencilBuffer'a ReferenceStencil'in değeriyle yazılacağı anlamına gelir.
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
Özet olarak StencilTest her zaman geçer, görüntü normal olarak ekrana çizilir ve ekrana çizilen pikseller için StencilBuffer'da 1 değeri kaydedilir.
İkinci DepthStencilState biraz daha karmaşık. Bu kez sadece StencilBuffer'daki değer olduğunda ekrana çizim yapmak istiyoruz. Bunu başarmak için StencilFunction işlevini CompareFunction.LessEqual ve ReferenceStencil değerini 1 olarak ayarladık. Bunun anlamı, şablon tamponundaki değer 1 olduğunda StencilTest'in başarılı olacağı anlamına gelir. StencilPass'in StencilOperation'a ayarlanması. StencilBuffer'ın güncellenmemesine neden olun. Bu, aynı maskeyi kullanarak birkaç kez çizmemize izin verir.
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
Özetle StencilTest, yalnızca StencilBuffer 1'den küçük olduğunda (maskeden alfa pikselleri) geçer ve StencilBuffer'ı etkilemez.
Şimdi DepthStencilStates'imizi kurduk. Maske kullanarak çizim yapabiliriz. Sadece ilk DepthStencilState'i kullanarak maskeyi çizin. Bu, hem BackBuffer'ı hem de StencilBuffer'ı etkileyecektir. Şimdi, stencil tamponu, maskenizin saydamlığa sahip olduğu 0 değerine ve 1'in renk içerdiği yerlerde, daha sonraki görüntüleri maskelemek için StencilBuffer'ı kullanabiliriz.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
İkinci SpriteBatch, ikinci DepthStencilStates'i kullanır. Ne çizdiğiniz önemli değil, sadece StencilBuffer'ın 1'e ayarlandığı pikseller şablon testini geçecek ve ekrana çizilecektir.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();
Draw yöntemindeki kodun tamamı aşağıdadır, oyun yapıcısında PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 değerini ayarlamayı unutmayın.
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();