Author Topic: OFFICIAL Q/A: sRGB, gamma, color pickers, linear workflow, ...  (Read 21557 times)

2016-11-09, 15:11:28

Ondra

  • Administrator
  • Active Users
  • *****
  • Posts: 8900
  • Turning coffee to features since 2009
    • View Profile
There is a lot of confusion about the sRGB checkbox in color picker lately and why the same numbers can represent different colors. I will try to explain it.

================================================================================
General intro
================================================================================


Q1: Why is 127 gray sometimes darker and sometimes brighter? Why is 0 240 0 green sometimes greener?
A: Because there are different color spaces, terms such as "red 240 120 50" can mean different actual colors in different color spaces - Adobe RGB, Wide RGB, XYZ, CIERGB, sRGB, ... The reason why we can usually get around 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, leading to wide adoption.

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

Q3: Why even complicate things with gamma?
A: 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. Linear gradient from 0 to 255 in sRGB looks roughly uniform. In '90s nobody was doing 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 resuls for 2D graphics. 8bit non-gamma format would produce bad results because all of its 255steps precision would be wasted in blacks, with no precision left for whites. Also appylying the gamma before sending the image to monitors would be too expensive.

Q4: Why is this a problem in 3ds Max?
A: Because 3ds Max is not color managed, and does not have the concept of color spaces. It internally uses just "RGB" with no information about which space it is - which is 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 need linear data (such as diffuse color) to work properly (linear workflow), while other slots need sRGB data (normal, bump, and displacement) to preserve what user intended in photoshop when he created the map and saved it as sRGB. 3ds Max has no way to specify which space is the input texmap in, or what space it returns results in, which puts the burden of checking this on user. We try to make it easier for users by showing warnings in normal maps, but that is not an ideal solution.

Q5: Why do different textures need to be in different color spaces?
A: I will give 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 the 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. Renderer needs to remove the same gamma curve to get the true linear values.
- Normal map cannot be photographed in reality. It is drawn in photoshop, and the standard here (created in realtime graphics before linear workflow era) is that 127 127 255 saved in jpeg is "no change to normal". If we would remove the same gamma curve as from diffuse texture, then "no change to normal" color would become "huge change in normal", which would screw up look 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 ;)
- When you draw a displacement map in photoshop and use linear gradient from black to white, you expect this to translate to linear slope on the surface. You save this gradient into JPG as linear progression from 0 to 255. If renderer would remove gamma from this and interpret the numbers as height then, the slope would no longer be linear, but gamma-curve shaped.
We would happily do these decisions for you on background, but that is not possible in 3ds Max - textures work as black boxes there, so we cannot determine how should each texture behave, when for example the same texture is instanced in different slots, reused in shader tree, ... Plus there is the issue of legacy workflows - people expect to load normal maps with gamma override - by not requiring gamma override we would break workflows people have because then overriding normal maps to 1.0 gamma would actually produce incorrect result.

================================================================================
Color pickers
================================================================================


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

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

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

Q9: How does Corona color picker work?
A: With sRGB checkbox off, it works exactly like 3ds Max picker, with one exception: we made the sliders perceptually uniform - roughly half of the scale is dark colors, and half is 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 sRGB checked, you can copy colors directly from photoshop/web/... with no brightness change.

Q10: Should the sRGB checkbox be on or off then?
A: There is no "correct" solution. Picking the colors visually works exactly the same in both cases. Only thing that changes are the numerical values. What is better depends on situation. Use sRGB=off for consistency with 3dsmax, sRGB=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!
A: No problem, just leave sRGB=off to have the same behavior as 3ds Max color picker

================================================================================
"I cannot be bothered with technical details" version
================================================================================
When using Corona Color Picker, leave sRGB off. It will behave exactly the same as 3ds max color picker. When you copy RGB values between photoshop and 3ds Max and notice the result is not matching, turn sRGB on first, then copy the values. You can mentally rename the checkbox to "match numbers to photoshop instead of 3dsmax"
« Last Edit: 2016-11-09, 19:07:27 by maru »
Rendering is magic.
Private scene uploader | How to get minidumps for crashed/frozen 3ds Max | Sorry for short replies, brief responses = more time to develop Corona ;)

2016-11-09, 18:02:34
Reply #1

cecofuli

  • Active Users
  • **
  • Posts: 1491
    • View Profile
Thanks so much! Very useful.
If we look the gradient, in 3ds max Color Picker we have less black part.
So, 3ds Max color gradients are displayed in sRGB, right? Because we have, in the Preferences, Enabled Gamma correction.
Corona gradient is always Linear and it isn't affected by the 3ds Max Gamma correction (Preferences)

For this reason, the 128 (that in 3ds Max is in the middle) in Corona has a different position.



