在iOS上的OpenGL中对纹理进行sRGB校正

时间:2014-12-28 06:59:29

标签: c++ ios opengl-es opengl-es-2.0

我遇到了this article中描述的问题,其中第二个颜色渐变实际上经过伽马校正两次,导致过度染色和褪色。这部分是我使用sRGB帧缓冲的结果,但这不是问题的实际原因。

我在iOS8上的测试应用中测试纹理,特别是我目前正在使用PNG图像文件并使用GLKTextureLoader将其作为立方体贴图加载。

默认情况下,纹理不会被视为处于sRGB空间中(它们总是由用于构建纹理的图像编辑软件保存)。

这样做的结果是Apple让GLKTextureLoader为你做了glTexImage2D电话,他们总是用GL_RGB8设置调用它,而对于未来色彩操作的实际正确性,我们必须取消校正伽玛,以便在我们的纹理中获取线性亮度值,以便我们的着色器进行采样。

现在我可以看到这样的论点,即大多数移动应用程序都不需要对颜色操作和颜色正确性迂腐,因为应用于涉及颜色混合的高级3D技术。问题的一部分是,使用宝贵的共享设备RAM来存储每个通道大于8位的任何位深度的纹理是不现实的,如果我们读取我们的JPG / PNG / TGA / TIFF和伽玛 - 不正确它的8位sRGB进入8位线性,我们将降低质量。

因此,大多数应用程序的过程只是乐于将线性颜色正确性抛到窗外,并且无论如何都要忽略伽马校正并在SRGB空间中进行混合。这非常适合愤怒的小鸟,因为它是一个没有阴影或混合的游戏,因此在伽马校正的色彩空间中进行所有操作是完全合理的。

所以这让我想到了现在的问题。我需要使用EXT_sRGB和GLKit让我很容易设置一个sRGB帧缓冲区,这对于运行iOS 7或更高版本的最后3代或左代设备非常有用。在这样做时,我解决了未经修正的渲染管道的黑暗和不自然的阴影外观。这使得我的朗伯式和blinn-phong的东西看起来真的很好看。它允许我将sRGB存储在渲染缓冲区中,这样我就可以进行后处理过程,同时利用通过将缓冲区存储在此颜色空间中提供的改进的感知颜色分辨率。

但是现在我开始使用纹理的问题是,我似乎甚至无法使用GLKTextureLoader,因为我在设置SRGB的选项标志时遇到了一个神秘的错误(代码18) GLKTextureLoaderSRGB)。并且它是不可能调试的,因为没有源代码可以使用它。

所以我想我可以使用glTexImage2D构建我的纹理加载管道并使用GL_SRGB8来指定我想要在着色器中对它们进行采样之前对纹理进行伽玛不校正。然而,快速浏览GL ES 2.0文档可以发现GL ES 2.0甚至不具备sRGB感知能力。

最后我找到了EXT_sRGB规范,其中包含

Add Section 3.7.14, sRGB Texture Color Conversion

If the currently bound texture's internal format is one of SRGB_EXT or 
SRGB_ALPHA_EXT the red, green, and blue components are converted from an
sRGB color space to a  linear color space as part of filtering described in
sections 3.7.7 and 3.7.8. Any alpha component is left unchanged.  Ideally,
implementations should perform this color conversion on each sample prior
to filtering but implementations are allowed to perform this conversion
after filtering (though this post-filtering approach is inferior to 
converting from sRGB prior to filtering).

The conversion from an sRGB encoded component, cs, to a linear component,
cl, is as follows.

        {  cs / 12.92,                 cs <= 0.04045
   cl = {
        {  ((cs + 0.055)/1.055)^2.4,   cs >  0.04045

Assume cs is the sRGB component in the range [0,1]."

因为在实现桌面硬件的游戏引擎时我从来没有挖过这么深的东西(我希望在使用每通道16位深度或更高的渲染缓冲区时,颜色分辨率的考虑基本上没有用)我理解它是如何工作的目前尚不清楚,但如果我要使用SRGB_EXT图像存储格式加载纹理,本段确实在某种程度上向我保证我可以拥有我的蛋糕并且也可以保留所有8位颜色信息。

在具有此扩展程序的OpenGL ES 2.0中,我可以使用SRGB_EXTSRGB_ALPHA_EXT而不是来自vanilla GL的类似SRGBSRGB8_ALPHA

我很抱歉没有提出一个简单的回答问题。让它成为这样一个:我在这里咆哮错误的树或者我的假设或多或少是正确的吗?感觉就像我一直盯着这些规格太久了。回答我的问题的另一种方法是,如果你可以了解我在尝试设置sRGB选项时得到的GLKTextureLoader错误18。

似乎还有更多的阅读让我这么做,因为我必须决定是否开始分支我的代码以获得一个使用GL ES 2.0和EXT_sRGB的代码路径,另一个使用GL ES 3.0,这当然看起来通过将glTexImage2D的文档与其他GL版本进行比较,看起来非常有希望,并且看起来比其他版本更接近OpenGL 4,所以我非常希望ES 3能够使移动设备更接近桌面上使用的API。

1 个答案:

答案 0 :(得分:0)

  

我在这里咆哮错误的树或者或多或少是我的假设   正确的吗?

您的假设是正确的。如果支持GL_EXT_sRGB OpenGL ES扩展,则可以使用sRGB帧缓冲区(从线性到伽马校正的sRGB自动转换)和sRGB纹理格式(从sRGB自动转换为线性RGB时),因此如果您想在线性色彩空间中工作,这绝对是最佳选择。

我无法帮助解决GLKit问题,对此不了解。