当使用
GL_FRAMEBUFFER_SRGB
时,开启或关闭都没有效果。我已经尝试过在默认帧缓冲区绑定和离屏FBO绑定时启用
GL_FRAMEBUFFER_SRGB
,但它们都不起作用。
GL_FRAMEBUFFER_SRGB
并不是你所想的那样:它
不会将任何帧缓冲区的
格式从RGB转换为sRGB。只有当帧缓冲区的格式已经指定为
sRGB
时,例如通过将一个内部格式为
GL_SRGB8
或
GL_SRGB8_ALPHA8
的纹理附加为颜色缓冲区到一个FBO上时,
GL_FRAMEBUFFER_SRGB
才会产生任何效果。如果您想要默认帧缓冲区进行sRGB转换,则必须使用特定于窗口系统的API来显式创建具有sRGB支持的PixelFormat/Visual/FBConfig/whatever。请参阅
GL / GLX / WGL_ARB_FRAMEBUFFER_SRGB
扩展规范以了解如何实现。
“然而,如果我指定GL_SRGB作为我绑定为离屏FBO的颜色缓冲区的纹理的内部格式,则可以正常工作。在此情况下,当启用GL_FRAMEBUFFER_SRGB时,片段着色器对纹理的写入会将其从线性空间转换为SRGB空间。”
“是的,这正是它应该工作的方式。GL_FRAMEBUFFER_SRGB启用位只是一种手段,用于禁用通常进行SRGB转换的格式上的转换,而不是相反。”
“我想知道,似乎从FBO到默认帧缓冲区复制时,GL_FRAMEBUFFER_SRGB转换未被应用。”
“让我们看一下最新的OpenGL规范:
OpenGL 4.6核心规范,第18.3.1节“Blitting Pixel Rectangles”(我强调):”
当从读取缓冲区中获取值时,如果启用了
FRAMEBUFFER_SRGB
并且与读取缓冲区对应的帧缓冲附件的
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
的值为
SRGB
(参见第9.2.3节),则红色、绿色和蓝色分量将根据方程式8.17从非线性sRGB颜色空间转换而来。
当写入绘制缓冲区时,大多数模糊操作都会绕过片段管道。唯一影响模糊的片段操作是像素所有权测试、剪裁测试和sRGB转换(参见第17.3.7节)。颜色、深度和模板掩码(参见第17.4.2节)将被忽略。
第17.3.7节“sRGB转换”规定:
如果启用了
FRAMEBUFFER_SRGB
,并且与目标缓冲区对应的帧缓冲附件的
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
的值为
SRGB
(参见第9.2.3节),混合后的R、G和B值将通过[以下公式...]转换为非线性sRGB颜色空间。
请注意,第17.3.7节将明确指出,仅当启用
GL_FRAMEBUFFER_SRGB
时,在写入颜色缓冲区时才会应用从线性到sRGB的转换。
因此,这给我们留下了以下可能性:
源和目标颜色缓冲区都采用标准的非sRGB格式:复制像素值,不会进行任何sRGB转换,无论如何设置GL_FRAMEBUFFER_SRGB
。
源缓冲区采用sRGB格式,目标缓冲区采用非sRGB格式。只有在启用GL_FRAMEBUFFER_SRGB
时才会进行从sRGB到线性的转换。
源缓冲区采用非sRGB格式,目标缓冲区采用sRGB格式。只有在启用GL_FRAMEBUFFER_SRGB
时才会进行从线性到sRGB的转换。
源和目标均采用sRGB格式。只有在启用GL_FRAMEBUFFER_SRGB
时才会进行从sRGB到线性和从线性到sRGB的转换。请注意,此处转换可能会被简化为无操作。这也包括双线性过滤的情况:GL规范不要求对sRGB源进行的双线性过滤在转换后在线性空间中应用,它同样可以在转换之前应用。
现在,故事可以结束了。但实际上并没有结束。随着GL历史的发展,使用sRGB格式的framebuffer blits的行为已经发生了许多变化。
在18.3.1节
OpenGL 4.3 core profile specification中提到:
当从读取缓冲区中获取值时,如果对应于读取缓冲区的framebuffer attachment的FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING的值为SRGB(详见9.2.3节),则红色、绿色和蓝色分量将根据以下方程从非线性sRGB颜色空间转换而来。
[第二段与4.6中引用的内容相同]
这意味着在GL 4.3之前,无论GL_FRAMEBUFFER_SRGB的设置如何,源缓冲区的转换总是会进行,只要它具有sRGB格式。对于目标缓冲区,这个设置仍然是相关的。
现在在
OpenGL 3.3中,没有提到使用sRGB格式时的blitting行为。相关章节是4.3.2“复制像素”,只有如下说明:
引用:
Blit操作绕过片段管道。影响blit的唯一片段操作是像素所有权测试和剪切。
这意味着它也将绕过目标缓冲区的线性到sRGB转换,并且完全不涉及源转换。
此外,驱动程序历史上也忽略了规范,并在涉及sRGB转换时做出了最佳决策。例如,参见
文章“2015年3月OpenGL驱动程序状态和FB sRGB转换”。还有
piglet OpenGL测试套件的这个不错的补丁,讨论问题并呈现一个有点悲伤的结论:
我认为简短的总结是:OpenGL中的sRGB几乎是最糟糕的。:(至少,我曾经交谈过的每个游戏开发者都这么说。呃。
然而,在我的经验中,大多数当前的GL > = 4.4驱动程序按照规定进行转换,因此情况并不那么糟糕了。但我也不会拿我的生命去打赌。