sRGB standard gamma correction and

sRGB standard

Brightness perception of the human eye is not linear, changes in the human eye is more sensitive to see the darker areas: Computer Color IS Broken

Based on this law characteristics of the human eye, the sRGB standard requires the use of an image encoding gamma , the more space to store more dark regions, to maximize the use of bit data indicating brightness or bandwidth

 

Gamma correction ( the Gamma Correction )

Early on, a cathode ray tube (CRT) display is an electronic display device only, however, but a relationship between its input voltage and luminance displayed similar relationship is not linear power law (pow-law) curve, so that the signal is pressure dark

Coincidentally is, sRGB is a standard image encoding gamma brighten power curve, just complementary thereto, so that no further adjustment can allow sRGB image displayed on the CRT in line with reality scene brightness

The subsequent emergence of LCD and plasma displays, in order to ensure compatibility, hardware and then also chose the same nonlinear characteristics of CRT

 

Similar to the sRGB standard encoding gamma (encoding Gamma), since the CRT can be corrected display gamma (display Gamma, standard value γ = 2.2), it is also known as gamma correction (Gamma correction)

 

 

 

 

The significance of rendering

Rendering of light are used in linear space. Because the design is that illumination brightness is 1 to 2 times 0.5

So light, texture and how it? Rendering used in texture generally have two sources, one photograph, one is hand-painted artist

Previously mentioned, the photo is gamma = 1 / 2.2 in. Are also general image processing software working in gamma space, so the artist painting FIG generally be considered to be gamma = 1 / 2.2 of

So, we can often see such a code in the pixel shader:

float4 diff = tex2D(diffuse_texture, uv);
return diff * max(0, dot(light_dir, normal));

这样的代码对吗?不对也对。

说其不对,是因为这里没显式地做gamma校正。做校正的话应该是这样的:

float4 diff = pow(tex2D(diffuse_texture, uv), 2.2f); // 对输入的纹理进行display gamma,转到线性空间
return pow(diff * max(0, dot(light_dir, normal)), 1 / 2.2f); // 对输出进行encoding gamma,再次转回gamma = 1/2.2空间

也就是说,gamma校正的过程就是把输入的texture都转换到线性空间,并把输出的调整到gamma = 1/2.2的空间

说其对,是因为如果diffuse texture如果是sRGB格式的,那么再读取的时候硬件会把它自动转到线性空间

如果render target的texture也是sRGB格式的,在输出的时候硬件也会把它自动转到gamma = 1/2.2空间

所以,如果输入和输出纹理都是sRGB,那么原先那段shader就是正确的。对于不支持sRGB的老硬件,就必须自己做pow了

 

除了渲染,另一个需要注意gamma的地方就是mipmap。如果原texture是gamma = 1/2.2空间的,那么在建立mipmap chain的时候,需要将原texture先转到线性空间,来计算各级mipmap;完成计算后,再将各级mipmap转到gamma = 1/2.2空间

 

总之,计算都要发生在线性空间,所以输入的纹理要先进行display gamma。如果输出的render target是sRGB格式,输出时要进行encoding gamma

输出时encoding gamma,会导致写入color buffer的颜色是非线性的,这样混合就发生在非线性空间中。解决方法是,在中间计算时不要对输出进行encoding gamma,在最后进行一个屏幕后处理操作对最后的输出进行encoding gamma

最佳选择是采用sRGB格式,这样pow是硬件内自动实现,速度更快,代码也简单。鉴于目前很多texture的数据是gamma = 1/2.2的,而纹理格式却被错误地标记成没有sRGB的,所以需要修改它们的格式标记,并重新建立mipmap

 

如果在gamma = 1/2.2的空间中进行着色计算,会造成了渲染出来的游戏总是暗沉沉的(如下右图所示),和真实世界不像

 

参考

klayge:gamma的传说

candycat1992:【图形学】我理解的伽马校正(Gamma Correction)

Unity:LinearRendering-LinearOrGammaWorkflow 

 

Guess you like

Origin www.cnblogs.com/kekec/p/12099861.html