I think theagentd is asking why we need to convert from gamma to linear in the shader (or sRGB sampler), instead of doing it as a preprocess or when loading the texture data. The answer lies in what I said about sRGB being a form of compression. If you perform the linear conversion ahead of time and store the result in a 8-bit-per-channel texture, you lose information. This code sample should provide enough evidence that it's true:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| byte[] colors = new byte[256]; for ( int i = 0; i < colors.length; i++ ) colors[i] = (byte)i;
for ( int i = 0; i < colors.length; i++ ) { byte gammaSrc = colors[i]; float gammaSample = (gammaSrc & 0xFF) / 255.0f; float gammaValue = (float)Math.pow(gammaSample, 2.2);
byte linearSrc = (byte)(gammaValue * 255.0); float linearValue = (linearSrc & 0xFF) / 255.0f;
System.out.println(gammaValue + " - " + linearValue); } |
If you run it and inspect the output, you'll see that every value is different except the two extremes, 0.0 and 1.0. More importantly, sampling the linear-space texture results in the first 20 or so values being clipped at 0.0.
And why the f*ck does monitors expect inverse gamma data? That makes just as much sense as saying that you have to add Pi to each color channel or multiply each channel by 10 or something just because "the monitor expects it". Maybe I'm just being stupid... ._.
They expect inverse gamma data because every piece of visual information ever made, whether it's photographs, textures, videos or even subpixel font antialiasing, has been designed with gamma output in mind. With good reason too. It couldn't have been Pi, or 10x, or anything else, because the gamma curve emulates the light and color response in human eyes. It makes perfect sense and helps computer systems get the most quality out of only 8 bits of information per color channel.