我是否需要在现代计算机/显示器上对最终颜色输出进行伽玛校正

时间:2014-04-12 04:39:52

标签: opengl graphics rendering gamma

我一直认为我的伽马校正管道应该如下:

  • 将sRGB格式用于(GL_SRGB8_ALPHA8)中加载的所有纹理,因为所有艺术程序都会对其文件进行预伽玛校正。从着色器中的GL_SRGB8_ALPHA8纹理采样时,OpenGL将自动转换为线性空间。
  • 在线性空间中进行所有照明计算,后期处理等。
  • 写入将在屏幕上显示的最终颜色时转换回sRGB空间。

请注意,在我的情况下,最终的颜色写入涉及我从FBO(线性RGB纹理)写入后缓冲区。

我的假设受到挑战,好像我在最后阶段进行了伽马校正,我的颜色比它们应该更亮。我设置了一个纯色,由我的值{255, 106 ,0}绘制,但是当我渲染时,我得到{255, 171 ,0} (通过印刷筛选和颜色挑选确定)。而不是橙色我变黄了。如果我在最后一步 伽马正确,我会得到{255, 106 ,0}的正确值。

根据some resources现代液晶屏幕模仿CRT伽玛。他们总是吗?如果没有,我怎么知道我是否应该伽马正确?我在其他地方出错了吗?


编辑1

我现在已经注意到即使我用光写的颜色是正确的,我使用纹理颜色的地方也不正确(但是如果没有伽马校正,我会更加暗淡)。我不知道这种差异来自何处。


编辑2

在我的纹理而不是GL_RGBA8尝试GL_SRGB8_ALPHA8后,即使在光照计算中使用纹理值(如果我将光的强度减半,输出颜色值为半),一切看起来都很完美)。

我的代码不再考虑任何地方的伽玛校正,我的输出看起来是正确的。

这让我更加困惑,不再需要/使用伽玛校正吗?


编辑3 - 响应datenwolf's answer

经过一些更多的实验后,我对这里的几点感到困惑。

1 - 大多数图像格式都是非线性存储的(在sRGB空间中)

我已经加载了一些图像(在我的例子中是.png和.bmp图像)并检查了原始二进制数据。在我看来,好像图像实际上是在 RGB 颜色空间中,好像我将像素值与图像编辑程序与我在程序中得到的字节数组进行比较,它们完美匹配。由于我的图像编辑器给了我RGB值,这表示存储在RGB中的图像。

我正在使用stb_image.h / .c来加载我的图像并一直加载.png并且在加载时没有看到它对图像进行伽马校正的任何地方。我还在十六进制编辑器中检查了.bmps,并且磁盘上的值与它们匹配。

如果这些图像实际存储在线性RGB空间的磁盘上,我应该如何(以编程方式)知道何时指定图像是在sRGB空间中?是否有某种方法可以查询更具特色的图像加载器可能提供的内容?或者由图像创建者来保存他们的图像作为伽马校正(或不校正) - 意味着建立一个约定并遵循它给定一个项目。我问了几位艺术家,他们都不知道伽马校正是什么。

如果我指定我的图像是sRGB,它们太暗了,除非我最后进行伽马校正(如果使用sRGB监视器输出,这是可以理解的,但请参见第2点)。

2 - "在大多数计算机上,有效扫描输出LUT是线性的!这意味着什么?"

我不确定我能在你的回复中找到这个想法的完成位置。

据我所知,经过实验,我对所有显示器的输出线性值进行了测试。如果我绘制全屏四边形并使用伽马校正的着色器中的硬编码值对其进行着色,则显示器会显示我指定的正确值。

我从你的回答中引用的句子和我的结果会让我相信现代监视器输出线性值(即不模仿CRT伽玛)

我们的应用程序的目标平台是PC。对于这个平台(不包括带有CRT或真正旧显示器的人),对#1进行任何响应是否合理,然后对于#2到伽马正确(即不执行最终RGB) - > sRGB转换 - 手动或使用GL_FRAMEBUFFER_SRGB)?

如果是这样的话,那GL_FRAMEBUFFER_SRGB的平台是什么(或者今天有效使用它的平台),或者是使用线性RGB的监视器真的那么新(假设GL_FRAMEBUFFER_SRGB是2008年推出的)?

-

我和我学校的其他一些图形开发人员谈过,并且从它的声音来看,他们都没有考虑伽马校正,他们没有发现任何不正确的事情(有些甚至没有意识到) 。一个开发人员特别说他在考虑伽玛时得到了不正确的结果,因此他决定不担心伽玛。 我不确定在我的目标平台的项目中该怎么做,因为我在线/看到我的项目有相互矛盾的信息。


编辑4 - 响应datenwolf's updated answer

  

是的,的确如此。如果在信号链中的某处应用非线性变换,但是所有像素值从图像到显示器都未被修改,则该非线性已经预先应用于图像的像素值。这意味着图像已经处于非线性色彩空间中。

如果我正在检查显示器上的图像,您的回复对我来说会有意义。为了确保我很清楚,当我说我正在检查图像的字节数组时,我的意思是我正在检查内存中纹理的数值,而不是屏幕上的图像输出(我做了做点#2)。对我来说,唯一能让我看到你说的是真实的方法就是图像编辑器给我的sRGB空间值。

另请注意,我确实尝试检查显示器上的输出,以及修改纹理颜色(例如,除以一半或加倍),输出显示正确(使用方法测量)我在下面描述。)

  

您是如何测量信号响应的?

不幸的是,我的测量方法比你的方法要粗糙得多。当我说我在我的显示器上进行实验时,我的意思是输出纯色全屏四边形,其颜色在着色器中硬编码为简单的OpenGL帧缓冲区(写入时不进行任何色彩空间转换)。当我输出白色,75%灰色,50%灰色,25%灰色和黑色时,显示正确的颜色。现在,我对正确颜色的解释肯定是错误的。我拍了一个截图然后使用图像编辑程序来查看像素的值是什么(以及视觉评估以确保值有意义)。如果我理解正确,如果我的显示器是非线性的,我需要在将它们呈现给显示设备之前执行RGB-> sRGB转换才能使它们正确。

我不会撒谎,我觉得我在这里有点偏离。我认为我可能会遇到的第二个混淆点(最终的RGB-> sRGB转换)将是一个可调整的亮度设置,默认为我的设备上看起来正确(没有伽马校正)。< / p>

0 个答案:

没有答案