Применить эффект пост-рендеринга к SpriteBatch в XNA - PullRequest
2 голосов
/ 21 июля 2010

Есть ли способ, в рамках XNA, визуализировать вашу 2D-сцену с использованием типичного метода SpriteBatch, а затем, после того, как этот кадр будет отрисован, применить эффект ко всему изображению?сепия или даже создание картины, похожей на старый фильм, с зернами, пылью, линиями и т. д.?

Ответы [ 2 ]

3 голосов
/ 21 июля 2010

Да - вам нужно установить цель рендеринга на для рендеринга в текстуру вместо вашего графического оборудования.Затем, когда ваш вывод будет в текстуре, вы примените эффекты пиксельного шейдера и отправите его.

Некоторые отличные базовые примеры эффектов доступны здесь (я также настоятельно рекомендую подписаться на этот блог) http://blogs.msdn.com/b/shawnhar/archive/2007/05/23/transitions-part-four-rendertargets.aspx

2 голосов
/ 03 января 2011

Вот мой светящийся код, мне было бы интересно узнать, как его улучшить. В основном я делю объекты на светящиеся и нормальные. Я создаю два объекта RenderTarget2D в моем методе Initialize, один из них с буфером глубины, потому что я делаю 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, затем очищаю цвет до черного с нулевой альфа-каналом и рисую светящиеся объекты. Я рисую это в 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 () ... Вот мой шейдер для размытия 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

...