我需要在片段着色器中进行输出伽马校正吗?

4
当我在片段着色器的main()函数中通过fragColor输出颜色时,颜色分量的强度是解释为线性RGB还是sRGB?换句话说,我是否需要在片段着色器中执行伽马校正,或者这已经被处理好了?
如果没有通用答案而取决于某些OpenGL属性:如何设置此属性?
为避免误解:相应的颜色完全是程序生成的,没有任何纹理或类似物(可能需要输入伽马校正)。
1个回答

4
每个片段着色器的输出都会被路由到帧缓冲区中的特定图像(基于glDrawBuffers状态)。该图像具有格式,该格式定义了相应输出的默认颜色空间解释。
因此,如果您将一个值写入线性RGB格式的图像中,则系统将把该值解释为线性RGB值。如果您将一个值写入sRGB格式的图像中,则系统将把该值解释为已经处于sRGB颜色空间中。因此不会执行任何转换,它将按原样写入纹理中。如果混合处于活动状态,则您编写的sRGB值将在sRGB颜色空间中与图像中的sRGB值混合。

现在,当涉及到写入sRGB颜色空间图像时,通常不希望出现这种行为。如果您有一个线性RGB值,则希望系统将该值转换为sRGB颜色空间(而不是假装它已经是)。同样重要的是,在混合处于活动状态时,您希望在sRGB图像中的值被转换为线性RGB,然后与片段着色器写入的线性值混合,最后再转换回sRGB。否则,混合会产生质量可疑的结果。

为了使所有这些发生,您必须glEnable(GL_FRAMEBUFFER_SRGB)。启用此功能后,颜色空间转换会发生在任何颜色空间为sRGB的图像上写入的任何片段着色器输出上。

默认情况下,此值为禁用状态。

因此,如果您想编写线性RGB值并将其转换为sRGB以进行显示,则必须:

  1. 确保你要写入的帧缓存图像使用 sRGB 色彩空间。对于 FBO,这很简单。但如果你要写入默认帧缓存,则需要在你的 OpenGL 初始化代码中解决这个问题。

  2. 当你希望使用颜色空间转换时,请启用 GL_FRAMEBUFFER_SRGB


当混合处于活动状态时,您希望将sRGB图像中的值转换为线性RGB,然后与片段着色器写入的线性值混合,最后再转换回sRGB。但如果您的目标用户也是Photoshop用户,那么如果在线性RGB中进行混合,则他们会大声抱怨您的混合方式错误。 :-/ - user1118321
你有什么指导可以提供吗?我该如何找出如何使默认的帧缓冲区(由GLUT创建)处于sRGB模式下?glutInitDisplayMode有一个GL_RGBA选项,但没有关于线性或sRGB的说明。我发现可以使用glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)来读取此属性,并且它返回GL_LINEAR,但似乎没有glSetFramebufferAttachmentParameteriv - A. Donda
好的,我刚刚发现有一个常量GLUT_SRGB,但是在FreeGLUT或原始的GLUT文档中都找不到如何使用它的任何文档。 - A. Donda
@A.Donda:这是传递给glutInitDisplayMode的参数。此外,你需要问自己一个问题:你想继续使用文档非常不完善的工具吗?还是你想转向一些由维护者足够关注以保持文档最新,从而使工具可用的东西? - Nicol Bolas
但目前为止:如果我想要在GLUT中编写线性RGB并对屏幕进行伽马校正,则正确的方法是在glutInitDisplayMode中同时使用GLUT_SRGB并在上下文创建后调用glEnable(GL_FRAMEBUFFER_SRGB) - 是这样吗? - A. Donda
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接