这样做时打开GL_FRAMEBUFFER_SRGB
或关闭没有效果。我尝试GL_FRAMEBUFFER_SRGB
使用默认的帧缓冲区绑定和屏幕外 FBO 绑定都启用它们,但它们不起作用。
GL_FRAMEBUFFER_SRGB
不像您认为的那样:它不会将任何帧缓冲区格式从 RGB 转换为 sRGB。
GL_FRAMEBUFFER_SRGB
只有当已经指定了帧缓冲区的格式时才会有任何效果sRGB
,例如通过将带有internalFormat
ofGL_SRGB8
或GL_SRGB8_ALPHA8
作为颜色缓冲区的纹理附加到 FBO。如果您想为默认帧缓冲区进行 sRGB 转换,则必须使用窗口系统特定的 API 来显式地创建一个 PixelFormat/Visual/FBConfig/whatever 支持 sRGB。查看有关如何执行此操作的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 core profile specification,第 18.3.1 节“Blitting Pixel Rectangles”(强调我的):
当从读取缓冲区中获取值时,如果
FRAMEBUFFER_SRGB
启用并且
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
对应于读取缓冲区的帧缓冲区附件的值为
SRGB
(参见第 9.2.3 节),则红色、绿色和蓝色分量从非线性 sRGB 转换而来根据公式 8.17 的颜色空间。
当值被写入绘图缓冲区时,blit 操作会绕过大部分片段管道。唯一影响 blit 的片段操作是像素所有权测试、剪刀测试和 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 颜色空间。 ..]
GL_FRAMEBUFFER_SRGB
请注意,第 17.3.7 节将明确在写入颜色缓冲区时,仅在启用时才会应用线性到 sRGB 的转换。
所以这给我们留下了以下可能性:
源颜色缓冲区和目标颜色缓冲区都有标准的 NON-sRGB 格式:blit 将复制像素值,无论如何GL_FRAMEBUFFER_SRGB
设置,都不会发生 sRGB 转换。
源缓冲区具有 sRGB 格式,目标缓冲区具有 NON-sRGB 格式。当且仅当 GL_FRAMEBUFFER_SRGB
启用时,才会完成从 sRGB 到线性的转换。
源缓冲区具有 NON-sRGB 格式,目标缓冲区具有 sRGB 格式。当且仅当 GL_FRAMEBUFFER_SRGB
启用时,才会完成从线性到 sRGB 的转换。
源和目标都具有 sRGB 格式。当且仅当 GL_FRAMEBUFFER_SRGB
启用时,才会完成从 sRGB 到线性和线性到 sRGB 的转换。请注意,转换在这里可能归结为无操作。这也包括双线性过滤的情况:GL 规范不要求在 sRGB 源上的双线性过滤在转换后应用于线性空间,它也可以在之前应用。
现在,故事可能到此为止了。但事实并非如此。具有 sRGB 格式的帧缓冲区 blit 的行为在 GL 历史中经历了许多变化。
第 18.3.1 节OpenGL 4.3 核心配置文件规范确实指出:
当从读缓冲区中取值时,如果
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
对应于读缓冲区的帧缓冲区附件的值为
SRGB
(见 9.2.3 节),则红、绿、蓝分量根据非线性 sRGB 颜色空间转换而来方程
[第二段与 4.6 中的前一段相同]
这意味着直到 GL 4.3,源缓冲区的转换总是在它具有 sRGB 格式时完成,无论GL_FRAMEBUFFER_SRGB
启用的设置如何。但是,对于目标缓冲区,此设置仍然是相关的。
现在在OpenGL 3.3中,没有提到使用 sRGB 格式进行 blitting 的行为。相关部分是 4.3.2 “复制像素”,仅说明:
Blit 操作绕过片段管道。唯一影响 blit 的片段操作是像素所有权测试和剪刀。
这意味着它还将绕过目标缓冲区的线性到 sRGB 转换,并且根本不声明源转换。
也不是说驱动程序在历史上也忽略了规范,并在 sRGB 转换方面做了他们认为最好的事情。例如,请参阅文章“2015 年 3 月 OpenGL 驱动程序状态和 FB sRGB 转换”。小猪 OpenGL 测试套件也有一个不错的补丁,它讨论了一些问题并提出了一个有点悲伤的结论:
我认为简短的总结是: OpenGL 中的 sRGB 几乎已经损坏了。:( 至少,我曾经与之交谈过的每个游戏开发者都这样告诉我。呃。
但是,根据我的经验,大多数当前的 GL >= 4.4 驱动程序都会按照指定的方式进行转换,因此情况不再那么糟糕了。但我也不会赌上我的生命。