PS: you should put this thread as a sticky thread


« Last Edit: 2016-11-09, 19:42:50 by cecofuli »

2016-11-09, 20:34:38
Reply #2

Ondra

  • Administrator
  • Active Users
  • *****
  • Posts: 8900
  • Turning coffee to features since 2009
    • View Profile
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, 3dsmax 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 uniform gradient
Rendering is magic.
Private scene uploader | How to get minidumps for crashed/frozen 3ds Max | Sorry for short replies, brief responses = more time to develop Corona ;)

2016-11-13, 03:45:46
Reply #3

astudio

  • Active Users
  • **
  • Posts: 170
    • View Profile
    • A-Studio
Quote
The biggest problem is that certain map slots need linear data (such as diffuse color) to work properly (linear workflow), while other slots need sRGB data (normal, bump, and displacement)

Quote
* Diffuse and Translucency are loaded with Gamma 2.2, the rest are loaded with Gamma 1.0.
from here: https://corona-renderer.com/forum/index.php/topic,12945.0.html

I'm sorry but I finally confused with all this terms. In simple words, we have a texture after photoshop. Means sRGB. Means gamma 2.2?  Do we need to load this texture with gamma override  1.0 for this linear workflow? Or do we load it automatically and Corona knows what to do?

2016-11-13, 21:56:00
Reply #4

Ondra

  • Administrator
  • Active Users
  • *****
  • Posts: 8900
  • Turning coffee to features since 2009
    • View Profile
The color values you observe and edit in photoshop are saved "as is" into the jpeg - the values do not change, and sRGB color space is assumed. So when you edit values in photoshop, you edit the 2.2g values - so 50% gray will not mean "50% of energy is reflected". 3dsmax removes the gamma from jpeg upon loading, so the 50% grey will become 21% grey in linear color space. If you use 127 127 127 jpeg saved from photoshop in 3dsmax as diffuse texture, it will mean the surface reflectance will be 21%
Rendering is magic.
Private scene uploader | How to get minidumps for crashed/frozen 3ds Max | Sorry for short replies, brief responses = more time to develop Corona ;)

2016-11-14, 02:26:22
Reply #5

astudio

  • Active Users
  • **
  • Posts: 170
    • View Profile
    • A-Studio
Does it mean that my 50%grey photoshop texture I nead to load with gamma override 1.0 to have visually same 50%grey texture in render? (sorry, that I ask for such oversimplified answer).

OR. Do i need to load my texture Automatic (recomended) and 3dsmax will translate it to linear by itself?
« Last Edit: 2016-11-14, 02:31:36 by astudio »

2016-11-14, 10:18:36
Reply #6

Ondra

  • Administrator
  • Active Users
  • *****
  • Posts: 8900
  • Turning coffee to features since 2009
    • View Profile
Does it mean that my 50%grey photoshop texture I nead to load with gamma override 1.0 to have visually same 50%grey texture in render? (sorry, that I ask for such oversimplified answer).

OR. Do i need to load my texture Automatic (recomended) and 3dsmax will translate it to linear by itself?
Asking simple questions is OK, it is actually the best way to resolve this. The answer is: NO. It will look the same when you load in max with default settings (which is removing gamma 2.2)

When you save 127 (50% grey) texture in .jpg and load that in 3dsmax, gamma will be removed. The texture will become 21% grey in linear. You render that, 21% of energy hitting the surface will be diffusely reflected. The surface will render looking 21% grey in linear color space, but then gamma will be applied back, resulting in 50% grey in sRGB that you see in frame buffer, same as your input.

tl;dr:
jpeg on input is always sRGB
pre-linear workflow: load sRGB -> compute in sRGB -> display sRGB -> WRONG result (you cannot compute in sRGB
linear workflow: load sRGB -> remove gamma -> compute in linear -> add gamma -> display sRGB -> CORRECT result

Rendering is magic.
Private scene uploader | How to get minidumps for crashed/frozen 3ds Max | Sorry for short replies, brief responses = more time to develop Corona ;)

2016-11-14, 11:48:16
Reply #7

astudio

  • Active Users
  • **
  • Posts: 170
    • View Profile
    • A-Studio
Thank you. Now it's really clear.

Let's over to displacement map. (I don't ask about normal map for now)

1. As I understand, we load it with gamma override 1.0, if we get it from trusted source like Megascans.
2. If we just draw it in photoshop, or render it from z-buffer and store it as jpg we must load it as sRGB.
3. If we store it in exr we load it with gamma override 1.0.
4. Is there a way to know a gamma of image from unknown sourse (jpg, png, tif).

PS. I have a feeling that I'm the only stupid user in this forum, but I'm sure that it will useful for all of us. The problem is that there are  a lot of different terms for same thing, and same term for different things (especially in optics). I just want to avoid inaccuracies.

