C++ iOS上OpenGL中纹理的sRGB校正

C++ iOS上OpenGL中纹理的sRGB校正,c++,ios,opengl-es,opengl-es-2.0,C++,Ios,Opengl Es,Opengl Es 2.0,我遇到了在中描述的问题,其中第二个颜色渐变被有效地进行了两次gamma校正,从而导致过度渲染和褪色。这部分是因为我使用了sRGB帧缓冲区,但这并不是问题的实际原因 我正在iOS8上的测试应用程序中测试纹理,特别是我目前正在使用PNG图像文件,并使用GLKTextureLoader将其作为立方体贴图加载 默认情况下,纹理不在sRGB空间中处理(它们总是由用于构建纹理的图像编辑软件保存在sRGB空间中) 这样做的结果是,苹果让GLKTextureLoader为您调用glTexImage2D,他们总是

我遇到了在中描述的问题,其中第二个颜色渐变被有效地进行了两次gamma校正,从而导致过度渲染和褪色。这部分是因为我使用了sRGB帧缓冲区,但这并不是问题的实际原因

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

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

这样做的结果是,苹果让GLKTextureLoader为您调用
glTexImage2D
,他们总是使用
GL_RGB8
设置调用它,而对于未来颜色操作的实际正确性,我们必须取消gamma校正,以便在纹理中获得线性亮度值,以便着色器进行采样

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

因此,大多数应用程序的过程只是愉快地将线性颜色正确性抛到窗外,不管怎样,只要忽略gamma校正,在SRGB空间中进行混合。这非常适合《愤怒的小鸟》,因为这是一款没有阴影或混合的游戏,所以在gamma校正的颜色空间中执行所有操作是完全明智的

这就引出了我现在面临的问题。我需要使用
EXT\u sRGB
,GLKit使我可以轻松设置sRGB帧缓冲区,这在运行iOS 7或更高版本的最后3代左右的设备上非常有效。在此过程中,我将解决未修正渲染管道的黑暗和不自然阴影外观。这让我的兰伯特和布林·冯的作品看起来很不错。它允许我将sRGB存储在渲染缓冲区中,这样我就可以进行后期处理,同时利用在该颜色空间中存储缓冲区所提供的改进的感知颜色分辨率

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

因此,我想我可以使用
glTexImage2D
构建纹理加载管道,并使用
GL\u SRGB8
指定在着色器中采样纹理之前,我要对纹理进行gamma取消更正。但是,快速查看GL ES 2.0文档可以发现,GL ES 2.0甚至不支持sRGB

最后我找到了
EXT\u sRGB
spec,它说

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]."
添加第3.7.14节,sRGB纹理颜色转换
如果当前绑定纹理的内部格式为SRGB_EXT或
SRGB_ALPHA_EXT红色、绿色和蓝色组件从
将sRGB颜色空间转换为线性颜色空间,作为中所述过滤的一部分
第3.7.7节和第3.7.8节。任何alpha组件都保持不变。理想的,
实现应在之前对每个样本执行此颜色转换
到筛选,但允许实现执行此转换
过滤后(尽管这种过滤后方法不如
过滤前从sRGB转换)。
从sRGB编码组件cs到线性组件的转换,
cl,如下所示。
{cs/12.92,cs 0.04045
假设cs是[0,1]范围内的sRGB组件。”
因为在为桌面硬件实现游戏引擎时,我从来没有挖掘过这么深的深度(在使用每个通道16位深度或更高的渲染缓冲区时,我认为颜色分辨率的考虑基本上是没有意义的)我对其工作原理的理解尚不清楚,但这一段确实在某种程度上让我放心,如果我要使用
SRGB\u EXT
图像存储格式加载纹理,我也可以吃蛋糕,保留所有8位颜色信息

在OpenGL ES 2.0中,通过这个扩展,我可以使用
SRGB\u-EXT
SRGB\u-ALPHA\u-EXT
,而不是类似的
SRGB
SRGB8-ALPHA

我很抱歉没有提出一个简单的可回答的问题。就让它这样吧:我是在这里找错了树还是我的假设或多或少是正确的?感觉我已经盯着这些规范看了太久了。另一种回答我问题的方法是,如果你能解释一下我尝试时遇到的GLKTextureLoader错误18设置sRGB选项

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

我是不是找错人了,还是我的假设或多或少都错了 对吗

您的假设是正确的。如果支持
GL\u EXT\u sRGB
OpenGL ES扩展,则sRGB帧缓冲区(从线性到伽马校正的sRGB自动转换)和sRGB纹理格式(从中采样时从sRGB自动转换为线性RGB)如果你想在一家公司工作,那么这绝对是一条路要走