一、什么是线性颜色空间和伽马颜色空间?
线性颜色空间是指与显示亮度值之间呈线性关系的像素值空间。
伽马(Gamma)颜色空间是指线性颜色空间中的像素值经过伽马校正得到的颜色空间。
之所以使用伽马颜色空间是由于早期CRT显示器的输入电压与显示亮度值之间呈一种非线性关系,如图1所示,这个非线性关系曲线近似为指数函数曲线,这个指数称为Gamma。
为了修正显示效果,在显示前会将图片的像素值做Gamma校正。Gamma校正的表达式如下:
使用伽马颜色空间更便于在显示器中显示。如今的LCD显示器虽然不存在非线性关系的问题,但为了继承这一属性,通常也会模拟这个非线性关系。
二、颜色空间的转换
虽然使用伽马空间便于显示,但是我们在渲染过程中对颜色值进行计算时,却希望使用线性颜色空间。这是因为光的传播是线性的。两束光打到同一个地方,得到的亮度是两束光“颜色”相加,而不是相乘、相减或者其他计算方式。
因此,在渲染过程中,要确定使用的是线性颜色空间,必要时需要把图片从伽马颜色空间转换到线性颜色空间。例如,所有的 JPEG 格式文件都会预校正为 Gamma 值为 2.2 的 Gamma颜色空间中,在渲染时需要转换到线性颜色空间再进行计算。而在显示前,应当将像素值变换到伽马颜色空间。
三、sRGB格式
为了避免繁琐的颜色空间转换,微软和惠普联合制定了一个规范,也就是目前我们最最常用的 Color Profile : sRGB。
所有的现代 GPU 都支持 sRGB 贴图格式。这类格式的图片虽然的像素还是经过 Gamma 校正的,但是文件里还保存了校正的 Gamma 值。但在使用前GPU会进行自动校正,因此使用sRGB格式可以保证 Shader 在访问贴图时,返回的是线性颜色空间下的值。
在显示之前,如果设定了 Frame Buffer 的格式为 sRGB,Shader 只需要直接把计算得到的值写进 FrameBuffer 就好了。GPU 会自动把值做 Gamma 校正,然后再写到 FrameBuffer。