c++ - OpenGL framebuffer blitting 在启用时是否考虑 Gamma 校正?

标签 c++ opengl framebuffer gamma

<分区>

这是我的问题,当我加载纹理时,我将它们加载为 SRGB 以将它们转换为线性空间。当我写入窗口系统提供的默认帧缓冲区时,我启用了 GL_FRAMEBUFFER_SRGB,以便写入帧缓冲区会将颜色从线性空间转换为 SRGB 空间。

现在的问题是我正在渲染到一个屏幕外的 FBO 中,然后将其传输到默认的帧缓冲区中。执行此操作时,打开或关闭 GL_FRAMEBUFFER_SRGB 无效。我已经尝试启用 GL_FRAMEBUFFER_SRGB 两者都使用默认帧缓冲区绑定(bind),并且使用屏幕外 FBO 绑定(bind),它们不起作用。

然而,如果我将 GL_SRGB 指定为我绑定(bind)为屏幕外 FBO 的颜色缓冲区的纹理的内部格式,则有效。我假设在这种情况下,当启用 GL_FRAMEBUFFER_SRGB 时,从片段着色器到纹理的写入会将其从线性空间转换为 SRGB 空间。

我想知道,从 FBO 到默认帧缓冲区的 blitting 似乎没有应用 GL_FRAMEBUFFER_SRGB 转换。因为我想在线性空间中工作,直到最终传输到默认帧缓冲区的后缓冲区,所以我如何在将屏幕外 FBO block 传输到默认帧缓冲区时应用转换?我猜想将屏幕外 FBO 采样为纹理并在默认帧缓冲区上渲染四边形会应用 SRGB 转换,但是没有办法使用帧缓冲区 blit 进行此转换吗?

最佳答案

When doing this turning GL_FRAMEBUFFER_SRGB on or off has no effect. I've tried enabling GL_FRAMEBUFFER_SRGBboth with the default framebuffer bound, and with the offscreen FBO bound, they don't work.

GL_FRAMEBUFFER_SRGB与您想象的不同:它不会将任何帧缓冲区格式从RGB 转换为sRGB。 GL_FRAMEBUFFER_SRGB仅当已指定帧缓冲区的格式时才有效sRGB ,例如通过附加纹理 internalFormatGL_SRGB8GL_SRGB8_ALPHA8作为 FBO 的颜色缓冲区。如果你想为默认的帧缓冲区进行 sRGB 转换,你必须使用窗口系统特定的 API 来明确地创建一个 PixelFormat/Visual/FBConfig/whatever with sRGB support。看看 GL / GLX / WGL _ARB_FRAMEBUFFER_SRGB extension spec关于如何做到这一点。

What does work however is if I specify GL_SRGB as the internal format of the texture that I bind as the colour buffer of the offscreen FBO. I'm assuming in this case when GL_FRAMEBUFFER_SRGB is enabled the writes from the fragment shader to the texture convert it from linear space to SRGB space.

是的,这正是它应该如何工作的。 GL_FRAMEBUFFER_SRGB启用位只是一种禁用格式的 SRGB 转换的方法,通常会执行这些转换,而不是相反。

I was wondering, it seems that blitting from the FBO to the default framebuffer the GL_FRAMEBUFFER_SRGB conversion doesn't get applied.

让我们来看看最新的 OpenGL 规范:OpenGL 4.6 core profile specification ,第 18.3.1 节“Blitting Pixel Rectangles”(强调我的):

When values are taken from the read buffer, if FRAMEBUFFER_SRGB is enabled and the value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment corresponding to the read buffer is SRGB (see section 9.2.3), the red, green, and blue components are converted from the non-linear sRGB color space according to equation 8.17.

When values are written to the draw buffers, blit operations bypass most of the fragment pipeline. The only fragment operations which affect a blit are the pixel ownership test, the scissor test, and sRGB conversion (see section 17.3.7). Color, depth, and stencil masks (see section 17.4.2) are ignored

第 17.3.7 节“sRGB 转换”说明:

