Monday, 12 April 2010
If you have read the article about orange & teal abyss in the Hollywood movies you may wonder how such an effect can be accomplished in games. It is very simple and I will cover it in this entry.
Normally, in the image and photography processing a lot of effects (including mentioned orange & teal) can be achieved by means of editing curves. Typical curves tool in Photoshop or Gimp looks as follows:
It's one of the most powerful tools and is used in many scenarios, eg. enhancing contrast or changing tonal atmosphere.
A curve is a function where arguments are input tones (on the x axis) and the results are output tones (y axis). Normally it is linear (meaning output image doesn't differ from the source one) but to change feeling and atmosphere of the image it is sometimes desirable to change its shape (in many scenarios so called s-curve will do which is presented in the image above). Thus contrast for instance can be enhanced or tonal atmosphere can be altered. Also some special effects can be achieved thanks to that (eg. one can do colour inversion this way). I don't want to cover a theory behind editing curves as there are a lot of tutorials on this subject regarding editing photos in Photoshop and Gimp so now I'm moving to the implementation details.
If we limit our input and output to the range of [0; 1] - i.e. typical colours range - then it is very simple to achieve this in the shader - this function can be passed as a 1D texture. Arguments are u-coordinates, and results are colours. In case we treat all the channels the same way, it will be texture in gray scale. However, it may be sometimes desirable to operate on red, green and blue channels separately - then it will be regular RGB texture. Underneath is the texture I used for achieving effect from the first image:
For each of the channels we compute their value as:
colour.r = tex2D(gradingTex, float2(scene.r, 0.5f)).r;
Where scene is our source image and gradingTex is the function to be used.
All we have to do is to get the pixel from the scene image and multiply each of its component by the value read from the curve texture at the place equal to the each of the channels.
Here are some examples using this simple yet so powerful approach: