The graphics pipeline from source art to final output is complicated and requires the artist to work in several different colour spaces along the way. In this article, I’ll give a brief overview of colour spaces, and then detail a commonly overlooked area in the texture pipeline where gamma is important. I did write this article originally in 2006. Today this workflow is a common practice.
In next part, I will extend this to The Academy Color Encoding System (ACES) which is a color image encoding system created by hundreds of industry professionals under the auspices of the Academy of Motion Picture Arts and Sciences. ACES allows for a fully encompassing color accurate workflow, with “seamless interchange of high quality motion picture images regardless of source. The direct impact for an Artist is to have a better looking image without having to massage it heavily.
The sRGB Standard
The sRGB colour space is based on the monitor characteristics expected in a dimly lit office, and has been standardised by the IEC (as IEC 61966-1-2). This colour space has been widely adopted by the industry, and is used universally for CRT, LCD and projector displays. Modern 8-bit image file formats (such as JPEG 2000 or PNG) default to the sRGB colour space.
A value in the sRGB colour space is a floating-point triple, with each value between 0.0 and 1.0. Values outside of this range are clipped. An sRGB colour from this [0, 1] interval is commonly encoded as an 8-bit unsigned integer between 0 and 255.
The pivotal fact to remember about sRGB is that it is non-linear. It roughly follows the curve y = x 2.2, although the actual standard curve is slightly more complicated (and will be listed at the end of this article). A graph of sRGB against gamma 2.2 looks as follows:
This mapping has the nice property that more resolution is given to low-luminance RGB values, which fits the human visual model well.
The Gamma Function As An Approximation
As can be seen by the above graph, the sRGB standard is very close to the gamma 2.2 curve. For this reason, the full sRGB conversion function is often approximated with the much simpler gamma function.
Please note that the value associated with the word gamma is the power value used in the function y = xp. Unfortunately gamma is often associated with brightness, which is not exactly what it is doing. The full [0, 1] interval is always mapped back onto the full [0, 1] interval.
What Maths Work In This Colour Space?
In general your lighting pipeline should be done in linear space, so that all lighting is accumulated linearly. This is the approach taken in many film pipeline, and is the only way to ensure that you are being physically correct.
However, assuming that the gamma function approximation is good enough, you can still perform modulate operations. In this case we have some constant A that we wish to modulate our sRGB source data x with, and store the result in sRGB as y. In linear space this would be written as:
y 2.2= A x2.2 = ( A1/2.2 x )2.2
Since we are working only in the [0, 1] interval, we canremove the power from both sides and work in the sRGB space itself. In whichcase:
y = A 1/2.2 x
So if we convert our constants into sRGB, then modulateoperations can still be performed. However, there are only very few operationsthat work this way. Additive operations (which are used in additive lightingmodels, or for alpha-blending) cannot bereformulated to work in a gamma 2.2 space, simply because the space isnon-linear. If you wish to have a correct additive lighting model, then youhave to work in a linear space, which will mean that you need ahigher-precision framebuffer to at least match the low-luminance granularity ofsRGB.
sRGB to linear RGB:rgb (sRGB), RGB (linear RGB)
|R =||r / 12.92||for r <= 0.04045|
|( (r + 0.055)/1.055 )2.4||for r > 0.04045|
|G =||g / 12.92||for g <= 0.04045|
|( (g + 0.055)/1.055 )2.4||for g > 0.04045|
|B =||b / 12.92||for b <= 0.04045|
|( (b + 0.055)/1.055 )2.4||for b > 0.04045|
This is commonly approximated as X = x 2.2 for all channels.
linear RGB to sRGB: RGB (linear RGB), rgb(sRGB)
|r =||12.92 R||for R <= 0.0031308|
|1.055 R 1.0 / 2.4 – 0.055||for R > 0.0031308|
|g =||12.92 G||for G <= 0.0031308|
|1.055 G 1.0 / 2.4 – 0.055||for G > 0.0031308|
|b =||12.92 B||for B <= 0.0031308|
|1.055 B 1.0 / 2.4 – 0.055||for B > 0.0031308|
This is commonly approximated as x = X 1/2.2 for all channels.
Ok, the maths looks interesting but how it affects my renderThe general idea is to have all your texture in linear color space and display every render with a sRGB look up table. By texture i mean any images that are not used to describe data such as displacement map, bump map, normal maps, roughness. In others words your color, diffuse or albedo maps.
For the first example, we will study the effect of this workflow on light transport.
The scene is fairly simple. We have an area light and a plane with a standard phong shader. I have set the intensity of light so we got roughly the same illumination in the red area.
The left picture is rendered as-is with no correction while the picture on the right is rendered with a sRGB look up table ( LUT). As you can see the left picture is overlighted. (intensity around 4000) While the right one behave nicely (with an intensity of 750 only).
Note that even the specular from phong shader looks plausible even if it is an mere approximation of a light source reflection. It looks like the reflection of an area light. Today with all the physcally based shader your shader will reflect directly the shape of the light rather than emulating the light source.
My second example is a simple scene with 2 spheres and a plane. The plane and one of the sphere got a standard shader with only a diffuse term set to a neutral gray. ( O.18 grey) The second sphere is fully reflective to see the environment map.
I used an HDR image from Paul Debevec’s website called beach.hdr to light my scene.
The first test is a render as-is:
As you can see the color of the environement map are more contrast / darker than what we can see in HDR shop. To correct this naturally we will change the exposure but the color will be affected and we will got a more saturated image which is wrong.
If we watch through a sRGB look up table we get this result:
The result this time is what we expected. The color match to what we can see in HDR shop. We can start to work safely because we got the right illumination.
To set a sRGB look up table please refer to your software documentation. For example in maya you will need to set it either un your render view or the viewport.
Just look for this menu :
Working with Textures :
On my next example I am introducing a texture on the grey plane by plug to the diffuse slot an image node. I am keeping the same HDR illumination and we are applying our sRGB look up table.
As you can see the texture is washed out. This doesn’t come from the illumination. This wood texture has been captured with a standard still camera ( Canon 5D in this case ) that work in sRGB colour space. Because we are watching this render with a sRGB look up table, we are infact applying the sRGB colorspace twice on the texture.
To get the correct look on the wood texture you need to cancel the sRGB and convert the texture to the linear color space.
As you can see now our texture is corrected and looks natural.
Converting your texture from sRGB to Linear could be done either outside your renderer ( this is recommended ) or done by the renderer on the fly.
For example in maya you can set the colorspace of your texture by setting the color space input of your file node :
Load a texture
Figure out in which color space the texture have been generated. Set the colorspace in the file node.
Make sure you are viewing your render with a sRGB lookup table.
We just reminded our self how important the linear workflow is to achieve photorealistic render. In the next part, we will push things a bit further and work with ACES color space. ACES color spaces will provide a better accuracy for our color which will improve our render even further. This is a very important step if you want to achieve more natural looking render out of the box.