Schablonenmaske mit AlphaTestEffect

7

Ich versuche, den folgenden Effekt in XNA 4.0 zu erzielen:

Geben Sie hier die Bildbeschreibung ein

Der violette Bereich hat eine Deckkraft von 50%. Ich bin mit dem folgenden Code ziemlich nahe gekommen:

public static DepthStencilState AlwaysStencilState = new DepthStencilState()
        {

            StencilEnable = true,
            StencilFunction = CompareFunction.Always,
            StencilPass = StencilOperation.Replace,
            ReferenceStencil = 1,
            DepthBufferEnable = false,
        };

public static DepthStencilState EqualStencilState = new DepthStencilState()
        {
            StencilEnable = true,
            StencilFunction = CompareFunction.Equal,
            StencilPass = StencilOperation.Keep,
            ReferenceStencil = 1,
            DepthBufferEnable = false,
        };

...

if (_alphaEffect == null)
{
       _alphaEffect = new AlphaTestEffect(_spriteBatch.GraphicsDevice);
       _alphaEffect.AlphaFunction = CompareFunction.LessEqual;
       _alphaEffect.ReferenceAlpha = 129;
       Matrix projection = Matrix.CreateOrthographicOffCenter(0, _spriteBatch.GraphicsDevice.PresentationParameters.BackBufferWidth, _spriteBatch.GraphicsDevice.PresentationParameters.BackBufferHeight, 0, 0, 1); 
       _alphaEffect.Projection = world.SystemManager.GetSystem<RenderSystem>().Camera.View * projection;
}

_mask = new RenderTarget2D(_spriteBatch.GraphicsDevice, _spriteBatch.GraphicsDevice.PresentationParameters.BackBufferWidth, _spriteBatch.GraphicsDevice.PresentationParameters.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);
_spriteBatch.GraphicsDevice.SetRenderTarget(_mask);
_spriteBatch.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.Stencil, Color.Transparent, 0, 0); 

_spriteBatch.Begin(SpriteSortMode.Immediate, null, null, AlwaysStencilState, null, _alphaEffect);
_spriteBatch.Draw(sprite.Texture, position, sprite.SourceRectangle,Color.White, 0f, sprite.Origin, 1f, SpriteEffects.None, 0);
_spriteBatch.End();

_spriteBatch.Begin(SpriteSortMode.Immediate, null, null, EqualStencilState, null, null);
_spriteBatch.Draw(_maskTex, new Vector2(x * _maskTex.Width, y * _maskTex.Height), null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0);
_spriteBatch.End();

_spriteBatch.GraphicsDevice.SetRenderTarget(null);
_spriteBatch.GraphicsDevice.Clear(Color.Black);

_spriteBatch.Begin();
_spriteBatch.Draw((Texture2D)_mask, Vector2.Zero, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, layer/max_layer);
_spriteBatch.End();

Mein Problem ist, dass ich den AlphaTestEffect nicht zum Verhalten bringen kann. Ich kann entweder den halbtransparenten lila Müll maskieren und ihn mit dem grünen Design füllen, oder ich kann über die vollständig undurchsichtige grasartige Textur zeichnen. Wie kann ich die genaue Deckkraft angeben, die durch das grüne Design ersetzt werden muss?

Brendan Wanlass
quelle
1
Hallo Brendan, und willkommen bei GDSE. Sie müssen Ihre Beiträge nicht signieren, da sie bereits mit Ihren Benutzerinformationen signiert sind, und Sie müssen kein Tag in Ihrem Titel ablegen, da Ihre Frage bereits Tags enthält. Ich habe beide herausgeschnitten.
Doppelgreener
Warum kannst du das Lila nicht durch einen richtigen Alphakanal ersetzen und es zuletzt zeichnen?
ClassicThunder

Antworten:

1

Ich bin mir nicht sicher, ob Sie dies mit dem AlphaTestEffect tun können (tatsächlich weiß ich nicht, wie ATE funktioniert). Ich möchte kürzlich eine Art Menü zeichnen, das den Schablonenpuffer korrekt ausfüllt und eine Art Maske ist.

Mein PixelShader sieht folgendermaßen aus:

float4 PSFunc (VertexShaderOutput input) : COLOR0
{
    float4 texel = tex2D(TextureSampler, input.TexCoord);
    clip(texel.w - AlphaClipValue);
    return texel;
}

AlphaClipValue definiert, welche Pixel in der Textur sichtbar sind. Beispiel: 0.8f definiert, dass alle Alpha-Werte in der Textur, die über 204 liegen, gezeichnet werden. Andere Pixel werden abgeschnitten.

protected readonly DepthStencilState DrawMaskDepthStencilState = 
    new DepthStencilState(){
        StencilEnable = true,
        StencilFunction = CompareFunction.Always,
        StencilPass = StencilOperation.Invert,
        ReferenceStencil = 0,
        DepthBufferEnable = true,
    };
protected readonly DepthStencilState DrawSceneDepthStencilState = 
    new DepthStencilState(){
    StencilEnable = true,
        StencilFunction = CompareFunction.Equal,
        StencilPass = StencilOperation.Keep,
        ReferenceStencil = 0,
        DepthBufferEnable = true,
    };

Nun die Auslosung ()

public override void Draw(GameTime gameTime){
    //set state that is able to draw
    GraphicsDevice.DepthStencilState = DrawMaskDepthStencilState;

    //set texture and AlphaClipValue (1 means only pixel with Alpha==255 gets drawn)
    DrawMenuEffect.Texture = _maskTexture;
    DrawMenuEffect.AlphaClipValue = 1f;
    DrawMenuEffect.CurrentTechnique.Passes[0].Apply();
    GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip,    FullScreenQuadStripVertices,0,2);

    GraphicsDevice.DepthStencilState = DrawSceneDepthStencilState;

    // Now draw rest of the scene 
}

Ich benutze meine eigenen projizierten Quads, um die Textur zu zeichnen, weil mir SpriteBatch nicht gefällt (es setzt einen Zustand zurück, der nicht zurückgesetzt wird). Aber ich denke, es sollte auch mit SpriteBatch funktionieren. Andernfalls können Sie hier nachsehen , wie Sie sie erstellen.

0xBADF00D
quelle