Какова правильная функция гамма-коррекции? - PullRequest
1 голос
/ 10 апреля 2020

В настоящее время я использую следующую формулу для гамма-коррекции цветов (преобразовать их из RGB в цветовое пространство sRGB) после прохода освещения:

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

Является ли эта формула правильной формулой для гамма-коррекция? Я спрашиваю, потому что я столкнулся с несколькими людьми, которые говорили, что это не так, и что правильная формула более сложна и имеет отношение к степени 2.4, а не 2.2. Я также слышал, что три цвета R, G и B должны иметь разные веса (что-то вроде 0,2126, 0,7152, 0,0722).

Мне также любопытно, какую функцию использует OpenGL, когда GL_FRAMEBUFFER_SRGB включен.

1 Ответ

1 голос
/ 10 апреля 2020

Гамма-коррекция может иметь любое значение, но с учетом линейного преобразования 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,0 вместо 2,2 и 2,4, чтобы избежать использования дорогих pow() (вместо них используются x*x и sqrt()). Это делается для достижения максимальной производительности (в контексте старого графического оборудования) и простоты кода, при этом жертвуя воспроизведением цветов. С практической точки зрения, жертва не так уж заметна, и в большинстве игр применяется дополнительное отображение тона и управляемый пользователем коэффициент гамма-коррекции, так что результат не напрямую связан со стандартом sRGB.

GL_FRAMEBUFFER_SRGB и выборка из * Ожидается, что для текстур 1017 * будет использоваться более правильная формула (в случае выборки текстур это скорее предварительно вычисленная таблица поиска на графическом процессоре, чем реальная формула, поскольку для преобразования требуется только 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)

Вот еще одна статья, описывающая использование sRGB в приложениях OpenGL, которая может оказаться полезной: https://unlimited3d.wordpress.com/2020/01/08/srgb-color-space-in-opengl/

...