我有一个渲染系统,我使用多重采样渲染缓冲区绘制到FBO,然后将其blit到具有纹理的另一个FBO,以便解析样本以便在绘制时读取纹理以执行后处理着色后备缓冲区(FBO索引0)。
现在我想获得一些正确的sRGB输出...问题是当我在OS X和Windows上运行它时,程序的行为相当不一致,这也会因机器而异:On使用Intel HD 3000的Windows不会应用sRGB非线性,而是使用Nvidia GTX 670的其他机器。在OS X中的Intel HD 3000上,它也将应用它。
所以这可能意味着我没有在程序中的正确位置设置GL_FRAMEBUFFER_SRGB
启用状态。但是,我似乎无法找到任何实际告诉我什么时候应该启用它的教程,他们只会提到它很容易并且没有性能成本。
我目前没有加载任何纹理,所以我还没有必要处理它们的颜色线性化。
要强制程序不要简单地吐出线性颜色值,我试过的只是注释掉我的glDisable(GL_FRAMEBUFFER_SRGB)
行,这实际上意味着为整个管道启用了这个设置,而我实际上是冗余的强迫它回到每一帧。
我不知道这是否正确。它肯定会对颜色应用非线性化,但我无法判断它是否会被应用两次(这会很糟糕)。当我渲染给我的第一个FBO时,它可以应用伽玛。当我把第一个FBO送到第二个FBO时,它可以做到这一点。为什么不?
我已经拍摄了最终帧的屏幕截图,并将原始像素颜色值与我在程序中设置的颜色进行比较:
我将输入颜色设置为RGB(1,2,3),输出为RGB(13,22,28)。
这似乎是低端的相当多的色彩压缩,让我质疑伽玛是否被多次应用。
我刚刚通过sRGB方程式,我可以验证转换似乎只应用一次,因为线性1/255,2 / 255和3/255确实映射到sRGB 13 / 255,22 / 255和28/255使用等式1.055*C^(1/2.4)+0.055
。鉴于这些低颜色值的扩展是如此之大,如果sRGB颜色变换被多次应用,那么它应该是显而易见的。
所以,我仍然无法确定正确的做法是什么。 glEnable(GL_FRAMEBUFFER_SRGB)
仅适用于最终的帧缓冲区值,在这种情况下,我可以在GL初始化例程中设置它并在以后忘记它吗?
答案 0 :(得分:20)
启用GL_FRAMEBUFFER_SRGB
时,对an sRGB image format图像的所有写入都将假定输入颜色(正在写入的颜色)位于线性颜色空间中。因此,它会将它们转换为sRGB色彩空间。
对sRGB格式的不的图像的任何写入都不应受到影响。因此,如果您正在写入浮点图像,则不会发生任何事情。因此,您应该能够将其打开并保持这种状态;当你渲染到sRGB帧缓冲区时,OpenGL会知道。
通常,您希望尽可能长时间地在线性色彩空间中工作。在后处理之后,只有最终渲染应该涉及sRGB色彩空间。因此,您的多重采样帧缓冲区应该保持线性(尽管您应该为其颜色提供更高的分辨率以保持准确性。使用GL_RGB10_A2
,GL_R11F_G11F_B10F
或GL_RGBA16F
作为最后的手段。)
至于此:
在使用Intel HD 3000的Windows上,它不会应用sRGB非线性
这几乎可以肯定是因为英特尔嘲笑编写OpenGL驱动程序。如果启用GL_FRAMEBUFFER_SRGB
时它没有做正确的事情,那是因为英特尔,而不是你的代码。
当然,也可能是英特尔的驱动程序没有给你一个sRGB图像(如果你渲染到默认的帧缓冲区)。