Adding 2D pixel effects to Layers

Written by Dean Edis.

In our first article we covered how we can write a simplified Photoshop-style API for displaying multiple textures on the screen, and we have since extended the code to several extra features:

Adding Parallax scrolling to your XNA code
Adding video layers to your XNA code
Reporting performance statistics in your XNA code

We will now move on to another powerful addition to the Layer code - Effect filters. Photoshop (and similar applications) allow effects to be applied on a layer-by-layer basis - Blur, grayscale, bloom, lighten, darken, etc. The ability to chain together multiple filters can create some stunning visual effects, and as XNA allows us to run these on the graphics card’s GPU they can have a minimal impact on your CPU.

Initially I’ll provide a single simple effect filter for displaying a Layer as grayscale. In later articles I’ll extend the collection to include more. As always my aim is to make the Layer API simple to use, hiding as much complexity from the caller as possible.

 

In the previous articles we showed how to display a video on one layer, with performance metrics overlayed on the top. I’ll extend this demo slightly further by adding an Effect which will turn the video to grayscale at runtime.

To add an Effect to a Layer you just need to add it to the Layer.Effects collection:

 

protected override void LoadContent()
{
 m_spriteBatch = new SpriteBatch(GraphicsDevice);

 // Define each layer.
 var videoLayer = new VideoLayer(m_graphics.GraphicsDevice, Content.Load<Video>("Animal"), 
true)

 {
 AutoRepeat = true
 };

var statsLayer = new StatsLayer(m_graphics.GraphicsDevice, m_graphics.PreferredBackBufferWidth, m_graphics.PreferredBackBufferHeight, Content.Load<SpriteFont>("Speccy8x8"));

 // Add effects to our layers.
 videoLayer.Effects.Add(new SimpleEffect(Content.Load<Effect>("grayscale")));

 // Create a Layers object, and define the order of the layers to display.
 m_rootLayers = new Layers(m_graphics.GraphicsDevice, m_graphics.PreferredBackBufferWidth, 
 m_graphics.PreferredBackBufferHeight);
 m_rootLayers.Add(videoLayer);
 m_rootLayers.Add(statsLayer);
}

(A SimpleEffect is a lightweight wrapper to XNA’s Effect object. See the documentation for the reasons why I did this, but in short it will make more complicated effects to be created in the future.)

To combine multiple effects together just keep adding to the collection. They will be processed in the order you add them, and can be added to multiple Layers.
Note: If you would like an effect to apply to a collection of Layer objects, then simply apply it to a single Layers object.

Behind the scene the Layer.Draw(...) code will look to see if any effects need to be applied. If there are then it uses a pair of off-screen render targets to apply each effect in turn - XNA does not support applying multiple effect filters ‘out of the box’. The final result is then drawn using the specified SpriteBatch, as in earlier versions of the Layer class.

You can download the full source (including a pre-built sample application showing its usage) from the link below.

DOWNLOAD SOURCE