XNA Shader Programming – Tutorial 9, Post process wiggle

XNA Shader Programming
Tutorial 9 – Post process wiggling
 
Welcome to the 9th tutorial in my Shader Programming series. Today we are going to look at a pretty simple but cool post process effect!
It’s hard to see the result in the image, so you should download the example and take a look at the result so you understand what we are about to make.
 
The source-code and binaries can be found on the bottom of this article.
 
Post processing?
Post processing is really just about applying an effect, or a combination of effects to a image/frame/video to make it look more polished, or to have a certain effect. A post process effect can be looked at as a filter the scene is going trough.
In this case, we are rendering a scene to a texture and applying a wiggling effect to the scene. This makes the scene look like it’s "underwater".
 
To make this happen, we need to modify our texture coordinate vector using some sort of a circle movement, and then use the modified texture coordinate to look up the color in our ColorMapSampler! Take this image for example:
 
The green points are just some example texture coordinates, and based on a timer, we can circulate this point around. Doing this on all texture coordinates will give us the wiggling effect we want!
 
The scene in our example contains a backdrop rendered using SpriteBatch, and a 3D model using our Diffuse shader from Tutorial 2. This scene is rendered into a texture, and that texture is used to render the scene. When rendering it, we apply our post process shader.
 
So, all in all, we got two shaders. One for the in-scene object, and one that will be used as the post process shader.
 
Implementing the shader
The post process shader only needs one shader, the pixel shader. To make the shader dynamic, we will need to implement a timer.

float fTimer;

This timer will be set from the application, and will be used in our sin/cos movment of every texture coordinate, making them move around! 🙂

We also need the ColorMap texture for the shader, containing our scene and is updated every frame.
sampler ColorMapSampler : register(s0);

Now, we got what we need for our shader! Lets take a look at our short pixel shader function:

float4 PixelShader(float2 Tex: TEXCOORD0) : COLOR
{
     Tex.x += sin(fTimer+Tex.x*10)*0.01f;
     Tex.y += cos(fTimer+Tex.y*10)*0.01f;

     float4 Color = tex2D(ColorMapSampler, Tex);
     return Color;
}

This shader simply takes the X and Y component of the current Texture Coordinate, Tex, and moves them around in a circle. the fTimer+Tex.x in the sin loop is there so the coordinate moves based on the timer, pluss the Tex.x to make the circle different for every step in the X-direction. We do the same thing with Y.

If we had used sin(fTimer)/cos(fTimer) in stead of including Tex.x/Tex.y, all texture coordinates would have been moving in the exact same circles. You should try this, and play around with the parameters so you fully understand why we are doing this.

Finally, we will need our technique, named PostProcess:

technique PostProcess
{
     pass P0
     {
          PixelShader = compile ps_2_0 PixelShader();
     }
}

Implementing the shader

It’s pretty simple to add our shader to whatever scene we want! Just render the scene into a texture:

RenderTarget2D renderTarget;
renderTarget = new RenderTarget2D(graphics.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, graphics.GraphicsDevice.DisplayMode.Format);
graphics.GraphicsDevice.SetRenderTarget(0, renderTarget);
// Render our scene
graphics.GraphicsDevice.SetRenderTarget(0, null);
SceneTexture = renderTarget.GetTexture();

Where SceneTexture is a Texture2D object.

Now, we must display the scenetexture, and applying the post process effect:

spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
{
    // Apply the post process shader
    effectPostOutline.Begin();
    {
        effectPostOutline.CurrentTechnique.Passes[0].Begin();
        {
            effectPostOutline.Parameters["fTimer"].SetValue(m_Timer);
            spriteBatch.Draw(SceneTexture, new Rectangle(0, 0, 800, 600), Color.White);
            effectPostOutline.CurrentTechnique.Passes[0].End();
        }
    }
    effectPostOutline.End();
}
spriteBatch.End();

And thats it! We got a very simple, but pretty cool post process effect. You should play around with the shader so implement your own post process effects. Try editing the circle each texture coordinate moves in! U guess you can come up with a quite cool distortion effect 😉

NOTE:
You might have noticed that I have not used effect.commitChanges(); in this code. If you are rendering many objects using this shader, you should add this code in the pass.Begin() part so the changed will get affected in the current pass, and not in the next pass. This should be done if you set any shader paramteres inside the pass.

Good luck!

YouTube – XNA Shader programming, Tutorial 9 – Wiggle post process shading
  

This entry was posted in XNA Shader Tutorial. Bookmark the permalink.

1 Response to XNA Shader Programming – Tutorial 9, Post process wiggle

  1. Юля says:

    Very useful tutorial.Thanx!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.