If FRAMEBUFFER_SRGB is enabled and the value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment corresponding to the destination buffer is SRGB (see section 9.2.3), the R, G, and B values after blending are converted into the non-linear sRGB color space by [formula follows ...]

请注意,第 17.3.7 节将明确说明,在写入颜色缓冲区时,线性到 sRGB 的转换仅在 GL_FRAMEBUFFER_SRGB 时应用。已启用。

所以这给我们留下了以下可能性:

  1. 源和目标颜色缓冲区都有标准的非 sRGB 格式:blit 将复制像素值,无论如何都不会发生 sRGB 转换 GL_FRAMEBUFFER_SRGB已设置。

  2. 源缓冲区为 sRGB 格式,目标缓冲区为非 sRGB 格式。从 sRGB 到线性的转换将会完成当且仅当 GL_FRAMEBUFFER_SRGB已启用。

  3. 源缓冲区为非 sRGB 格式,目标缓冲区为 sRGB 格式。从线性到 sRGB 的转换将完成当且仅当 GL_FRAMEBUFFER_SRGB已启用。

  4. 源和目标都具有 sRGB 格式。从 sRGB 到线性的转换以及从线性到 sRGB 的转换将在且仅当时完成 GL_FRAMEBUFFER_SRGB已启用。请注意,这里的转换可能归结为空操作。这也包括双线性过滤的情况:GL 规范不要求在转换后在线性空间中应用 sRGB 源的双线性过滤,它也可以在转换之前应用。

到这里,故事就可以结束了。但事实并非如此。具有 sRGB 格式的帧缓冲区 blit 的行为在 GL 历史中经历了许多变化。

第 18.3.1 节 OpenGL 4.3 core profile specification状态:

When values are taken from the read buffer, if the value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment corresponding to the read buffer is SRGB (see section 9.2.3), the red, green, and blue components are converted from the non-linear sRGB color space according to equation

[Second paragraph is the same as the previous qoute from 4.6]

这意味着直到 GL 4.3, 缓冲区的转换总是在它具有 sRGB 格式时完成,无论 GL_FRAMEBUFFER_SRGB 的设置如何。使能够。不过,对于目标缓冲区,此设置仍然相关。

现在 OpenGL 3.3 , 没有提到使用 sRGB 格式进行 block 传输的行为。相关部分是 4.3.2“复制像素”,仅说明:

Blit operations bypass the fragment pipeline. The only fragment operations which affect a blit are the pixel ownership test and the scissor.

这意味着它还将绕过目标缓冲区的线性到 sRGB 转换,并且根本不声明源转换。

此外,在 sRGB 转换方面,历史上的驱动程序也没有忽略规范并做了他们认为最好的事情。参见示例 the artice "March 2015 OpenGL drivers status and FB sRGB conversions" .还有this nice patch to the piglet OpenGL test suite谈论问题并提出一个有点悲伤的结论:

I think the short summarys is: sRGB in OpenGL is just about as broken as it possibly can be. :( At least, every game developer I've ever talked to tells me so. Ugh.

然而,根据我的经验,大多数当前的 GL >= 4.4 驱动程序都按照指定的方式进行转换,所以情况不再那么糟糕了。但我也不会赌上性命。

关于c++ - OpenGL framebuffer blitting 在启用时是否考虑 Gamma 校正?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46113577/

相关文章:

c++ - malloc 前面的 (double **) 是什么意思?

c++ - 将 glLoadMatrixf 与我自己的矩阵一起使用

c++ - SDL_GL_SetAttribute 不设置颜色大小

opengl - 请求最新版本的 OpenGL 上下文

c++ - 结构初始化语法

c++ - 传递对模板函数调用运算符重载的引用

linux - 如何使用 linux 帧缓冲区旋转 Qt5 应用程序?

c++ - 附上两张图片到fbo进行mrt渲染

opengl - glClear() 在 Intel HD 4000 (GL 4.0) 上提供 GL_OUT_OF_MEMORY 但在 GeForce (GL 4.2) 上不提供......为什么?

c++ - 网格在我尝试显示时根本不显示