Gamma校正看起来没有正确校正,这是线性的吗?

时间:2015-04-22 18:29:56

标签: c++ opengl glsl lighting gamma

我想对我的OpenGL灯光实施伽玛校正,但是应用了伽马校正后,我的结果看起来根本不是线性的。

我还发现OpenGL: Gamma corrected image doesn't appear linear与我的问题非常相似,但还没有得到答案,也没有讨论实际的漫反射灯。

作为一个例子,我在线性空间中定义了以下4种浅色:

glm::vec3 lightColors[] = {
    glm::vec3(0.25),
    glm::vec3(0.50),
    glm::vec3(0.75),
    glm::vec3(1.00)
};

将每个光源分开并对漫反射光方程应用基本线性衰减,我得到以下结果:

wrong gamma

这是片段着色器:

void main()
{           
    vec3 lighting = vec3(0.0);
    for(int i = 0; i < 4; ++i)
        lighting += Diffuse(normalize(fs_in.Normal), fs_in.FragPos, lightPositions[i], lightColors[i]);
    // lighting = pow(lighting, vec3(1.0/2.2));
    FragColor = vec4(lighting, 1.0f);
}

我不仅几乎看不到伽马校正灯的亮度差异,伽玛校正也会使衰减失真。就我的理解而言,所有计算(包括衰减)都是在线性空间中完成的,并且通过校正伽玛,监视器应该正确地显示它(因为它再次将其校正为输出)。仅根据灯光颜色,最右边的圆圈应该是左圆圈的4倍,亮度是第二个圆圈的两倍,这似乎并非如此。

仅仅是因为我没有足够的敏感度来感知正确的亮度差异或者出了什么问题吗?

我试过的其他东西只是将精确的灯光颜色输出到默认的帧缓冲区而不进行伽马校正。

gamma output

左边是未矫正的,右边是伽马矫正;红色数字表示来自Photoshop的颜色选择器的RGB强度。我知道Photoshop RGB值并不代表最终输出图像(因为Photoshop会将RGB值读取为监视器输出)。直觉上左图像似乎更好,但是根据RGB强度值,我说我的片段着色器确实正确地对最右边的图像进行了伽马校正。因为这些强度中的每一个都会通过监视器并以正确的强度进入我的眼睛。例如,0.75伽马校正的0.75强度变为0.88 ^ 2.2 = 0.75作为监视器的输出。

正确的形象是否确实正确?而且,与其他图像相比,实际照明是如何关闭的呢?

1 个答案:

答案 0 :(得分:6)

您获得的结果是预期的结果。

您似乎将显示器创建的物理辐射度辐射与人类的感知亮度混淆。后者是非线性的,简单的伽马模型是一种近似的方法。基本上,监视器反转人眼的非线性变换,因此标准(非线性)RGB空间被线性感知 - 使用RGB强度0.5被感知为大约亮度的一半1.0,因此上。

如果您在显示经过伽马校正的灰度级别时将色度计或分光光度计放在显示器上,您实际上会看到0.73步骤将以坎德拉/平方公尺显示白色水平亮度的大约50%(假设你的显示与sRGB模型没有太大偏差,不是使用伽玛2.2,而是使用伽马2.4组合的线性段,其余的只是另一种近似值。

现在的问题是:你到底想要达到什么目的?如果要进行物理精确计算,通常需要在线性颜色空间中工作。但是,一个亮度为另一个亮度的50%的光源并不像人类那么明亮一半,你得到的结果基本上是正确的。

如果您只想拥有一个与感知亮度呈线性关系的色彩空间,则可以完全跳过伽马校正,因为sRGB已经尝试提供了这种格式。如果您需要精确的结果,可能只需要进行一些颜色校准或小的伽玛调整来校正显示器引入的偏差。