首页 > 解决方案 > sRGB 转换 OpenGL

问题描述

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

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

我很困惑,因为如果我将 sRGB 数据输入到最终将其再次转换为 sRGB 的东西会改变颜色,但事实并非如此。

标签: openglcolor-profilesrgb

解决方案


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

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

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

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

为了解决光照不正确的问题,OpenGL 引入了sRGB 感知功能,因此用户可以明确说明输入图像是在 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]

仅当 OpenGL 已通过使用GL_SRGB8_ALPHA8纹理格式和使用GL_FRAMEBUFFER_SRGBwhile 渲染到屏幕外或窗口缓冲区以这种方式显式配置时,才会执行隐式转换的步骤。整个概念可能难以理解,甚至难以实施

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

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

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

在并非设计为图像查看器的 OpenGL 查看器中支持任意颜色配置文件可能涉及太多复杂性。然而,一些系统定义了几个标准颜色空间来执行系统作曲家的隐式转换——这比使用其特殊的查找表和公式支持任意颜色配置文件要可靠得多。

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


推荐阅读