出于性能原因,我将2D和3D渲染分开。对于每种类型,我都有两个QGLFramebufferObjects,因为QGLFramebuffer不支持以GL_TEXTURE_2D
为目标的多重采样,因此一旦完成对多重采样缓冲区的绘制,便将其渗入“正常” QGLFramebufferObject中,在此像素值将被解析。一旦针对一种/两种渲染类型完成了此操作,缓冲区就用作着色器的纹理输入,该着色器将2D“层”混合到3D层上。
我应该提到我被锁定使用QGLFramebufferObjects而不是纯OpenGL对象,因为我将QPainter用于所有2D工作,并且QPainter只能绘制到Qt类型上。
此过程工作正常,除了抗锯齿过深之外,它几乎看起来像是深色轮廓:
经过一些研究,我发现这归因于使用线性色彩空间而不是sRGB(here和here)。因此,我为FBO斑点启用了GL_FRAMEBUFFER_SRGB
,将所有FBO的纹理目标内部类型设置为GL_SRGB8_ALPHA8
,并在着色器中的混合计算之前执行sRGB-> Linear(然后在最终输出之前再次返回)。
但这是行不通的。它看起来太亮,太暗或完全一样。每当整个帧太暗/太亮时,我就知道这是因为我错过了色彩空间转换。但是,当看起来完全一样时-发生了什么!?
我真的可以和某人说明启用GL_FRAMEBUFFER_SRGB
状态的操作顺序,如果闪烁会影响色彩空间,以及哪些FBO必须在sRGB中才能使反走样看起来正确。还是我完全错了,是否是其他原因导致了这些多重采样伪像?
最佳答案
因此,我为GLOB启用了GL_FRAMEBUFFER_SRGB,将所有FBO的纹理目标内部类型设置为GL_SRGB8_ALPHA8,并在着色器中的混合计算之前执行了sRGB-> Linear(然后在最终输出之前再次执行)。
直到最后一步,这才有意义。
image format that uses the sRGB colorspace表示从该纹理访问的纹理将自动从sRGB颜色空间转换为线性颜色空间。当您从纹理中获取纹理像素时,这本身就会发生。免费。因此,您根本不必执行任何“ sRGB-> Linear”计算。
同样,当渲染到使用sRGB色彩空间的图像时启用了GL_FRAMEBUFFER_SRGB
时,假定您写入该图像的值是线性的。通过启用GL_FRAMEBUFFER_SRGB
,您要告诉OpenGL做的就是将您写入的线性值转换为sRGB色彩空间值。这又是免费的,并且可以很好地与混合和抗锯齿配合使用。同样,您不必进行任何手动转换。
因此,实际上,您需要做的是确保正确的线性颜色管线。在sRGB色彩空间中创建的任何纹理都应使用sRGB色彩空间中的图像格式。这将确保您在着色器中从它们获得的值是线性的,因此照明数学实际上是有效的。写入颜色值时,需要将它们写入启用了GL_FRAMEBUFFER_SRGB
的sRGB颜色空间帧缓冲区。这将确保您从着色器写入的线性值正确转换为sRGB以进行显示。
最后一部分是您还需要确保显示器也是sRGB图像。我对Qt OpenGL上下文初始化一无所知,但除非他们在过去大约四年的时间里一直忽略OpenGL,否则应该使用一些设置来强制它使用sRGB颜色空间缓冲区创建上下文。