正确的伽玛校正功能是什么?

时间:2020-04-10 10:12:58

标签: opengl colors rendering srgb

当前,在照明通过之后,我使用以下公式对伽玛校正颜色(将其从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使用哪个函数。

1 个答案:

答案 0 :(得分:1)

伽玛校正可能有任何值,但是考虑到线性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);
}

实际上,在某些使用2.0系数而不是2.2和2.4的GLSL代码中,您可能会发现更多近似值,从而避免使用昂贵的pow()x*xsqrt()代替)。这是为了达到最佳性能(在旧的图形硬件的情况下)和代码简单,同时牺牲色彩还原性。实际上,牺牲并不是那么明显,大多数游戏都应用了附加的色调映射和用户管理的伽玛校正系数,因此结果并不直接与sRGB标准相关。

GL_FRAMEBUFFER_SRGBGL_SRGB8纹理的采样期望使用更正确的公式(在纹理采样的情况下,它更可能是在GPU上预先计算的查找表,而不是实际公式,因为只有256值进行转换)。例如,查看对GL_ARB_framebuffer_sRGB extension的评论:

 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/