Der erste Schritt besteht darin, der Grafikkarte mitzuteilen, dass wir den Schablonenpuffer benötigen. Um dies zu tun, wenn Sie GraphicsDeviceManager erstellen, setzen wir PreferredDepthStencilFormat auf DepthFormat.Depth24Stencil8, sodass tatsächlich eine Schablone zum Schreiben vorhanden ist.
graphics = new GraphicsDeviceManager(this) {
PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8
};
Der AlphaTestEffect wird verwendet, um das Koordinatensystem festzulegen und die Pixel mit Alpha zu filtern, die den Alpha-Test bestehen. Wir werden keine Filter setzen und das Koordinatensystem auf den Ansichtsport setzen.
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
Als nächstes müssen wir zwei DepthStencilStates einrichten. Diese Zustände bestimmen, wann der SpriteBatch in die Schablone und wann der SpriteBatch in den BackBuffer gerendert wird. Wir interessieren uns hauptsächlich für zwei Variablen StencilFunction und StencilPass.
- StencilFunction bestimmt, wann der SpriteBatch einzelne Pixel zeichnet und wann sie ignoriert werden.
- StencilPass bestimmt, wann gezeichnete Pixel die Schablone beeinflussen.
Für den ersten DepthStencilState setzen wir StencilFunction auf CompareFunction. Dies bewirkt, dass der StencilTest erfolgreich ist und wenn der StencilTest, den SpriteBatch ausführt, dieses Pixel gerendert wird. StencilPass ist auf StencilOperation eingestellt. Ersetzen bedeutet, dass bei erfolgreichem StencilTest dieses Pixel mit dem Wert von ReferenceStencil in den StencilBuffer geschrieben wird.
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
Zusammenfassend besteht der StencilTest immer, das Bild wird normal auf den Bildschirm gezeichnet und für auf den Bildschirm gezeichnete Pixel wird der Wert 1 im StencilBuffer gespeichert.
Der zweite DepthStencilState ist etwas komplizierter. Dieses Mal möchten wir nur dann auf dem Bildschirm zeichnen, wenn der Wert im StencilBuffer ist. Um dies zu erreichen, setzen wir die StencilFunction auf CompareFunction.LessEqual und die ReferenceStencil auf 1. Dies bedeutet, dass der StencilTest erfolgreich ist, wenn der Wert im Schablonenpuffer 1 ist. StencilPass auf StencilOperation setzen. Behalten bewirkt, dass der StencilBuffer nicht aktualisiert wird. Auf diese Weise können wir mit derselben Maske mehrere Male zeichnen.
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
Zusammenfassend lässt sich sagen, dass der StencilTest nur erfolgreich ist, wenn der StencilBuffer kleiner als 1 ist (Alpha-Pixel von der Maske), und den StencilBuffer nicht beeinflusst.
Jetzt haben wir unsere DepthStencilStates eingerichtet. Wir können tatsächlich mit einer Maske zeichnen. Zeichnen Sie einfach die Maske mit dem ersten DepthStencilState. Dies wirkt sich sowohl auf den BackBuffer als auch auf den StencilBuffer aus. Nachdem der Schablonenpuffer den Wert 0 hat, bei dem Sie Transparenz maskiert haben, und 1, bei dem es Farbe enthielt, können wir StencilBuffer verwenden, um spätere Bilder zu maskieren.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
Der zweite SpriteBatch verwendet die zweiten DepthStencilStates. Unabhängig davon, was Sie zeichnen, bestehen nur die Pixel, bei denen der StencilBuffer auf 1 gesetzt ist, den Schablonentest und werden auf den Bildschirm gezeichnet.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();
Unten finden Sie den gesamten Code in der Draw-Methode. Vergessen Sie nicht, PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 im Spielkonstruktor festzulegen.
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();