Understanding sRGB, gamma, color values

The original intention of this guide was to understand what the sRGB checkbox in the Corona Color Picker does. We will do our best to explain here why the same values can sometimes represent different colors, and provide some further general information.

You can also find a "too long; didn't read" version of this guide at the very bottom of this page. 

General intro

Q1: Why is 127 gray sometimes darker and sometimes brighter? Why is 0 240 0 green sometimes greener?
A1: Because there are different color spaces, terms such as "red 240 120 50" can mean different actual colors in those different color spaces - Adobe RGB, Wide RGB, XYZ, CIERGB, sRGB, ... The reason why we can usually get by just using numbers without specifying color space is that the sRGB color space is widely adopted and was set as the default for web graphics.

Q2: Why not just always use sRGB color space then?
A2: Because the sRGB color space is "narrow" and can express only a relatively small subset of all colors, without negative values. It is also non-linear - there is a gamma curve involved - so you cannot add two sRGB colors in rendering (i.e. from 2 lights in the scene) and expect a correct result. You need a linear space for that - this is what the linear workflow is about.

Q3: Why even complicate things with gamma?
A3: Because human vision is highly non-linear - roughly logarithmic. By applying a gamma, sRGB is roughly perceptually uniform - adding 1 to a dark or bright color results in roughly the same increase in brightness. A linear gradient from 0 to 255 in sRGB looks roughly uniform. In the '90s, nobody was doing any rendering (which needs linear color space as opposed to 2D graphics), converting between color spaces would be too expensive, and memory was scarce, so the 8bit gamma-baked sRGB, modelled to match '90s CRT monitors was created to give good visual results for 2D graphics. An 8bit non-gamma format would produce bad results because all of its 255 steps in precision would be wasted in the blacks, with no precision left for whites. Also, applying the gamma before sending the image to monitors would be too expensive.

Q4: Why is this a problem in 3ds Max?
A4: Because 3ds Max is not color managed at all, and does not have the concept of color spaces. Internally, it uses just "RGB" with no information about which space it is in - which is a problem, because that number can represent different colors, and renderers cannot just use sRGB, as explained previously. The biggest problem is that certain map slots (such as diffuse color) need linear data to work properly (linear workflow), while other slots (normal, bump, and displacement) need sRGB data to preserve what the user intended when they created the map in Photoshop and saved it as sRGB. 3ds Max has no way to specify which space the input texmap is in, or what space it returns results in, which puts the burden of checking this onto the user. We try to make it easier for our users by showing warnings for normal maps, but that is still not an ideal solution.

Q5: Why do different textures need to be in different color spaces?
A5: Let's take a look at an example: diffuse color vs. normal/displace map:

- Diffuse color is just a captured surface reflectance (assuming no reflections). The renderer internally has to multiply the diffuse color with incident radiance to produce bounced radiance when calculating GI/direct light. This multiplication will not work if done in sRGB color space, because it is not linear. When you created a photo of your wood/gravel/leaf, your camera added the gamma curve to the image when it was saved as .jpg - because that is what the standard requires. The renderer needs to remove the same gamma curve to get the true linear values.

- A normal map cannot be photographed in reality. It is drawn in Photoshop, and the standard here (created in the "real-time graphics before linear workflow" era) is that 127 127 255 saved in jpeg is "no change to normal". If we removed the same gamma curve as we did with the diffuse texture, then "no change to normal" color would become "huge change to normal", which would screw up the appearance of the model because all normals would be way off. This is really easy to reproduce and I bet it happened to everyone at least once ;)

An example material using a normal map loaded with incorrect gamma. 

Exactly the same normal map is used, only with the "Add gamma to input" checkbox enabled. This instantly makes the rendering correct. The good thing is that Corona will try to catch this kind of error automatically, and warn the user about it by displaying a message upon rendering.

- When you draw a displacement map in Photoshop and use a linear gradient from black to white, you expect this to translate to a linear slope on the surface. You save this gradient into a JPG as a linear progression from 0 to 255. If the renderer removed the gamma from this and interpreted the numbers as height, then the slope would no longer be linear, but gamma-curve shaped.
We would happily make these decisions for you in the background, but that is not possible in 3ds Max - textures work as black boxes there, so we cannot determine how each texture should behave, for example when the same texture is instanced into different slots, reused in a shader tree, etc. Plus there is the issue of legacy workflows - people expect to load normal maps with a gamma override - and by not requiring a gamma override, we would break the established workflows that people have, because then overriding normal maps to 1.0 gamma would actually produce an incorrect result.

