如何在XNA for Windows Phone中为我的纹理创建阴影效果?

时间:2012-01-12 12:37:22

标签: c# .net windows-phone-7 xna windows-phone-7.1

我正在使用XNA Framework为Windows Phone 7编写一个简单的2D游戏。

基本上,用户可以拖动多个项目。我通过在RenderTarget2D上绘制内容来动态创建纹理,然后再绘制RenderTarget2D。我使用模板缓冲区将更大纹理的一部分绘制到渲染目标上。

代码段

util.GraphicsDevice.SetRenderTarget(result);
util.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.Stencil | ClearOptions.DepthBuffer, Color.Transparent, 0, 0);

// The "mask"

spriteBatch.Begin(SpriteSortMode.Deferred, util.DontWriteColorsState, null, util.StencilAlways, null, alphaTestEffect);
spriteBatch.Draw(maskTexture, destination, Color.White);
spriteBatch.End();

// The actual texture

spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, util.StencilKeepWhere1, null, alphaTestEffect);
spriteBatch.Draw(bigTexture, destination, source, Color.White);
spriteBatch.End();

util.GraphicsDevice.SetRenderTarget(null);

util只是一个帮助类的实例,我使用它不必在任何地方复制粘贴相同的代码,它包含DepthStencilState个对象和其他一些东西。)

我想在这些纹理后面创建一个投影效果。我想在渲染目标上绘制阴影。

不幸的是,Windows Phone 7不支持自定义着色器效果,因此我无法使用互联网上的任何示例。所以我决定尝试在软件中实现它。但是我对这种事情完全缺乏经验,所以结果既缓慢又难看。

我在软件中所做的是:

  • 在蒙版纹理周围创建一个笔划,并使用低不透明度绘制
  • 围绕上一个笔划创建笔划,并使用低不透明度绘制
  • ...此步骤重复次数与投影大小相同

然而,它非常缓慢,基本上慢得令人无法接受。

所以问题是

是否可以使用XNA中的内置效果创建阴影或阴影效果?此外,如果没有,是否有一种算法可以在软件中创建漂亮的投影?

提前感谢您的回答! :)

编辑:

我正在考虑这种阴影:
Drop shadow effect

显然,这只是一个例子,我不希望它恰好是这个尺寸。 :)

3 个答案:

答案 0 :(得分:1)

我冒昧地调整你的解决方案@Venemo,这就是我提出的一个良好的开端:

public Texture2D CreateBlurredTexture(Texture2D originalTexture, SpriteEffects effects)
    {
        var device = originalTexture.GraphicsDevice;
        var rt = new RenderTarget2D(device, originalTexture.Width/2, originalTexture.Height/2);
        var rt2 = new RenderTarget2D(device, originalTexture.Width, originalTexture.Height);
        Color shadowColor = Color.Lerp(Color.Black, Color.Transparent, 0.9f);
        using (var spriteBatch = new SpriteBatch(device))
        {
            device.SetRenderTarget(rt);
            device.Clear(Color.Transparent);
            spriteBatch.Begin();
            spriteBatch.Draw(originalTexture, new Rectangle(0, 0, rt.Width, rt.Height), null, shadowColor, 0, Vector2.Zero, effects, 0f);
            spriteBatch.Draw(originalTexture, new Rectangle(1, 1, rt.Width - 2, rt.Height - 2), null, shadowColor, 0, Vector2.Zero, effects, 0f);
            spriteBatch.Draw(originalTexture, new Rectangle(2, 2, rt.Width - 4, rt.Height - 4), null, shadowColor, 0, Vector2.Zero, effects, 0f);
            spriteBatch.Draw(originalTexture, new Rectangle(3, 3, rt.Width - 6, rt.Height - 6), null, shadowColor, 0, Vector2.Zero, effects, 0f);
            spriteBatch.Draw(originalTexture, new Rectangle(4, 4, rt.Width - 8, rt.Height - 8), null, shadowColor, 0, Vector2.Zero, effects, 0f);
            spriteBatch.End();
            device.SetRenderTarget(rt2);
            device.Clear(Color.Transparent);
            spriteBatch.Begin();
            spriteBatch.Draw(rt, new Rectangle(0, 0, rt2.Width, rt2.Height), Color.White);
            spriteBatch.End();
            device.SetRenderTarget(null);
        }

        return rt2;
    }

它的作用是创建纹理的副本,并在每次绘制时增加不透明度,同时朝向中心。完成此操作后,您可以抵消它并增加其大小以创建更大的阴影效果。这应该根据你的纹理完成任务。

答案 1 :(得分:0)

绘制阴影以纯黑色绘制原始渲染目标,可能具有一定的透明度,与原始位置稍微偏移 接下来再次绘制,就像之前在阴影上渲染纹理一样。


关于编辑,为边创建纹理,为角创建纹理,然后将投影绘制为4个边和4个角。

答案 2 :(得分:0)

这是我想出来的,最终 当然有点hacky,但当我提出这个问题时,它有点像我需要的那样。

    public static Texture2D CreateBlurredTexture(Texture2D originalTexture, SpriteEffects effects)
    {
        var device = originalTexture.GraphicsDevice;
        var rt4 = new RenderTarget2D(device, originalTexture.Width / 4, originalTexture.Height / 4);

        using (var rt2 = new RenderTarget2D(device, originalTexture.Width * 3 / 2, originalTexture.Height * 3 / 2))
        using (var rt3 = new RenderTarget2D(device, originalTexture.Width / 2, originalTexture.Height / 2))
        using (var spriteBatch = new SpriteBatch(device))
        {
            device.SetRenderTarget(rt2);
            device.Clear(Color.Transparent);
            spriteBatch.Begin();
            spriteBatch.Draw(originalTexture, new Rectangle(0, 0, rt2.Width, rt2.Height), null, Color.White, 0, Vector2.Zero, effects, 0f);
            spriteBatch.End();
            device.SetRenderTarget(rt3);
            device.Clear(Color.Transparent);
            spriteBatch.Begin();
            spriteBatch.Draw(rt2, new Rectangle(0, 0, rt3.Width, rt3.Height), Color.White);
            spriteBatch.End();
            device.SetRenderTarget(rt4);
            device.Clear(Color.Transparent);
            spriteBatch.Begin();
            spriteBatch.Draw(rt3, new Rectangle(0, 0, rt4.Width, rt4.Height), Color.White);
            spriteBatch.End();
            device.SetRenderTarget(null);
        }

        return rt4;
    }