unity的颜色空间Gamma和Linear
介绍
- 人眼观察到的颜色不是线性的,为了使人眼感觉到线性的颜色变化,需要对颜色进行伽马校正
- Gamma校正的公式为 Cl = pow(Cg,Y) ,Cl 是线性颜色(取值0-1),Cg 是Gamma颜色,Y 是Gamma值,显示设备的 Gamma 值为 2.2,因此 Gamma 颜色转线性是会变暗的
- 显示设备接收的是经过Gamma校正的的电信号,即使是新的数字设备也沿用该习惯
除了显示设备,图片和视频保存的颜色也是伽马校正过的 - 伽马的颜色空间叫做 sRGB
为什么要用线性空间
因为 Gamma 颜色是为了符合人眼习惯而进行校正的,但在光照等需要对颜色进行运算时使用 Gamma 颜色是不准确的,所以需要先转换到线性空间,计算后在显示前再还原到 Gamma 空间
unity对线性颜色的支持
- 素材的颜色空间
美术提供的贴图一般是Gamma空间的,但法线和深度一般是线性空间的
在导入纹理到unity中时,如果是Gamma空间则勾选 sRGB ,否则不勾选
这样unity就知道素材的颜色空间 - unity内部的颜色空间
- PlayerSettings -> OtherSettings -> ColorSpace 可以选择 Gamma 或 Linear
- 当你切换颜色空间时,unity会马上对素材进行处理,转成对应的颜色空间,而不是运行时再处理,提高运行效率,比如 纹理勾选 sRGB,ColorSpace设为Linear,则要对纹理进行转换,保存在缓存中
- shader对颜色空间的处理
- 我们在shader中获取的像素颜色就是unity颜色空间下的颜色,因此最好在项目开始时就要确定颜色空间,因为会影响shader的编写,一般建议用 Linear 空间
- shader中可以用 UNITY_COLORSPACE_GAMMA 和 #ifndef UNITY_COLORSPACE_GAMMA 宏来编写不同颜色空间下的代码
- shader中可以用unity提供的函数转换颜色空间
- 线性转伽马 col.rgb = LinearToGammaSpace(col.rgb);
- 伽马转线性 col.rgb = GammaToLinearSpace(col.rgb);
- URP对颜色空间的处理
如果选择 Linear 的颜色空间,则URP会在 FinalBlitPass 中把颜色转成 Gamma 空间后再上屏 - 截屏或录屏对颜色空间的处理
如果unity设为Linear的颜色空间,则获取的纹理中的颜色都是线性空间,此时如果是自己保存的话,必须先转成Gamma颜色空间,因为正常的图片和视频都是保存为Gamma空间
可以观察录制的结果,太暗是没有做LinearToGamma 的转换,太亮则是多做了LinearToGamma的转换
unity使用线性颜色空间常见问题
- android原生端提供的相机纹理通常是Gamma空间,如果在unity中渲染需要转成线性空间
可以在 RawImage 上直接挂个Gamma转Linear的材质最方便 - 保存成视频通常是 Gamma 空间,从unity把纹理传给 android 录制,需要转成 Gamma 空间