代码之家  ›  专栏  ›  技术社区  ›  Adam Haile

对XNA中的spriteBatch应用后渲染效果

  •  2
  • Adam Haile  · 技术社区  · 14 年前

    在XNA框架中,是否有一种方法可以使用典型的spriteBatch方法渲染二维场景,然后在渲染完该帧后,对整个图像应用效果?

    例如,模糊、灰暗甚至使整件事看起来像一部旧电影,有纹理、灰尘、线条等等?

    2 回复  |  直到 14 年前
        1
  •  3
  •   seraphym    14 年前

    是-将渲染目标设置为 渲染为纹理 而不是你的图形硬件。然后,一旦你的输出是在一个纹理,你将应用你的像素着色效果,并发送它。

    这里提供了一些很好的基本示例效果(我衷心建议您也订阅这个博客) http://blogs.msdn.com/b/shawnhar/archive/2007/05/23/transitions-part-four-rendertargets.aspx

        2
  •  2
  •   Jason Goemaat    14 年前

    这是我的发光代码,我会对如何改进它的评论感兴趣。基本上我把物体分为发光的和普通的。我在初始化方法中创建了两个renderTarget2d对象,其中一个具有深度缓冲区,因为我正在执行3D操作:

    GlowTarget = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);
    GlowTarget2 = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, SurfaceFormat.Color, DepthFormat.None);
    

    在我的绘制方法中,我将普通对象渲染为GlowTarget,然后用零Alpha将颜色清除为黑色,并绘制发光对象。我画这个到GlowTarget2与自定义效果像素着色应用于模糊它在X方向。然后清除渲染目标并绘制普通对象。最后,我在顶部绘制了GlowTarget2纹理,使用另一个自定义效果在Y方向模糊。

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        // draw clear GlowTarget and draw normal, non-glowing objects to set depth buffer
        GraphicsDevice.SetRenderTarget(GlowTarget);
        GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Stencil | ClearOptions.Target, Color.FromNonPremultiplied(0, 0, 0, 0), 1f, 0);
        MyScene.DrawNormal();
    
        // clear target only and set color to black WITH ZERO ALPHA, then draw glowing objects
        // so they will be the only ones that appear and they will be hidden by objects in front of them
        GraphicsDevice.Clear(ClearOptions.Target, Color.FromNonPremultiplied(0, 0, 0, 0), 1f, 0);
        MyScene.DrawGlow();
    
        // blur objects horizontally into GlowTarget2
        GraphicsDevice.SetRenderTarget(GlowTarget2);
        GraphicsDevice.Clear(Color.FromNonPremultiplied(0, 0, 0, 0));
        using (SpriteBatch sb = new SpriteBatch(GlowTarget2.GraphicsDevice))
        {
            blurXEffect.Parameters["PixelSize"].SetValue((float)(1.0f / (float)GlowTarget.Width));
            sb.Begin(0, BlendState.Additive, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullNone, blurXEffect);
            sb.Draw(GlowTarget, new Rectangle(GraphicsDevice.Viewport.X, GraphicsDevice.Viewport.Y, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);
            sb.End();
        }
    
        // now reset context and clear for actual drawing
        GraphicsDevice.SetRenderTarget(null);
        GraphicsDevice.BlendState = BlendState.Opaque;
        GraphicsDevice.Clear(Color.Black);
    
        // TODO: Add your drawing code here
        base.Draw(gameTime);
    
        // draw scene to graphics card back buffer
        MyScene.DrawNormal();
    
        using (SpriteBatch sprite = new SpriteBatch(GraphicsDevice))
        {
            // draw glowing texture and blur Y this time
            blurYEffect.Parameters["PixelSize"].SetValue((float)(1.0f / (float)GlowTarget.Height));
            sprite.Begin(0, BlendState.Additive, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullNone, blurYEffect);
    
            //sprite.Draw(GlowTarget, new Vector2(0, 0), Color.White);
            sprite.Draw(GlowTarget2, new Rectangle(GraphicsDevice.Viewport.X, GraphicsDevice.Viewport.Y, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);
            sprite.End();
        }
    }
    

    如果你用2d做一些简单的事情,比如应用一个效果,那么你可以在spriteBatch.begin()调用中设置一个自定义效果…这是我的Bluring X着色程序:

    // texture we are rendering
    sampler2D tex : register(S0);
    
    float PixelSize;
    
    // pixel shader function
    float4 main(float2 uv : TEXCOORD) : COLOR
    {
        float4 c = 0; // will get max of each value for c
        float alpha = 0; // alpha will be average
    
        float2 myuv = uv;
        for(int i = -7; i <= 7; i++)
        {
            myuv.x = uv.x + (i * PixelSize * 1.5);
            float4 sample = tex2D(tex, myuv);
            c = max(c, sample);
            alpha += sample.a;
        }
    
        c.a = saturate(pow(abs(alpha / 6), 0.4));
        return(c);
    }
    
    technique Technique1
    {
        pass Pass1
        {
            PixelShader = compile ps_2_0 main();
        }
    }
    

    这是一个示例图像,红绿色和蓝色正方形,上面有发光版本: Glow Sample