2016-11-14, 12:20:46
Reply #8

romullus

  • Global Moderator
  • Active Users
  • ****
  • Posts: 5899
  • Let's move this topic, shall we?
    • View Profile
    • My Models
#2. no, you have to load displacement with gamma 1, if you want that it work in the same way as you painted it in photoshop.
I'm not Corona Team member. Everything i say, is my personal opinion only.

2016-11-14, 14:47:30
Reply #9

maru

  • Corona Team
  • Active Users
  • ****
  • Posts: 9108
  • Marcin
    • View Profile
Remember that one way to find out whether an image, such as displacement or bump map, is loaded with correct gamma or not is simply eyeballing it. Here is an example: https://corona-renderer.com/forum/index.php/topic,12932.msg83635.html#msg83635

2016-11-14, 18:47:45
Reply #10

astudio

  • Active Users
  • **
  • Posts: 170
    • View Profile
    • A-Studio
Ok. 1 & 2 is clear. We need load it with gamma 1.0.
I prepared texture in photoshop with 25, 50, 75% and 100% brightness. With override 1.0 it works correctly, with automatic loading (2.2) - not. Png 8 and 16 bits - the same.
I attach it for proof :).

3. I converted this texture in 32 Bit, saved it as hdr.  Here Juraj wrote: "For full quality disp, use the .exr file, loaded with gamma 1.0 of course. Not rocket science is going on."
I tested it - gamma 1 (or automatic, doesn't matter) gives me the same result as jpg with gamma 2.2. For correct result I need to load it with inversed gamma 0.454545.
What do I miss? How to store image in 32 Bit?

PS. BTW tiff is not working at all. Good to know.

2016-11-16, 14:00:20
Reply #11

astudio

  • Active Users
  • **
  • Posts: 170
    • View Profile
    • A-Studio
Friends, don't leave this thread. It's really important.
What will be conclusion about 32 bit textures? Do I need to override gamma 0.4545? (the test is in previous post)

2016-11-16, 14:29:35
Reply #12

romullus

  • Global Moderator
  • Active Users
  • ****
  • Posts: 5899
  • Let's move this topic, shall we?
    • View Profile
    • My Models
Can you describe how you created/saved exr texture in photoshop? I don't think that PS is best tool for authoring textures in 32 bit depth though.

Edit: i tried to create similar map like in post #10 in photoshop in 16bit mode, then converted image to 32bit and noticed how pixel values get changed after that, probably that means that photoshop has baked gamma during conversion (BTW, it tries to do so when converting from 32bits to lower depth too). After i corrected pixel values manually and resaved it as exr, then it works as displacement map as expected. So likely it's issue with photoshop and not with Corona or exr.
« Last Edit: 2016-11-16, 15:21:58 by romullus »
I'm not Corona Team member. Everything i say, is my personal opinion only.

2016-11-16, 17:52:13
Reply #13

astudio

  • Active Users
  • **
  • Posts: 170
    • View Profile
    • A-Studio
You are right. There are bad news. Photoshop really change RGB at converting to 32 Bit. So what to do? Is PNG 16Bit enough for displacement? Is it better then jpg or it's the same? Or may be there is some special way for converting to 32 Bit?

EDIT: Just some interesting tests in photoshop: Image converted to 32 Bit  has same lightness value in Lab mode, but in RGB mode change RGB values completely. Applying gamma 2.2 makes RGB values closer to original values (not the same), but change completely lightness value in Lab mode. :(
« Last Edit: 2016-11-16, 18:10:29 by astudio »

2016-11-16, 18:07:12
Reply #14

dubcat

  • Active Users
  • **
  • Posts: 460
  • ฅ^•ﻌ•^ฅ meow
    • View Profile
From my experience Photoshop is having a hard time reading negative floating point values.

If you want to get 1:1 result from a displacement bake, you have to save it as 32 bit.
This way you will get negative and positive floating point values. Displacement strength becomes a multiplier and should be left at 1 to get 1:1 result.

Let's say you sculpt a hill that is 20cm high and a pit that is -20cm deep on a plane.
Save it as 32bit.
Apply this displacement map onto a new flat plane.
Leave displacement strength at 1.
This will give give you a hill that is 20cm high and a pit that is -20cm deep.
If you change displacement strength to 2.
The hill will become 40cm high and the pit will be -40cm deep.

This is the proper/accurate way to generate/use displacement maps.
My soul always die a little when I see 3D scan stores sell displacement as 16bit.
             ___
    _] [__|OO|
   (____|___|     https://www.twitch.tv/dubca7 / https://soundcloud.com/dubca7 ( ͡° ͜ʖ ͡°)