在 QGLFramebufferObject 中使用多重采样的 sRGB 颜色
出于性能原因,我将 2D 和 3D 渲染分开。我每种类型都有两个 QGLFramebufferObject,因为 QGLFramebuffer 不支持以 GL_TEXTURE_2D 作为目标的多重采样,因此一旦绘制到多重采样缓冲区中,它就会被位图传输到“正常”QGLFramebufferObject,其中像素值为解决了。一旦对一种/两种渲染类型完成此操作,缓冲区将用作着色器的纹理输入,该着色器将 2D“层”混合到 3D“层”上。
我应该提到的是,我只能使用 QGLFramebufferObjects 而不是纯 OpenGL 对象,因为我使用 QPainter 来完成所有 2D 工作,而 QPainter 只能在 Qt 类型上进行绘制。
这个过程工作正常,除了抗锯齿太暗,它几乎看起来像一个黑暗的轮廓:
完成后一些研究我发现这归因于使用线性色彩空间而不是 sRGB (此处 和 此处)。因此,我为 FBO blitting 启用了 GL_FRAMEBUFFER_SRGB,将所有 FBO 的纹理目标内部类型设置为 GL_SRGB8_ALPHA8,并在着色器中进行混合计算之前执行 sRGB->Linear (并在最终输出之前再次返回)。
但它不起作用;它要么看起来太亮,要么太暗,要么一模一样。每当整个框架太暗/太亮时,我知道这是因为我错过了色彩空间转换。但当它看起来完全一样时 - 发生了什么事!?
我确实需要有人解释启用 GL_FRAMEBUFFER_SRGB 状态的操作顺序,如果位块传送会影响颜色空间,以及哪些 FBO 需要处于 sRGB 中才能使抗锯齿看起来正确。或者我完全错了,是不是完全有其他原因导致了这些多重采样伪影?
For performance reasons I have separated my 2D and 3D rendering. I have two QGLFramebufferObjects for each type because QGLFramebuffer does not support multisampling with GL_TEXTURE_2D
as a target, so once drawing is done into the multisampled buffer, it is blitted into a 'normal' QGLFramebufferObject where the pixel values are resolved. Once this has been done for one/both of the render types, the buffers are used as texture inputs to a shader that blends the 2D 'layer' onto the 3D one.
I should mention that I'm locked into using QGLFramebufferObjects instead of pure OpenGL objects because I use QPainter for all 2D work, and QPainter can only paint onto Qt types.
This process works fine, except the anti-aliasing is too dark, it almost looks like a dark outline:
After doing some research I discovered this was down to using linear colour space instead sRGB (here and here). So I enabled GL_FRAMEBUFFER_SRGB
for my FBO blitting, set the texture target internal type for my all FBOs to GL_SRGB8_ALPHA8
, and performed sRGB->Linear before the blending calculations in my shader (and back again before the final output).
But it is isn't working; it either looks too bright, too dark, or exactly the same. Whenever the whole frame is too dark/light, I know it's because I've missed a colour-space conversion. But when it looks exactly the same - what is going on!?
I could really do with someone explaining the order of operations for enabling the GL_FRAMEBUFFER_SRGB
state, if blitting will affect the colour space, and which FBOs need to be in sRGB for the anti-aliasing to look correct. Or am I totally wrong, and is it something else entirely that is causing these multisampling artifacts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
直到最后一步,这都是有意义的。
使用 sRGB 色彩空间的图像格式意味着从该纹理进行的纹理访问将自动从 sRGB 色彩空间转换为线性色彩空间。当您从纹理中获取纹素时,这种情况会自行发生。它免费。因此,您根本不必进行任何“sRGB->线性”计算。
同样,当您在渲染到使用 sRGB 色彩空间的图像时启用了 GL_FRAMEBUFFER_SRGB 时,您写入该图像的值将被假定为线性。通过启用 GL_FRAMEBUFFER_SRGB ,您将告诉 OpenGL 将您写入的线性值转换为 sRGB 色彩空间值。这又是免费的,并且可以很好地与混合和抗锯齿配合使用。同样,您不必进行任何手动转换。
所以实际上,您需要做的是确保正确的线性颜色管道。在 sRGB 色彩空间中创建的任何纹理都应使用 sRGB 色彩空间中的图像格式。这将确保您在着色器中从它们获得的值是线性的,因此照明数学实际上有效。当您写入颜色值时,您需要将它们写入 sRGB 颜色空间帧缓冲区,并启用 GL_FRAMEBUFFER_SRGB。这将确保您从着色器写入的线性值正确转换为 sRGB 进行显示。
最后一部分是您需要确保您的显示器也是 sRGB 图像。我对 Qt OpenGL 上下文初始化一无所知,但除非他们在过去 4 年左右的时间里一直忽略 OpenGL,否则应该有一些设置可以用来强制它创建带有 sRGB 色彩空间缓冲区的上下文。
That made sense right up until the final step.
An image format that uses the sRGB colorspace means that texture accesses from that texture will automatically be converted from the sRGB colorspace into a linear colorspace. This happens by itself when you fetch texels from the texture. It's free. So you shouldn't have to do any "sRGB->Linear" computations at all.
Similarly, when you have enabled
GL_FRAMEBUFFER_SRGB
when rendering to an image that uses the sRGB colorspace, values you write to that image are assumed to be linear. By enablingGL_FRAMEBUFFER_SRGB
, what you are telling OpenGL to do is to convert the linear values you write to sRGB colorspace values. This is again free, and works just fine with blending and antialiasing. So again, you shouldn't have to do any manual conversion.So really, what you need to do is ensure a properly linear color pipeline. Any textures of yours that were created in the sRGB colorspace should use image formats in the sRGB colorspace. This will ensure that values you get from them in the shader are linear, so lighting math actually works. When you write color values, you need to write them to an sRGB colorspace framebuffer, with
GL_FRAMEBUFFER_SRGB
enabled. This will ensure that the linear values you write from your shader are properly converted to sRGB for display.The last part is that you need to make sure that your display is an sRGB image as well. I know nothing about Qt OpenGL context initialization, but unless they've been ignoring OpenGL for the last 4 years or so, there should be some setting you can use to force it to create a context with sRGB colorspace buffers.