If a 0 - 255 gradient is used as a displacement map, it will produce a different curve depending on the gamma it is loaded with.

Color pickers

Q6: Why is this an issue in color pickers?
A6: Because there are exactly the same problems when picking a color as when using a texture - you can think about color pickers as small 1*1 pixel textures, and you need to specify their color space the same way as for textures.

Q7: How does the 3ds Max color picker work?
A7: When gamma is set up properly in 3ds max, the color picker will show linear (no-gamma) sRGB numbers, show a gradient which is linear in linear space, BUT show sRGB (color-mapped) colors on the monitor.

Q8: What is the problem with this?
A8: We identified these problems:
- The color gradient shown on the sliders in the 3ds Max color picker progresses uniformly in linear space, so it progresses non-linearly in the displayed sRGB, so it is perceptually non-uniform. You can see this by how all the blacks are cramped at the very top, and how half of the slider looks completely white.
- You cannot do a direct input of color values from Photoshop, a webpage, etc. Photoshop uses sRGB values, and when you put those values into the 3ds Max inputs, they get interpreted as linear values, resulting in a brighter color. This leads to absurd situations where you would open a texture in Photoshop, pick one if its pixels, write that color into 3ds Max, and get completely different results. Or when putting 127 into the color picker gives a different result from placing a 127 gray jpeg texture into the texture slot.
- The same goes the other way - if you pick color for a material under white lighting, say 255 127 0, then render, then copy the image to Photoshop, the material will have a much different green color value.

RGB 176 39 50 is picked in the Photoshop Color Picker. These values represent an intensive burgundy color.  

Exactly the same RGB values are copied into the Corona Color Picker in 3ds Max with sRGB checkbox disabled (this is the default behavior when using the native 3ds Max color picker!). This results in having a completely different, much more pastel color than what was seen in Photshop. 

Enabling the sRGB checkbox in the Corona Color Picker makes the rendered color consistent with what was selected in Photoshop. Note that the color values remain the same regardless of the sRGB checkbox state. 

Q9: How does the Corona Color Picker work?
A9: With the sRGB checkbox off, it works exactly like the 3ds Max picker, with one exception: we made the sliders perceptually uniform so that roughly half of the scale shows the dark colors, and the other half shows the light colors. When you enable the sRGB checkbox, then nothing changes (displayed color, sliders, ...) except for the numerical values - those are now in sRGB.

This means that with the sRGB checkbox on, you can copy colors directly from Photoshop, the web, etc. with no brightness change.

In the native 3ds Max color picker, blacks only take a very small range of the slider. The Corona Color Picker has a more uniform gradient, which makes it more convenient to use. 

Q10: Should the sRGB checkbox be on or off then?
A10: There is no "correct" solution. Picking the colors visually works exactly the same in both cases. The only thing that changes are the numerical values. What is better depends on situation.

Turn the sRGB checkbox off for consistency with 3ds Max.

Turn the sRGB checkbox on when you need to match Photoshop or web values.

Q11: This is confusing, but I want to use the new color picker because of temperature!
A11: No problem, just leave sRGB=off to have the same behavior as the 3ds Max color picker.

Q12: What color space is Corona Renderer using?

A12: It is using WideRGB color space, which is then displayed as sRGB on your monitor. 

"I cannot be bothered with technical details" version

  • When using the Corona Color Picker, leave the sRGB checkbox off. It will behave exactly the same as the 3ds max color picker. 
  • When you copy RGB values between Photoshop and 3ds Max and notice the result does not match, turn sRGB on first, then copy the values. You can mentally rename the checkbox to "match numbers to Photoshop instead of 3ds Max".

There are 3 different qualities for the slider:

a) Is the slider progression uniform in sRGB or linearRGB?
In Corona it is in sRGB, in Max it is in linearRGB

b) Are the displayed colors in sRGB or linearRGB?
Both in Max and Corona they are in sRGB

c) Are the numbers displayed in sRGB or linearRGB?
In Max it is linearRGB, in Corona it depends on the sRGB checkbox

As you can see, 3ds Max progresses the slider in linearRGB but displays it in sRGB, leading to its non-uniformity (there is almost no black displayed). Corona both progresses and displays it in sRGB, leading to a uniform gradient

Original forum thread: https://corona-renderer.com/forum/index.php?topic=13833.new#new