何时调用glEnable(GL_FRAMEBUFFER_SRGB)?

20

我有一个渲染系统,先使用多重采样的渲染缓冲区(FBO)进行绘图,然后再使用纹理将其复制到另一个FBO中以解析采样并读取纹理,从而在绘制到背景缓冲区(即FBO索引0)时执行后处理阴影。

现在我想获得一些正确的sRGB输出...问题是程序的行为在OS X和Windows上相当不一致,这也取决于计算机:在具有Intel HD 3000的Windows上,它不会应用sRGB非线性度量,但在我的其他Nvidia GTX 670计算机上却会应用。 在OS X上的Intel HD 3000也会应用它。

这可能意味着我没有在程序的正确点设置GL_FRAMEBUFFER_SRGB启用状态。但是,我似乎找不到任何真正告诉我何时应该启用它的教程,他们只是提到它很容易,并且不需要付出性能代价。

我目前没有加载任何纹理,因此我没有必要处理线性化它们的颜色。

为了强制程序不仅仅回显线性颜色值,我尝试注释掉我的glDisable(GL_FRAMEBUFFER_SRGB)行,这实际上意味着此设置在整个管道中都已启用,并且我实际上每帧都多余地强制它重新启用。

我不知道这是否正确。 它确实对颜色应用了非线性度量,但我不能确定这是否被应用了两次(这将是不好的)。 它可以在我渲染到第一个FBO时应用gamma。 它可以在我将第一个FBO复制到第二个FBO时应用gamma。 为什么不呢?

我甚至进行了屏幕截图,比较最终帧的原始像素颜色值与程序中设置的颜色:

我将输入颜色设置为RGB(1,2,3),输出为RGB(13,22,28)。

这似乎是低端颜色压缩很大,并让我怀疑gamma是否被多次应用。

我刚刚仔细研究了sRGB方程,可以确认转换似乎只应用了一次,因为线性的1/255、2/255和3/255确实使用方程1.055*C^(1/2.4)+0.055映射到sRGB中的13/255、22/255和28/255。由于这些低颜色值的扩展非常大,如果sRGB颜色变换被应用多次,那么这应该是显而易见的。

所以,我仍然没有确定正确的做法。在这种情况下,glEnable(GL_FRAMEBUFFER_SRGB)是否只适用于最终帧缓冲区的值?如果是这样的话,我可以在我的GL初始化程序中设置它,然后忘记它吗?

1个回答

27
当启用GL_FRAMEBUFFER_SRGB时,对于sRGB图像格式的所有图像写入都会假定输入颜色(正在写入的颜色)处于线性颜色空间中。因此,它将把它们转换为sRGB颜色空间。
任何写入非sRGB格式图像的操作都不应受影响。因此,如果您要写入浮点图像,则不应发生任何事情。因此,您应该能够只需打开它并保持这种状态;OpenGL将知道您何时正在渲染到sRGB帧缓冲区。
一般来说,您希望尽可能长时间地使用线性颜色空间。仅在后期处理之后,您的最终渲染才涉及sRGB颜色空间。因此,您的多重采样帧缓冲区可能仍然是线性的(尽管您应该为其颜色提供更高的分辨率以保留准确性。使用GL_RGB10_A2GL_R11F_G11F_B10FGL_RGBA16F作为最后的选择)。
至于这个:
在Windows系统上,使用Intel HD 3000显卡时,它将不会应用sRGB非线性。这很可能是因为Intel编写OpenGL驱动程序的能力较差。如果启用GL_FRAMEBUFFER_SRGB后仍未做正确的事情,则是由于Intel而不是您的代码问题。当然,如果您正在渲染到默认帧缓冲区,则也可能是Intel的驱动程序没有提供sRGB图像。

1
好的,事情是这样的。当我在初始化时启用GL_FRAMEBUFFER_SRGB并且在此之后永远不再触碰它时,即使在Windows中使用Intel HD 3000,它也会执行正确的转换。只是似乎需要在更多的代码路径上启用它,而不仅仅是在Nvidia上。 - Steven Lu
你说的很有道理,缓冲区的sRGB格式应该决定是否将sRGB值写入它们。我会测试一下,看看这是否被正确实现,这肯定会让我从每个通道的8位中获得更多的里程碑。我希望多重采样分辨率步骤也能正确执行:之前我遇到过错误的多重采样解析结果,但那时可能是在错误的模式下工作。(请参见此主题http://www.opengl.org/discussion_boards/showthread.php/165081-Multisample-resolve-is-not-gamma-correct-with-FBOs) - Steven Lu

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