在XNA框架中,有没有办法使用典型的SpriteBatch方法渲染2D场景,然后在渲染帧后,将效果应用于整个图像?
例如,模糊,棕褐色甚至使整个事物看起来像旧电影,有颗粒,灰尘,线条等?
答案 0 :(得分:3)
是的 - 您要做的是将渲染目标设置为渲染到纹理而不是图形硬件。然后,一旦输出在纹理中,您将应用像素着色器效果,并将其发送出去。
这里有一些很棒的基本样本效果(我衷心地建议订阅这个博客) http://blogs.msdn.com/b/shawnhar/archive/2007/05/23/transitions-part-four-rendertargets.aspx
答案 1 :(得分:2)
这是我的发光代码,我会对如何改进它的评论感兴趣。基本上我有对象分为发光和正常。我在Initialize方法中创建了两个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()调用中设置自定义效果......这是我的模糊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();
}
}
这是一个示例图像,红绿蓝正方形,上面有发光版本: