Xna StencilBuffers

本文关键字:StencilBuffers Xna | 更新日期: 2023-09-27 18:11:20

我一直在不知疲倦地尝试让模板缓冲区在xna 4.0中工作,但没有运气

 private void DrawReflectionMask()
    {
        if (AlphaEffect == null)
        {
            AlphaEffect = new AlphaTestEffect(GraphicsDevice);
            AlphaEffect.VertexColorEnabled = true;
            AlphaEffect.DiffuseColor = Color.White.ToVector3();
            AlphaEffect.AlphaFunction = CompareFunction.Equal;
            AlphaEffect.ReferenceAlpha = 0;
            AlphaEffect.World = Matrix.Identity;
            AlphaEffect.View = Matrix.Identity;
        }
        if(mReflection == null)
        {
            mReflection = Content.Load<Texture2D>("reflection");
            mMask = Content.Load<Texture2D>("ice-mask");
        }
        mSpriteBatch.End();
        RenderTarget2D lMaskRenderTarget = new RenderTarget2D(mGraphicsDevice, mPixelViewport.Width, mPixelViewport.Height,false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0 ,RenderTargetUsage.DiscardContents);

        GraphicsDevice.SetRenderTarget(lMaskRenderTarget);
        BlendState lOldState = GraphicsDevice.BlendState;
        GraphicsDevice.BlendState = ABlendState;
        GraphicsDevice.Clear(ClearOptions.Stencil | ClearOptions.Target, new Color(0,0,0,1), 0, 0);
        SpriteBatch.Begin(SpriteSortMode.Immediate,null,null, AlwaysStencilState,null);
        for (int x = mViewPort.Viewport.Left; x < mViewPort.Viewport.Right; x++)
        {
            for (int y = mViewPort.Viewport.Top; y < mViewPort.Viewport.Bottom; y++)
            {
                int lTileIndex = mMap[x, y].TileID;
                Rectangle lSourceRectangle = new Rectangle((lTileIndex % 8) * 32, (lTileIndex / 8) * 32, 32, 32);
                mSpriteBatch.Draw(mMask,
                                  new Vector2((x - mViewPort.Viewport.X) * 32, (y - mViewPort.Viewport.Y) * 32),
                                  lSourceRectangle,
                                  Color.White);
            }
        }
        SpriteBatch.End();
        GraphicsDevice.BlendState = lOldState;
        SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, EqualStencilState, null);
        for (int x = 0; x < 4; x++)
        {
            for (int y = 0; y < 3; y++)
            {
                SpriteBatch.Draw(mReflection, new Vector2(x * 256, y * 256), Color.White);
            }
        }
        SpriteBatch.End();
        GraphicsDevice.SetRenderTarget(null);
        //lMaskRenderTarget.SaveAsPng(new FileStream("Image.png", FileMode.Create), lMaskRenderTarget.Width, lMaskRenderTarget.Height);
        SpriteBatch.Begin();
        SpriteBatch.Draw(lMaskRenderTarget, Vector2.Zero, Color.White);
    }

这是我的函数,我用它来尝试绘制到模板蒙版…

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,
    };

这些是我的模板状态…

我想做的是掩盖部分基于蒙版的纹理。

这是我的倒影

http://www.badsheepgaming.com/Kevin/reflection.png

这是我的面具

http://www.badsheepgaming.com/Kevin/ice-mask.png

下面是我用这段代码得到的结果

http://www.badsheepgaming.com/Kevin/outcome.png

这是我所期望的

http://www.badsheepgaming.com/Kevin/cow.png

Xna StencilBuffers

已经很晚了,而且我不太擅长解释模板缓冲区,但我以前已经找到了使用它们的方法。此外,我不知道这是否会起作用,但似乎没有其他人回应,所以我想我应该试一试。

无需实际编译代码,看起来一切都按照您的意图进行了设置。画瓷砖,然后只在瓷砖的顶部画反射,对吗?我认为这里的问题是,即使你的贴图是完全透明的,这些像素仍然被绘制,因此模板测试通过,并将现有的0替换为1。

第1步:测试看看这是否真的是问题。

尝试画每一个其他瓷砖…if((x + y) % 2 == 0) { /* draw tile */ }。如果这为您的反射创建了一个棋盘图案,那么您就知道透明像素通过了模板测试。继续第二步(否则告诉我它不能工作)。

步骤2:修复模板传递问题

你需要一种方法来剪辑这些透明像素之前,他们有机会通过模板测试。你可以通过使用颜色键或像素着色器来做到这一点。要使用颜色键,请选择图像资源,然后单击属性选项卡/菜单。在这里,你应该找到"使用颜色键"answers"颜色键"选项。你应该能够选择图像的透明颜色作为颜色键,这将阻止图像的那部分渲染(它将被剪切),并且不会通过模板测试。

选择# 1 :

你可以编写一个像素着色器,在绘制贴图时绘制反射。通过这样做,它将允许你为贴图的每个部分添加正确数量的反射,即使贴图有"羽毛"(渐变透明度)边缘。使用颜色键是不可能得到这样平滑的效果的。

替代# 2

:

假设你在一个完全透明的背景上绘制贴图,你可以用一个特殊的混合模式来绘制反射。

Source = DestAlpha
Dest = One

这将附加地将反射绘制到图像的不透明部分。或者,您可以将它们相互叠加(我认为这是如何设置的?):

Source = Dest
Dest = Zero

无论如何,我希望这在某种程度上有所帮助,或者至少引导你走向正确的方向。祝你好运,找到一个好的回应。:)