10 Post-Processing Effects
Post-processing in shaders involves rendering a scene to a texture, applying a pixel (fragment) shader to it, and then rendering a rectangle that is the same size as the screen with the modified texture on it. Sound fun? Well there are plenty of ways to set up the post processing framework and we won't worry about it here. But once you are set up here are ten post-processing hlsl effects to experiment with.
The 10 Effects
Negative Effect - Single Color Effect - Black or White
Grayscale - Animated Ripple - Zoom - Edge Detection
Simple Blur - Gamma Correction - Checkerboard
Source Code - Download Here
Note the source code was written with illustrative purposes in mind and is not optomized.
Default View
Here is little 3D scene thrown together pretty quickly. It will be used a test/example for the post processing effects.

1) Negative Effect
Our first effect is super simple; it is really just one simple line:
color.rgb = 1 - color.rgb;
And that one line produces the "negative" image below. It's something that really just one line of code can make such a change in the image.

2) Single Color Effect
This effect converts the image to have hues of a single color. It finds the intensity of each pixel using the formula:
Intensity = 0.3R + 0.59G + 0.11B
And then multiplies the intensity by the single color and outputs
it. The color in this example is
(255, 180, 30). Here is the main code:
const float3 luminance = float3(0.3, 0.59, 0.11);
const float3 singleColor = float3(1, 0.7, 0.15);
float4 color = tex2D(screenTextureSampler, input.textureCoordinate);
float4 intensity = dot(color.rgb, luminance);
return float4(intensity * singleColor, 1);

3) Black or White
A simple black or white shader that averages the RGB color of each pixel and sets it black or white based off of predefined cutoff values:
const float minCutOff = 0.3;
const float maxCutOff = 0.85;
float4 color = tex2D(screenTextureSampler, input.textureCoordinate);
float colorAverage = (color.r + color.g + color.b) / 3.0;
if(colorAverage < minCutOff || colorAverage > maxCutOff)
color.rgb = 0;
else
color.rgb = 1;
return color;
Changing the cutoff values can really alter the effect.

4) Grayscale
Even simpler than black or white is using the dot product with a constant float3 to make a grayscale effect:
color.rgb = dot(color.rgb, float3(0.3, 0.59, 0.11));

5) Animated Ripple
This effect uses a timing variable set by the application and ripples the image using sine. It may not be as visible in the static picture but it has a fairly nice effect animated.

6) Zoom
This zoom effects let's you enter a screen coordinate to center the zoom around and a zoom factor. The actual zooming is a translation and multiply:
float2 texOffset = zoomSpotNorm + (input.textureCoordinate * zoomFactorInverse);

7) Edge Detection
An old classic. This edge detection works by finding the differences in intensity of a pixel neighbors above and below and left and right. these two differences are summed and scaled by a factor. (The intensities are found the same as in the single color effect. Here is the edge detection of neighbors:
float3 absoluteDifference = scale * ( abs(up - down) + abs(left - right) );
return float4(absoluteDifference, 1);
Here it is with a scale of 3:

8) Simple Blur
This simple blur samples the pixels around a given pixel and averages them. The efficient way to do this is in two passes, one for the horizontal direction and another for the vertical. The example here just makes a single pass and averages over a 5 x 5 area:

9) Gamma Correction
This applies the formula f(c) = c^(1/Y). Below is an image with gamma set to 3.5.

10) Checkerboard
This may not really count as a post-processing effect, but I like it. Just take the width and height of a square, divide the current texture coordinate by it, and if both are even or odd give one color, else give it another.

