在具有多重采样的 QGLFramebufferObject 中使用 sRGB 颜色
Posted
技术标签:
【中文标题】在具有多重采样的 QGLFramebufferObject 中使用 sRGB 颜色【英文标题】:Using sRGB colour in QGLFramebufferObject with multisampling 【发布时间】:2012-01-28 23:55:39 【问题描述】:出于性能原因,我将 2D 和 3D 渲染分开。对于每种类型,我有两个 QGLFramebufferObject,因为 QGLFramebuffer 不支持以GL_TEXTURE_2D
作为目标的多重采样,因此一旦在多重采样缓冲区中完成绘图,它就会被传送到解析像素值的“普通”QGLFramebufferObject 中。一旦为一种/两种渲染类型完成此操作,缓冲区将用作着色器的纹理输入,将 2D“层”混合到 3D 层。
我应该提到我被锁定在使用 QGLFramebufferObjects 而不是纯 OpenGL 对象,因为我使用 QPainter 进行所有 2D 工作,而 QPainter 只能绘制到 Qt 类型上。
这个过程效果很好,除了抗锯齿太暗,几乎看起来像一个黑色的轮廓:
在做了一些研究后,我发现这归结为使用线性色彩空间而不是 sRGB(here 和 here)。所以我为我的 FBO blitting 启用了GL_FRAMEBUFFER_SRGB
,将我所有 FBO 的纹理目标内部类型设置为GL_SRGB8_ALPHA8
,并在我的着色器中进行混合计算之前执行 sRGB->Linear(并在最终输出之前再次返回)。
但它不起作用;它要么看起来太亮、太暗,要么看起来完全一样。每当整个画面太暗/太亮时,我知道这是因为我错过了色彩空间转换。但是当它看起来完全一样时——这是怎么回事!?
我真的可以请人解释启用GL_FRAMEBUFFER_SRGB
状态的操作顺序,如果 blitting 会影响色彩空间,以及哪些 FBO 需要在 sRGB 中才能使抗锯齿看起来正确。还是我完全错了,导致这些多重采样伪影的完全是其他原因吗?
【问题讨论】:
【参考方案1】:所以我为我的 FBO blitting 启用了 GL_FRAMEBUFFER_SRGB,将我所有 FBO 的纹理目标内部类型设置为 GL_SRGB8_ALPHA8,并在我的着色器中进行混合计算之前执行 sRGB->Linear(并在最终输出之前再次返回)。
直到最后一步才有意义。
image format that uses the sRGB colorspace 表示从该纹理访问的纹理将自动从 sRGB 颜色空间转换为线性颜色空间。当您从纹理中获取纹素时,这会自行发生。它是免费的。所以你根本不需要做任何“sRGB->线性”计算。
同样,当您在渲染到使用 sRGB 颜色空间的图像时启用GL_FRAMEBUFFER_SRGB
,您写入该图像的值被假定为线性。通过启用GL_FRAMEBUFFER_SRGB
,您告诉 OpenGL 要做的是将您写入的线性值转换为 sRGB 颜色空间值。这又是免费,并且在混合和抗锯齿方面工作得很好。同样,您不必进行任何手动转换。
所以说真的,您需要做的是确保正确的线性颜色管道。您在 sRGB 颜色空间中创建的任何纹理都应使用 sRGB 颜色空间中的图像格式。这将确保您在着色器中从它们获得的值是线性的,因此光照数学确实有效。写入颜色值时,需要将它们写入 sRGB 颜色空间帧缓冲区,并启用 GL_FRAMEBUFFER_SRGB
。这将确保您从着色器写入的线性值正确转换为 sRGB 以供显示。
最后一部分是您需要确保您的 显示器 也是 sRGB 图像。我对 Qt OpenGL 上下文初始化一无所知,但除非他们在过去 4 年左右一直忽略 OpenGL,否则应该有一些设置可以用来强制它使用 sRGB 颜色空间缓冲区创建上下文。
【讨论】:
你说的完全正确,我应该更仔细地阅读超级圣经,它说明了你所说的。然而,Qt 似乎没有为它的视口提供缓冲存储类型的能力——这并不令人印象深刻。不仅如此,Qt 正在渲染它的每个组件具有不同的状态,但这些是针对不同的 SO 问题......最后一件事,如果我试图将我的着色器输出渲染到没有GL_FRAMEBUFFER_SRGB
的缓冲区中,会它出来太亮或太暗?
@cbamber85:如果您的着色器写入线性值并期望它们存储为 sRGB,那么是的,结果会出错。这完全取决于您的着色器期望发生的事情。以上是关于在具有多重采样的 QGLFramebufferObject 中使用 sRGB 颜色的主要内容,如果未能解决你的问题,请参考以下文章