什么是正确的伽马校正函数?

5

在光照通道之后,我目前使用以下公式来进行伽马校正颜色(将它们从RGB转换为sRGB颜色空间):

output = pow(color, vec3(1.0/2.2));

这个公式是否是正确的伽马校正公式?我问这个问题,因为我遇到了一些人说它不是正确的,正确的公式更加复杂,并且涉及2.4次方而不是2.2。我还听说三种颜色R、G和B应该有不同的权重(类似于0.2126、0.7152、0.0722)。

我也很好奇当启用GL_FRAMEBUFFER_SRGB时,OpenGL使用哪个函数。

编辑: 这是Guy Davidson的演讲“你所知道的关于颜色的一切都是错的”中涵盖的许多主题之一。伽马校正函数在这里介绍,但整个演讲与颜色空间,包括sRGB和伽马校正有关。


1
当您想要将通道相加创建亮度Y以创建图像的灰度时,在线性化之后应用0.2126, 0.7152, 0.0722的sRGB加权。如果您仅将线性RGB转换为编码的sRGB或从中转换,则通常不会应用这些系数。 - Myndex
1个回答

10

伽马校正可能具有任何值,但考虑到线性RGB / 非线性sRGB转换,“2.2是一个近似值”,因此您的公式可能被认为既正确又错误: https://en.wikipedia.org/wiki/SRGB#Theory_of_the_transformation

真实的sRGB传输函数基于2.4的伽马系数,并在暗值处出现不连续,如下所示:

float Convert_sRGB_FromLinear (float theLinearValue) {
  return theLinearValue <= 0.0031308f
       ? theLinearValue * 12.92f
       : powf (theLinearValue, 1.0f/2.4f) * 1.055f - 0.055f;
}
float Convert_sRGB_ToLinear (float thesRGBValue) {
  return thesRGBValue <= 0.04045f
       ? thesRGBValue / 12.92f
       : powf ((thesRGBValue + 0.055f) / 1.055f, 2.4f);
}

实际上,在一些使用GLSL的代码中,你可能会发现比2.2和2.4更粗略的近似值,以避免使用昂贵的pow()函数(而是使用x*xsqrt())。这是为了实现最大性能(在旧的图形硬件环境下)和代码简洁,而牺牲了色彩再现度。实际上,这种牺牲并不那么明显,大多数游戏都应用额外的色调映射和用户管理的伽马校正系数,因此结果并不直接符合sRGB标准。
期望使用更正确的公式的有GL_FRAMEBUFFER_SRGB和从GL_SRGB8纹理进行采样(在纹理采样的情况下,更可能是GPU上预计算的查找表而不是真正的公式,因为只有256个值需要转换)。例如,参见GL_ARB_framebuffer_sRGB扩展的注释。
 Given a linear RGB component, cl, convert it to an sRGB component, cs, in the range [0,1], with this pseudo-code:

     if (isnan(cl)) {
         /* Map IEEE-754 Not-a-number to zero. */
         cs = 0.0;
     } else if (cl > 1.0) {
         cs = 1.0;
     } else if (cl < 0.0) {
         cs = 0.0;
     } else if (cl < 0.0031308) {
         cs = 12.92 * cl;
     } else {
         cs = 1.055 * pow(cl, 0.41666) - 0.055;
     }

  The NaN behavior in the pseudo-code is recommended but not specified in the actual specification language.
  sRGB components are typically stored as unsigned 8-bit fixed-point values.
  If cs is computed with the above pseudo-code, cs can be converted to a [0,255] integer with this formula:

     csi = floor(255.0 * cs + 0.5)

这里有另一篇关于OpenGL应用程序中使用sRGB的文章,您可能会觉得很有用:https://unlimited3d.wordpress.com/2020/01/08/srgb-color-space-in-opengl/


谢谢你。这正是我在寻找的。 - janekb04

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接