La première étape consiste à indiquer à la carte graphique que nous avons besoin du tampon de gabarit. Pour ce faire, lorsque vous créez GraphicsDeviceManager, nous définissons PreferredDepthStencilFormat sur DepthFormat.Depth24Stencil8 pour qu'il y ait en fait un gabarit sur lequel écrire.
graphics = new GraphicsDeviceManager(this) {
PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8
};
L'AlphaTestEffect est utilisé pour définir le système de coordonnées et filtrer les pixels avec alpha qui réussissent le test alpha. Nous n'allons pas définir de filtres et définir le système de coordonnées sur le port d'affichage.
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
Ensuite, nous devons configurer deux DepthStencilStates. Ces états dictent le moment où le SpriteBatch effectue le rendu vers le gabarit et le moment où le SpriteBatch effectue le rendu vers le BackBuffer. Nous sommes principalement intéressés par deux variables StencilFunction et StencilPass.
- StencilFunction dicte quand le SpriteBatch dessinera des pixels individuels et quand ils seront ignorés.
- StencilPass dicte quand les pixels dessinés les pixels affectent le pochoir.
Pour le premier DepthStencilState, nous définissons StencilFunction sur CompareFunction. Cela provoque le StencilTest à réussir et lorsque le StencilTest le SpriteBatch rend ce pixel. StencilPass est défini sur StencilOperation. Remplacez ce qui signifie que lorsque le StencilTest réussit, ce pixel sera écrit dans le StencilBuffer avec la valeur du ReferenceStencil.
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
En résumé, le StencilTest passe toujours, l'image est dessinée à l'écran normalement et pour les pixels dessinés à l'écran, une valeur de 1 est stockée dans le StencilBuffer.
Le deuxième DepthStencilState est légèrement plus compliqué. Cette fois, nous voulons uniquement dessiner à l'écran lorsque la valeur dans le StencilBuffer est. Pour ce faire, nous définissons StencilFunction sur CompareFunction.LessEqual et ReferenceStencil sur 1. Cela signifie que lorsque la valeur dans le tampon de stencil est 1, StencilTest réussit. Définition de StencilPass sur StencilOperation. Keep empêche le StencilBuffer de se mettre à jour. Cela nous permet de dessiner plusieurs fois en utilisant le même masque.
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
En résumé, le StencilTest ne passe que lorsque le StencilBuffer est inférieur à 1 (les pixels alpha du masque) et n'affecte pas le StencilBuffer.
Maintenant que nous avons configuré nos DepthStencilStates. Nous pouvons réellement dessiner en utilisant un masque. Dessinez simplement le masque à l'aide du premier DepthStencilState. Cela affectera à la fois le BackBuffer et le StencilBuffer. Maintenant que le tampon de gabarit a une valeur de 0 où votre masque avait de la transparence et 1 où il contenait de la couleur, nous pouvons utiliser StencilBuffer pour masquer les images ultérieures.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
Le deuxième SpriteBatch utilise le second DepthStencilStates. Peu importe ce que vous dessinez, seuls les pixels où le StencilBuffer est défini sur 1 passeront le test du pochoir et seront dessinés à l'écran.
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();
Vous trouverez ci-dessous l'intégralité du code de la méthode Draw, n'oubliez pas de définir PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 dans le constructeur du jeu.
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();