sRGB 转换 OpenGL

问题描述

假设我从具有 sRGB 颜色配置文件的 jpg 文件加载纹理,并且在加载时没有转换为线性 RGB。当屏幕上显示 rect 时,我看不到图像有任何问题。颜色与在其中一个编辑器中打开的颜色相同。

问题,由于没有转换,RGB 值仍然在 sRGB 范围内。硬件如何知道不需要转换或者为什么它没有被 GPU 转换。基本上为什么没有发生 XYZ -> sRGB 转换。

我很困惑,因为如果我将 sRGB 数据输入到最终将其再次转换为 sRGB 的内容中会改变颜色,但它不会。

解决方法

首先,OpenGL 默认不做任何颜色转换。 让我们从最小的配置开始,包括输入图像、窗口缓冲区(由 OpenGL 渲染)和监视器。每个可能由不同的色彩空间定义,但在最简单的情况下,它看起来像这样:

[RGB image|sRGB] -> [OpenGL Window Buffer|sRGB] -> [Monitor|sRGB]

默认情况下,显示器配置为使用 sRGB preset,即使是支持更宽颜色范围的显示器,以避免错误的颜色输出。渲染到OpenGL Window Buffer默认不执行任何颜色转换,因此如果输入图像在sRGB色彩空间中,它在OpenGL Window Buffer中将保持不变。 OS Composer 通常只是将 OpenGL Window Buffer 复制到屏幕上 - 这一步也没有暗示颜色转换。所以基本上所有步骤都只是传递输入图像,如果它在 sRGB 色彩空间中,您会看到预期的结果。

现在考虑另一种情况:您正在应用输入图像将纹理映射到启用照明的 3D 对象上。 光照方程仅在线性RGB色彩空间中有意义,因此无需额外配置OpenGL基本上将采用非线性sRGB图像值,将它们作为参数传递给未修改的着色方程并写入结果进入OpenGL Window Buffer,它将被传递到配置为sRGB色彩空间的Monitor。结果将是负担得起的,但在物理上是不正确的。

为了解决光照不正确的问题,OpenGL 引入了sRGB-awareness 特性,以便用户可以明确指出输入图像是在 sRGB 还是线性 RGB 色彩空间中,以及如果 GLSL 程序颜色值的结果应该从线性 RGB 颜色空间隐式转换为非线性 sRGB 颜色空间。所以:

[GLSL Texture Input|sRGB -> linear RGB implicit conversion] ->
 -> [GLSL Lighting Equation|linear RGB] ->
 -> [GLSL output|linear RGB -> sRGB implicit conversion]

只有在使用 GL_SRGB8_ALPHA8 纹理格式并在渲染到屏幕外或窗口缓冲区时使用 GL_FRAMEBUFFER_SRGB 以这种方式显式配置 OpenGL 时,才会执行隐式转换步骤。整个概念might be tricky to understand and even trickier to implement

请注意,在此上下文中,“线性 RGB”实际上是指线性化的 sRGB 色彩空间,因为通常会忽略线性 RGB 的实际含义。这是因为对于颜色数学(照明和其他),重要的是 RGB 值在任何线性色彩空间中的输入和输出上是线性的,但是当谈到隐式 sRGB -> 线性 RGB 和线性 RGB - > sRGB 转换 - 这些显然依赖于 sRGB 和 OpenGL 规范定义的 RGB 值的转换。实际上,有更多的线性 RGB 色彩空间不代表 sRGB 色彩空间。

现在考虑您的 Input Image 不在 sRGB 色彩空间中,而是使用其他一些 RGB 色彩配置文件。 OpenGL 并没有提供太多其他纹理格式,除了线性 RGB 和 sRGB,因此将此类图像正确转换为 sRGB 颜色空间应由图像读取器或通过特殊的 GLSL 程序执行即时颜色空间转换。

现在考虑将 Monitor 配置为非 sRGB 配置文件,如 Adob​​eRGB。在这种情况下,将 sRGB 图像传递到 OpenGL 窗口将产生扭曲的颜色。通过让 Windows 知道您的显示器采用另一种颜色配置文件,您将帮助某些应用程序(如 Photoshop)正确转换颜色,但 OpenGL 对 Windows 中配置的这些颜色配置文件一无所知!它是负责应用颜色配置文件信息以执行适当的颜色转换(通过特殊的 GLSL 程序或通过其他方式)的应用程序。通过在非 sRGB 色彩空间应用程序中使用输入图像,还可以选择执行 non-sRGB -> sRGB -> another non-sRGB 颜色转换或实现 GLSL 程序,该程序将在没有代理 sRGB(或通过代理)的情况下执行颜色转换XYZ) 直接到目标色彩空间,以避免由于瞬态转换而丢失色彩精度信息。

在并非设计为图像查看器的 OpenGL 查看器中支持任意颜色配置文件可能会涉及太多复杂性。但是,某些系统定义了多个标准色彩空间来由系统组合器执行隐式转换 - 这比支持具有特殊查找表和公式的任意颜色配置文件要可靠得多。

例如,macOS 定义了 NSWindow::setColorSpace property,它允许应用程序明确指定填充Window Buffer 的色彩空间,以便系统本身执行必要的转换为实际的监视器颜色配置文件。 Android system defines a similar interface 用于支持与旧的 sRGB 颜色配置文件相比具有扩展颜色范围的新 P3 显示颜色配置文件。然而,这意味着 OpenGL 渲染器实际上知道如何在这个特定的色彩空间中输出结果——这是另一个话题(还有一组额外的 OpenGL 扩展可以帮助开发人员朝这个方向发展)......到目前为止我还没有听说过Windows 中的类似 API,但我可能会错过一些东西。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...