颜色空间

为什么现代显示器还保留了Gamma解码

  现在的液晶显示器依然保留了2.2次方的解码gamma校正。但这并不是什么历史遗留问题,也不是因为CRT的物理特性,而是现代数据编码上实实在在的需求。

  对物理线性的颜色编码做0.45次方的gamma校正,目的是为了让颜色编码的亮度分级与人眼主观亮度感受线性对应。这样在相同的数据位数下,图像数据可以保留更多人眼敏感的信息。以8位色为例:由于人眼对暗色调更加敏感,那就对物理线性的颜色做0.45次方的处理,也就是编码gamma。校正完成后,相当于使用了0~128的范围来表达原来与物理强度保持线性时0~55的亮度变化。

  因此,显示器做解码gamma的目的是为了让便于保存和传输的颜色编码变回物理线性的形式,以便人眼观察显示器时能得到与观察现实世界时相近的感受。

 

美术制作标准

  在美术制作过程中并不是所有贴图输出的都是在Linear空间下,像颜色贴图为了能够让人肉眼判断颜色的区别所有一般都是sRGB的存储。其实也就是我们需要通过肉眼来区分颜色信息的贴图要储存为sRGB,其他的通道图没有颜色信息的都是储存为Linear。

sRGB:Base Color固有色贴图,Emission自发光贴图

Linear:Metallic金属度贴图,Roughness粗糙度贴图,Smoothness光滑度贴图

Normal法线贴图是不需要关注在哪个色彩空间下的。

 

硬件要求

线性空间需要图形API的硬件支持,在移动平台下开发,安卓设备需要支持OpenGL3.0,iOS设备需要支持Metal特性。

sRGB Frame Buffer 和 sRGB Sampler

 

透明度偏差 

直接对透明通道进行Gamma校正或者在Shader中校正,并不能让线性空间和Gamma空间的半透明效果保持一致。

主要原因是线性空间和Gamma空间的AlphaBlend计算公式不一样。

例如:Blend SrcAlpha OneMinusSrcAlpha

Gamma空间下的混合公式:color = src * srcAlpha + dest * OneMinusSrcAlpha

Linear空间下的混合公式:color = (src^2.2 * srcAlpha + dest^2.2 * OneMinusSrcAlpha) ^ (1/2.2);

说明:dest是屏幕FrameBuffer。 屏幕FrameBuffer是gamma数值,混合时需要矫正为线性。

注意:在Unity引擎中,如果勾选了sRGB的贴图是RGBA格式,在sRGB Sampler采样的时候并不会对Alpah通道做线性校正。在线性空间做Alpha Blend混合时,也会在线性空间计算混合。 

 

透明度偏差解决方案

1. URP可编程渲染管线内,UI相机以Gamma空间渲染

2. 后处理方法解决,也可以考虑直接渲染到RT上来优化

3. 美术在线性空间下制作半透明的美术资源

 

终极解决方案

https://cmwdexint.com/2019/05/30/3d-scene-need-linear-but-ui-need-gamma/

 

参考:

https://zhuanlan.zhihu.com/p/66558476

https://zhuanlan.zhihu.com/p/79351489

https://github.com/chenjd/Unity_UI_Gamma

posted @ 2021-01-04 10:32  何文西  阅读(225)  评论(0编辑  收藏  举报