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

Gamma correction doesn't look properly corrected, is this linear?

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

我还发现 这与我的问题非常相似,但尚未收到答复,也未讨论实际的漫射光。

作为示例,我有以下 4 种线性定义的光色 space:

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

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

这是片段着色器:

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);
}

我不仅几乎看不到伽马校正灯的亮度有任何差异,伽马校正也扭曲了衰减。就我的理解而言,所有计算(包括衰减)都是以线性 space 完成的,并且通过校正伽玛,监视器应该正确显示它(因为它再次将其作为输出取消校正)。仅根据灯光颜色,最右边的圆圈应该是左边圆圈的 4 倍和第二个圆圈的两倍,但事实似乎并非如此。

是我不够敏感,无法感知正确的亮度差异还是哪里出了问题?

我尝试的其他方法只是将准确的光色输出到默认帧缓冲区,不带和带伽马校正。

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

右图真的正确吗?而且,与其他图像相比,实际光线怎么会这么暗?

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

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

如果在显示伽玛校正灰度级别时将色度计或分光光度计放在显示器上,您实际上会看到 0.73 步长将显示 [=24= 中白电平亮度的大约 50% ]^2(假设您的显示与顺便说一句的 sRGB 模型没有太大偏差。不使用 gamma 2.2,而是将线性段与 gamma 2.4 结合用于其余部分,2.2 只是另一个近似值)。

现在的问题是:你到底想达到什么目的?如果您想进行精确的物理计算,通常需要使用线性颜色 space。但是,一个光源的亮度是另一个光源亮度的 50%,给人的感觉却不是另一个光源的一半,你得到的结果基本上是正确的。

如果您只想要一种颜色 space 在感知亮度上呈线性,您可以完全跳过伽马校正,因为 sRGB 已经在尝试提供这种校正。如果您想要准确的结果,您可能只需要进行一些颜色校准或小的伽马调整来纠正显示器引入的偏差。