Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在OpenGL中将SRGB纹理转换为线性_C++_Opengl_Graphics_Colors_3d - Fatal编程技术网

C++ 在OpenGL中将SRGB纹理转换为线性

C++ 在OpenGL中将SRGB纹理转换为线性,c++,opengl,graphics,colors,3d,C++,Opengl,Graphics,Colors,3d,我目前正在尝试在渲染器中正确实现gamma校正。我已经使用glEnableGL_framebuffer_SRGB将我的帧缓冲区设置为SRGB,现在只剩下正确导入SRGB纹理了。我知道三种方法可以做到这一点: 在着色器中转换值:vec3 realColor=powsampledColor,2.2 让OpenGL为我做这件事:glTexImage2D…,,GL_SRGB…,GL_RGB 直接转换值: for (GLubyte* pixel = image; pixel < image + si

我目前正在尝试在渲染器中正确实现gamma校正。我已经使用glEnableGL_framebuffer_SRGB将我的帧缓冲区设置为SRGB,现在只剩下正确导入SRGB纹理了。我知道三种方法可以做到这一点:

在着色器中转换值:vec3 realColor=powsampledColor,2.2 让OpenGL为我做这件事:glTexImage2D…,,GL_SRGB…,GL_RGB

直接转换值:

for (GLubyte* pixel = image; pixel < image + size; ++pixel) 
    *pixel = GLubyte(pow(*pixel, 2.2f) + 0.5f);
现在我尝试使用第三种方法,但它不起作用

它是超慢的,我知道它必须循环通过所有的像素,但仍然。 它使一切看起来完全错误,见下图。 这里有一些图片

无伽马校正: 在片段着色器中采样时的方法2更正 尝试方法3时有些奇怪 所以现在我的问题是方法3有什么问题,因为它看起来与正确的结果完全不同,假设方法2是正确的,如果我认为是的话

我已使用glEnableGL_framebuffer_SRGB将我的帧缓冲区设置为SRGB

这不会将您的帧缓冲区设置为sRGB格式-它仅在帧缓冲区已使用sRGB格式时启用sRGB转换-它们仅使用GL_framebuffer_sRGB enable状态来实际禁用具有sRGB格式的帧缓冲区上的sRGB转换。您仍然必须明确要求windows的默认帧缓冲区为sRGB容量,或者可能幸运地在没有要求的情况下获得一个,但这在实现和平台上会有很大的不同,或者如果渲染到FBO,您必须创建一个sRGB纹理或渲染目标

直接转换值:

for (GLubyte* pixel = image; pixel < image + size; ++pixel) 
      *pixel = GLubyte(pow(*pixel, 2.2f) + 0.5f);
首先,powx,2.2不是sRGB的正确公式-实际公式使用接近0的一个小线性段,其余部分使用2.4的幂-使用2.2的幂只是进一步的近似值

然而,这种方法更大的问题是,GLubyte是一种8位无符号整数类型,范围为[0255],在其上执行pow…,2.2,得到[0196964.7]中的一个值,当转换回GLubyte时,将忽略较高的位并基本上计算模256,因此您将得到非常无用的结果。从概念上讲,您需要255.0*powx/255.0,2.2,这当然可以进一步简化

这里最大的问题是,通过进行这种转换,由于值范围的非线性失真,基本上失去了很多精度。 如果你事先做了这样的转换,你将不得不使用更高精度的纹理来存储线性化的颜色值,比如每通道16位半浮点数,仅仅保持8位的非规则是一个彻底的灾难——这也是为什么GPU在访问纹理时直接进行转换的原因,这样就不必将纹理的内存占用空间放大2倍

因此,我真的怀疑您的方法3是否能够正确导入SRGB纹理。它只会破坏任何忠诚,即使做得对。方法1和方法2没有这个问题,但是方法1只是愚蠢的,因为硬件会免费为你做这件事。所以我真的想知道为什么你甚至会考虑1和3。 我已使用glEnableGL_framebuffer_SRGB将我的帧缓冲区设置为SRGB

这不会将您的帧缓冲区设置为sRGB格式-它仅在帧缓冲区已使用sRGB格式时启用sRGB转换-它们仅使用GL_framebuffer_sRGB enable状态来实际禁用具有sRGB格式的帧缓冲区上的sRGB转换。您仍然必须明确要求windows的默认帧缓冲区为sRGB容量,或者可能幸运地在没有要求的情况下获得一个,但这在实现和平台上会有很大的不同,或者如果渲染到FBO,您必须创建一个sRGB纹理或渲染目标

直接转换值:

for (GLubyte* pixel = image; pixel < image + size; ++pixel) 
      *pixel = GLubyte(pow(*pixel, 2.2f) + 0.5f);
首先,powx,2.2不是sRGB的正确公式-实际公式使用接近0的一个小线性段,其余部分使用2.4的幂-使用2.2的幂只是进一步的近似值

然而,这种方法更大的问题是,GLubyte是一种8位无符号整数类型,范围为[0255],在其上执行pow…,2.2,得到[0196964.7]中的一个值,当转换回GLubyte时,将忽略较高的位并基本上计算模256,因此您将得到非常无用的结果。从概念上讲,您需要255.0*powx/255.0,2.2,这当然可以进一步简化

这里最大的问题是,通过进行这种转换,由于值范围的非线性失真,基本上失去了很多精度。 如果你事先做了这样的转换,你将不得不使用更高精度的纹理来存储线性化的颜色值,比如每通道16位半浮点数,仅仅保持8位的非规则是一个彻底的灾难——这也是为什么GPU在访问时直接进行转换的原因 g纹理,这样就不必将纹理的内存占用空间放大2倍


因此,我真的怀疑您的方法3是否能够正确导入SRGB纹理。它只会破坏任何忠诚,即使做得对。方法1和方法2没有这个问题,但是方法1只是愚蠢的,因为硬件会免费为你做这件事。所以我真的想知道为什么你甚至会考虑1和3。 我只需要正确导入SRGB纹理,图像是否在SRGB颜色空间中?也就是说,文件中的图像数据是sRGB吗?最后,我不认为选项1或选项3有什么意义。选项1会丢失线性过滤,因为它在sRGB中进行过滤,这在数值上是无意义的。选项3会丢失压缩,因为在转换为线性后,您必须对图像使用更大的位深度,否则将丢失像素值的精度。@Nicolas我的意思是,现在我唯一要做的就是正确导入纹理。我很确定它们是SRGB,因为它们是反照率和光泽度贴图,我读到这些纹理通常是SRGB。至于我为什么不使用选项2,这是因为我将所有纹理存储在TextureDarray中以提高性能。但问题是,据我所知,所有层都必须具有相同的内部格式,并且并非所有纹理都是SRGB,就像法线贴图一样。没有人强迫你将所有纹理放在同一个数组纹理中。可以有两个甚至3个阵列纹理。这并不是说着色器不知道何时读取法线贴图和漫反射颜色。整理纹理的目的是减少状态更改的数量;使用多个阵列纹理不会改变这一点,因为您不必在不同的绘制之间实际更改任何状态。@Nicolas我正计划研究使用多个更好的稀疏和无绑定纹理Darray,但我想先做一些工作。然而现在,我认为这是一个很好的时间来检查它,因为不能有不同大小的纹理已经开始让我讨厌了。谢谢你的帮助!我只需要正确导入SRGB纹理,图像是否在SRGB颜色空间中?也就是说,文件中的图像数据是sRGB吗?最后,我不认为选项1或选项3有什么意义。选项1会丢失线性过滤,因为它在sRGB中进行过滤,这在数值上是无意义的。选项3会丢失压缩,因为在转换为线性后,您必须对图像使用更大的位深度,否则将丢失像素值的精度。@Nicolas我的意思是,现在我唯一要做的就是正确导入纹理。我很确定它们是SRGB,因为它们是反照率和光泽度贴图,我读到这些纹理通常是SRGB。至于我为什么不使用选项2,这是因为我将所有纹理存储在TextureDarray中以提高性能。但问题是,据我所知,所有层都必须具有相同的内部格式,并且并非所有纹理都是SRGB,就像法线贴图一样。没有人强迫你将所有纹理放在同一个数组纹理中。可以有两个甚至3个阵列纹理。这并不是说着色器不知道何时读取法线贴图和漫反射颜色。整理纹理的目的是减少状态更改的数量;使用多个阵列纹理不会改变这一点,因为您不必在不同的绘制之间实际更改任何状态。@Nicolas我正计划研究使用多个更好的稀疏和无绑定纹理Darray,但我想先做一些工作。然而现在,我认为这是一个很好的时间来检查它,因为不能有不同大小的纹理已经开始让我讨厌了。谢谢你的帮助!谢谢我忘了它不在0-1范围内,就像在着色器中一样,而是作为整数。我现在觉得这个方法并不完美,但现在还可以。我不使用方法2,因为我将纹理打包到Texture2 Darray中以提高性能,但我会在某个时候切换到使用多个最好是sparce bindless Texture2 Darray,然后我将能够使用方法2。谢谢。我忘了它不在0-1范围内,就像在着色器中一样,而是作为整数。我现在觉得这个方法并不完美,但现在还可以。我没有使用方法2,因为我将纹理打包到Texture2 Darray中以提高性能,但我会在某个时候切换到使用多个最好是sparce bindless Texture2 Darray,然后我将能够使用方法2。