显示器的对输入的响应曲线是上图下方的y=x^2.2这条曲线.
gamma correction发生在最后frame buffer显示在显示器上之前,即对输出pixel应用y=x^2.2的反函数y=x^(1/2.2)来进行gamma correction.以此来对显示器对输入的相应曲线做抵消,使frame buffer的输出能和最终在显示器上显示的值呈线性关系一一对应.
举个例子,一个pixel的rgb是(0.5, 0, 0),以r通道值0.5为例,进行gamma correction后的值=0.5^(1/)2.2)=0.7297400528,以此作为输入给显示器得到的值=0.7297400528^(2.2)=0.5.
再举个例子,一个pixel的rgb是(0.3, 0, 0),以r通道值0.3为例,进行gamma correction后的值=0.3^(1/)2.2)=0.5785326090,以此作为输入给显示器得到的值=0.5785326090^(2.2)=0.3.
接下来简要说明纹理的SRGB color space.艺术家在DCC里创作图片并导出之后,多数会存储在SRGB color space,即对每一个texle应用了y=x^(1/2.2).我们在读取图片之后,将其转换到linear space,即对其应用y=x^2.2.在OpenGL中对应的internal format:GL_SRGB和GL_SRGBA.对于本身就在linear space的图片,就不需要此操作,比如那些查找表,以及法线纹理.
额外说一下,上图中上方的曲线,y=x^(1/2.2),我们将图片存储到SRGB color space有一个额外的好处,就是在有限的图片精度中存储更多暗部范围的数值.举个例子,0.5^(1/2.2)=0.72974,.再举个例子,0.2^(1/2.2)=0.4811565.
总结一下gamma矫正应用场合有两处,一处是纹理internal format指定为GL_SRGB或GL_SRGBA,在linear space计算光照;一处是光照计算完成之后,再对逐个pixel进行gamma矫正,这里要么在shader里自己手动实现pow(rgb, 1/ 2.2),要么通过图形API内置实现来实现,如glEnable(GL_FRAMEBUFFER_SRGB).