在QGLFramebufferObject中使用sRGB颜色并进行多重采样

时间:2012-01-28 23:55:40

标签: c++ qt opengl framebuffer srgb

出于性能原因,我将2D和3D渲染分开了。我为每种类型都有两个QGLFramebufferObjects,因为QGLFramebuffer不支持使用GL_TEXTURE_2D作为目标的多重采样,因此一旦完成多重采样缓冲区的绘制,它就会被分成一个“正常”QGLFramebufferObject,其中像素值被解析。对一个/两个渲染类型完成此操作后,缓冲区将用作着色器的纹理输入,该着色器将2D“图层”混合到3D图层上。

我应该提到我使用QGLFramebufferObjects而不是纯OpenGL对象,因为我使用QPainter进行所有2D工作,而QPainter只能绘制到Qt类型上。

这个过程很好,除了抗锯齿太暗,它几乎看起来像一个黑色轮廓:

Bad blending

在做了一些研究之后,我发现这取决于使用线性颜色空间而不是sRGB(herehere)。所以我为我的FBO blitting启用了GL_FRAMEBUFFER_SRGB,将我所有FBO的纹理目标内部类型设置为GL_SRGB8_ALPHA8,并在我的着色器中进行混合计算之前执行了sRGB-> Linear(并且在最终输出)。

但它不起作用;它要么看起来太亮,太暗,要么完全一样。每当整个画面太暗/太亮时,我知道这是因为我错过了色彩空间转换。但是当它看起来完全一样 - 发生了什么!?

我真的可以解释启用GL_FRAMEBUFFER_SRGB状态的操作顺序,如果blitting会影响颜色空间,并且哪些FBO需要在sRGB中以使抗锯齿看起来正确。或者我完全错了,是否完全导致了这些多重采样工件呢?

1 个答案:

答案 0 :(得分:1)

  

所以我为我的FBO blitting启用了GL_FRAMEBUFFER_SRGB,将我所有FBO的纹理目标内部类型设置为GL_SRGB8_ALPHA8,并在我的着色器中进行混合计算之前执行sRGB-> Linear(并在最终输出之前再次返回)。 / p>

直到最后一步,这才有意义。

image format that uses the sRGB colorspace意味着来自该纹理的纹理访问将自动从sRGB颜色空间转换为线性颜色空间。当您从纹理中获取纹素时,会自行发生这种情况。这是免费。因此,您根本不需要进行任何“sRGB->线性”计算。

同样,当您在渲染到使用sRGB色彩空间的图像时启用GL_FRAMEBUFFER_SRGB时,您写入该图像的值将被假定为线性。通过启用GL_FRAMEBUFFER_SRGB,您告诉OpenGL要做的是将您写入的线性值转换为sRGB色彩空间值。这又是 free ,并且在混合和抗锯齿方面效果很好。所以,你不应该进行任何手动转换。

实际上,您需要做的是确保正确的线性颜色管道。在sRGB颜色空间中创建的任何纹理应使用sRGB颜色空间中的图像格式。这将确保在着色器中从它们获得的值是线性的,因此光照数学实际上是有效的。编写颜色值时,需要将其写入sRGB色彩空间帧缓冲区,并启用GL_FRAMEBUFFER_SRGB。这将确保您从着色器中写入的线性值正确转换为sRGB以供显示。

最后一部分是您需要确保您的显示也是sRGB图像。我对Qt OpenGL上下文初始化一无所知,但除非他们在过去4年左右一直忽略OpenGL,否则应该有一些设置可以强制它用sRGB色彩空间缓冲区创建上下文。