首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Xna StencilBuffers

Xna StencilBuffers
EN

Stack Overflow用户
提问于 2011-10-17 09:26:49
回答 1查看 552关注 0票数 0

我一直在不知疲倦地工作,试图让模板缓冲区在XNA4.0中工作,但没有成功

代码语言:javascript
复制
 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);
    }

这是我的函数,我正在使用它来尝试绘制模板蒙版...

代码语言:javascript
复制
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

EN

回答 1

Stack Overflow用户

发布于 2011-10-17 14:15:18

现在已经很晚了,我也不太擅长解释模板缓冲区,但我之前已经找到了解决它们的方法。此外,我不知道这是否会奏效,但似乎没有其他人响应,所以我想我应该试一试。

在没有实际编译代码的情况下,看起来一切都按照您的预期进行了设置。绘制平铺,然后只在平铺上绘制反射,对吗?我认为这里的问题是,即使您的磁贴是完全透明的,这些像素仍然是绘制的,因此模板测试是通过的,并用1替换现有的0。

第1步:测试以确定这是否真的是问题所在。

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

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

在这些透明像素有机会通过模板测试之前,您需要一种方法来裁剪它们。可以使用颜色键或像素明暗器执行此操作。要使用颜色键,请选择平铺的图像资源,然后单击属性选项卡/菜单。在这下面你可以找到"Use Color Key“和"Color Key”选项。你应该能够选择你的图像的透明颜色作为颜色键,这将阻止图像的该部分渲染(它将被裁剪),并且不会通过模板测试。

备选方案#1

您可以编写一个像素着色器,在绘制平铺时绘制反射。通过这样做,它将允许您添加正确数量的反射到瓷砖的每个部分,即使瓷砖有“羽化”(渐变透明)的边缘。使用颜色键无法获得像这样的平滑外观。

替代方案#2

假设您在完全透明的背景上绘制瓷砖,则可以使用特殊的混合模式绘制反射。

代码语言:javascript
复制
Source = DestAlpha
Dest = One

这将附加地将反射绘制到图像的不透明部分。或者,您可以将它们多个相互关联(我认为这就是它的设置方式?):

代码语言:javascript
复制
Source = Dest
Dest = Zero

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7788593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档