我想问一下有关sRGB颜色空间及其在OpenGL中每通道表示8位的问题。深入研究主题之后,我发现将图像存储在sRGB中只是为了补偿监视器所做的相反的伽玛操作,该监视器“模仿”了旧CTR本质上出于兼容性原因所做的操作。人眼具有类似的非线性响应这一事实只是一个巧合,与伽马校正无关(许多令人困惑的文章声称),因为输出将是linear again anyway

假设这种理解是正确的,在OpenGL中,我们具有用于纹理的GL_SRGB8_ALPHA8格式,该格式每个通道具有8位。但是,由于0〜255的范围与线性RGB纹理相同,是否表示要将每个通道的8bit线性纹理转换为sRGB,颜色值将保持不变,并且一个简单的“标志”将告诉OpenGL:看一下0〜255范围不是线性的,所以将它们解释为曲线?
sRGB每通道16位图像(例如16位PNG)如何处理?

最佳答案

范围是相同的。 The values are not

存储前的线性值是浮点数。因此,它们比每通道8位格式的精度更高。

如果将它们存储在linearRGB图像中,则输入范围为[0,1],并将它们均匀映射到[0,255]。

但是,如果您进行sRGB转换,则需要采用[0,1]范围,并通过约2.2的非线性伽玛映射将它们映射到[0,255]。尽管此非线性映射不会神奇地创建更多的值,但它的作用是有效地为您提供范围较高部分而不是较低部分的精度。

在sRGB转换中,输入范围[0.5,1]中的值将映射到[56,255]。这超过了输出范围的75%,而输入范围的50%覆盖了该范围。这样可以更好地表示输入中的较大值。

线性映射会平均失去精度。 sRGB映射在较暗的区域比较亮的区域失去更多的精度。换句话说,与线性映射相比,它在较亮的区域保留了更高的精度。

在内存与视觉质量之间进行权衡时,sRGB的整体效果优于linearRGB每通道8位。

但是,由于0〜255的范围与线性RGB纹理相同,是否表示要将每个通道的8bit线性纹理转换为sRGB,颜色值将保持不变,并且一个简单的“标志”将告诉OpenGL:看一下0〜255范围不是线性的,所以将它们解释为曲线?

这取决于您在说什么操作。

sRGB纹理是一种将其RGB信息存储在sRGB色彩空间中的纹理。但是,假定着色器操作需要的是LinearRGB颜色空间中的数据,而不是sRGB。所以using an sRGB format means that texture fetches will convert the pixels they read from sRGB to linearRGB

使用sRGB格式从片段着色器写入附着FBO的图像可能会或可能不会执行转换。在此,必须使用GL_FRAMEBUFFER_SRGB明确启用转换。其想法是,某些操作将在sRGB色彩空间中生成值(例如,GUI。大多数图像是在sRGB色彩空间中创建的),而其他操作将在linearRGB(正常渲染)中生成值。因此,您可以选择打开或关闭转换。

该转换还允许混合到read sRGB destination pixels, convert them to linear, blend with the incoming linearRGB values, and then convert them back to sRGB for writing

从sRGB图像上传和下载将直接在sRGB色彩空间中写入和读取像素值。

sRGB每通道16位图像(例如16位PNG)如何处理?

那他们呢OpenGL没有每通道16位sRGB格式。

sRGB转换通常通过256项表查找完成。对于每个sRGB值,都有一个预先计算的线性值。

因此,就像其他任何图像格式提供OpenGL不匹配的内容一样,您也必须手动转换它们。

关于opengl - 8位sRGB和OpenGL混淆,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47091421/

10-12 21:58