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已经很晚了,而且我不太擅长解释模板缓冲区,但我以前已经找到了使用它们的方法。此外,我不知道这是否会起作用,但似乎没有其他人回应,所以我想我应该试一试。
无需实际编译代码,看起来一切都按照您的意图进行了设置。画瓷砖,然后只在瓷砖的顶部画反射,对吗?我认为这里的问题是,即使你的贴图是完全透明的,这些像素仍然被绘制,因此模板测试通过,并将现有的0替换为1。
第1步:测试看看这是否真的是问题。
尝试画每一个其他瓷砖…if((x + y) % 2 == 0) { /* draw tile */ }
。如果这为您的反射创建了一个棋盘图案,那么您就知道透明像素通过了模板测试。继续第二步(否则告诉我它不能工作)。
步骤2:修复模板传递问题
你需要一种方法来剪辑这些透明像素之前,他们有机会通过模板测试。你可以通过使用颜色键或像素着色器来做到这一点。要使用颜色键,请选择图像资源,然后单击属性选项卡/菜单。在这里,你应该找到"使用颜色键"answers"颜色键"选项。你应该能够选择图像的透明颜色作为颜色键,这将阻止图像的那部分渲染(它将被剪切),并且不会通过模板测试。
选择# 1 :
你可以编写一个像素着色器,在绘制贴图时绘制反射。通过这样做,它将允许你为贴图的每个部分添加正确数量的反射,即使贴图有"羽毛"(渐变透明度)边缘。使用颜色键是不可能得到这样平滑的效果的。
替代# 2:
假设你在一个完全透明的背景上绘制贴图,你可以用一个特殊的混合模式来绘制反射。
Source = DestAlpha
Dest = One
这将附加地将反射绘制到图像的不透明部分。或者,您可以将它们相互叠加(我认为这是如何设置的?):
Source = Dest
Dest = Zero
无论如何,我希望这在某种程度上有所帮助,或者至少引导你走向正确的方向。祝你好运,找到一个好的回应。:)