J'essaie actuellement de masquer certains sprites. Plutôt que de l'expliquer par des mots, j'ai composé quelques exemples d'images:
La zone à masquer (en blanc)
Maintenant, le sprite rouge qui doit être recadré.
Le résultat final.
Maintenant, je sais que dans XNA, vous pouvez faire deux choses pour y parvenir:
- Utilisez le tampon de pochoir.
- Utilisez un Pixel Shader.
J'ai essayé de faire un pixel shader, qui a essentiellement fait ceci:
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);
}
}
Cela semble recadrer les images (bien que ce ne soit pas correct une fois que l'image commence à bouger), mais mon problème est que les images se déplacent constamment (elles ne sont pas statiques), donc ce recadrage doit être dynamique.
Existe-t-il un moyen de modifier le code du shader pour prendre en compte sa position?
Alternativement, j'ai lu sur l'utilisation du tampon de gabarit, mais la plupart des exemples semblent dépendre de l'utilisation d'un rendu cible, ce que je ne veux vraiment pas faire. (J'utilise déjà 3 ou 4 pour le reste du jeu, et en ajouter un autre par dessus semble exagéré)
Le seul tutoriel que j'ai trouvé qui n'utilise pas Rendertargets est celui du blog de Shawn Hargreaves ici. Le problème avec celui-ci, cependant, c'est que c'est pour XNA 3.1, et ne semble pas bien se traduire par XNA 4.0.
Il me semble que le pixel shader est la voie à suivre, mais je ne sais pas comment obtenir le bon positionnement. Je pense que je devrais changer mes coordonnées à l'écran (quelque chose comme 500, 500) pour qu'elles soient comprises entre 0 et 1 pour les coordonnées du shader. Mon seul problème est d'essayer de savoir comment utiliser correctement les coordonnées transformées.
Merci d'avance pour votre aide!
Réponses:
Vous pouvez utiliser votre approche pixel shader mais elle est incomplète.
Vous devrez également lui ajouter des paramètres qui informent le pixel shader où vous souhaitez placer votre pochoir.
Dans votre code C #, vous passez des variables au pixel shader avant l'
SpriteBatch.Draw
appel comme ceci:la source
maskCoord
calcul, l'un des X aurait dû être un Y. J'ai modifié ma réponse initiale avec le correctif et inclus les paramètres de la pince UV dont vous aurez besoin pour votreMaskTexture sampler
.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.
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.
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.
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.
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.
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.
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.
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.
la source
Dans la réponse ci - dessus , des choses étranges se sont produites lorsque j'ai fait exactement ce qui est expliqué.
La seule chose dont j'avais besoin était les deux
DepthStencilStates
.Et les tirages sans
AlphaTestEffect
.Et tout allait bien comme prévu.
la source