0

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

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

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

混合不好

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

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

我真的可以请人解释启用GL_FRAMEBUFFER_SRGB状态的操作顺序,如果 blitting 会影响色彩空间,以及哪些 FBO 需要在 sRGB 中才能使抗锯齿看起来正确。还是我完全错了,导致这些多重采样伪影的完全是其他原因吗?

4

1 回答 1

1

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

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

使用 sRGB 颜色空间的图像格式意味着从该纹理访问的纹理将自动从 sRGB 颜色空间转换为线性颜色空间。当您从纹理中获取纹素时,这会自行发生。它是免费的。所以你根本不需要做任何“sRGB->Linear”计算。

同样,当您GL_FRAMEBUFFER_SRGB在渲染到使用 sRGB 颜色空间的图像时启用时,您写入该图像的值被假定为linear。通过启用GL_FRAMEBUFFER_SRGB,您告诉 OpenGL 要做的是将您写入的线性值转换为 sRGB 颜色空间值。这又是免费的,并且可以很好地用于混合和抗锯齿。同样,您不必进行任何手动转换。

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

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

于 2012-01-29T00:14:27.010 回答