I have some confusion regarding gamma correction and the output of my shaders. I'll start with the setup, then explain my current understanding of the matter, and finally the question.
Setup
I'm using OpenGL ES 3.2 on Android.
I have a texture (skybox) and an object in the scene. Both are rendered to an off-screen framebuffer that has a texture as color attachment. This texture is then sampled for on-screen rendering.
Skybox shader:
#version 320 es
precision mediump float;
in vec3 o_textureCoords;
out vec4 o_fragColor;
uniform samplerCube u_skyboxTexture;
vec4 srgbToLinear(vec4 srgbColor) {
return vec4(pow(srgbColor.rgb, vec3(2.2)), srgbColor.a);
}
void main() {
o_fragColor = texture(u_skyboxTexture, o_textureCoords); // Left
o_fragColor = srgbToLinear(texture(u_skyboxTexture, o_textureCoords)); // Right
}
Object shader (relevant parts):
#version 320 es
precision mediump float;
const vec3 lightColor = vec3(1.0, 1.0, 1.0);
const vec3 objectColor = vec3(0.4, 0.2, 0.1);
out vec4 o_fragColor;
void main() {
// ...
vec3 light = (ambient + diffuse + specular) * objectColor;
o_fragColor = vec4(light, 1.0);
}
Final shader:
#version 320 es
precision mediump float;
in vec2 o_texCoords;
out vec4 o_fragColor;
uniform sampler2D u_texture;
void main() {
vec4 color = texture(u_texture, o_texCoords);
o_fragColor = color; // Left
o_fragColor = vec4(pow(color.rgb, vec3(1.0 / 2.2)), color.a); // Right
}
Let's consider two cases:
- Left: not concerning myself with colorspace and gamma correction at all
- Right: transforming the texture into linear colorspace and gamma correction at the end
The object color is (0.4, 0.2, 0.1)
. When I type these values into a color picker I get , which looks similar to the rabbit-color on the left.
My Understanding
- Assume images (like the skybox) to be in sRGB space most of the time
- Try to work in linear colorspace as long as possible, and gamma correct at the end
If c
is my color, then because of (1) I should assume that when I retrieve a texel it actually is gamma-corrected (c ^ (1/gamma)
). So to get c
I do (c ^ (1/gamma)) ^ gamma
as in srgbToLinear()
.
Because of (2) I leave my object color as is when shading the object and only apply gamma correction at the very end.
Also, because of gamma correction we can expect the resulting images to look a bit brighter.
Question
With my current understanding I would expect the image on the right to be the correct one. I get that the rabbit should look brighter, but especially when comparing it to what the color picker outputs, I can't help but feel confused about it. Is it simply my expectations that fail me or am I doing something wrong here?