We said that the transfer function for

**linear sRGB**(sometimes referred to as simply "RGB", or "linear space") is, as the name suggests,

**linear**, while for

**sRGB it is not**. But what is a transfer function? Essentially, it is a simple function which returns the color intensity given a number, in other words it “maps” numbers to color intensities. If we express the intensity as a float for example , we could say the minimum intensity is 0.0 and the maximum is 1.0 (intensities from 0 to 1 are also said to be “normalized”), and if we also express numbers in the same way they will also range from zero to one. The “number” here is what our application uses or image data stores, and the “color intensity” is what your monitor will actually display.

Usually many image formats use only one byte to store a primary color, so numbers range from

**0**(0.0) to

**255**(1.0).

Here's how the transfer function for linear sRGB and sRGB looks like:

The red curve is the sRGB (non-linear) function, while the blue line is linear sRGB.

On the X axis you have the numbers, on the Y axis you have the resulting color intensity.

Now let’s take a closer look at the sRGB (non-linear) function, which is approximately an exponential function with exponent 2.2:

The numbers we are using are the same, 0 to 1, however they map to different intensities. In

**linear sRGB**, “0.5” means 0.5 intensity for example, but in

**sRGB**it means much less, about 0.2 intensity. So (R=0.5, G=0.5, B=0.5) is middle grey in linear sRGB but is a darker color in sRGB.

If you try to visualize how the numbers from 0 to 1 map into that curve adding for ex. 0.1 between samples, you will notice that darker intensities are quite near each other, but as the color intensity gets lighter, they are more distant. These means sRGB has more precision on dark tones than light ones, while in linear sRGB the precision is the same for all intensities.

If we had infinite numbers, precision wouldn’t matter, because you would be able to express every color intensity in either sRGB or linear sRGB. However colors are usually stored in a limited amount of bytes, so precision does matter.

As we said in the previous post, all modern monitors expect the image in sRGB format. So if you set a color byte as "122" they will interpret it as 0.2 and not as 0.5. If you store your image in linear space, you will end up with an image which is darker than you intended it to be.

If you are confused about the reason of all this, don't worry, everything will become clear by the end of this post.

The first thing you may be wondering is: Why sRGB function isn't linear? Why bother mapping numbers with a curve and get 0.5 -> 0.2, when 0.5 -> 0.5 is much easier to understand?

There are basically two reasons for this.

Let's start with the first: Do you remember those old big cathode computer monitors and televisions we used some years ago? For electrical reasons we do not cover here, their input/output curve looks like exactly the sRGB curve. Which means if you tell one of those old monitors: "Okay, here's an input of 0.5" it will display an intesity of about 0.2 instead.

So it is convenient to store images in sRGB to begin with. The number stored in the image is the input to the television/monitor without further conversions or precision loss.

So one reason is compatibilty with these monitors.

However modern monitors do not have this issue and their response is linear, so why not throw away all those old things and store everything in linear format?

Here's the second reason: The human eye happens to better discern dark tones than light tones so giving more precision to dark tones makes a lot of sense. Why waste precision in something your eye cannot discern? That's why modern monitors use sRGB and, despite being linear, "mimic" the behaviour of the old monitors by applying the same curve. The sRGB curve has usually and exponent of 2.2 (the exponent is also called "gamma") so all you have to do to transform from linear to non-linear is applying that gamma or the inverse 1/2.2 to convert back and forth. Modern monitors also allow you to customize this exponent to make images appear generally darker or brighter. (But usually this is not needed, as changing the backlight luminosity is more appropriate in most cases)

Okay that's all for theory! In the next post we will get our hands dirty and write some code in OpenGL and Unity.

Stay tuned!