Unity Linear Gamma色彩空间矫正测试

Gamma和Linear修正的问题相信网上已经有很多文章了。简单来说显示器的颜色输出不是线性的,根据硬件参数和输出颜色

信息拟合曲线是x^2.2,因此会使用一个x^0.45曲线将其拟合回线性。

 

因为0.5^0.45 = 0.73,0.5^2.2 = 0.217,我们可以通过一张0.5rgb的灰度图放Unity中观察变亮还是变暗

来判断Unity在线性空间下做了哪些操作,以及参数配置是否正确。

 


 

这里进入URP渲染管线,并设置为Linear线性颜色空间进行测试:

测试1:一张图片在ps里制作成(127,127,127)的纯色,导入Unity。不勾选sRGB,输出颜色较亮,勾选sRGB,输出颜色正常

结论:最终颜色输出时可能有gamma0.45处理。

 

测试2:frag里输出颜色为0.5,该shader最终屏幕输出时,输出颜色较亮

结论:进一步确定输出时有gamma0.45(pow(x,0.45))的处理。

 

测试3:增加一个UV偏移的shader参数值,在Gamma颜色空间和Linear颜色空间下切换查看,无区别

结论:颜色空间的修正处理类似滤镜,而正常传入Shader的字段数值不会做编解码,不参与显示相关的数值也不用做

纠正。

 

测试4:增加一个float类型的shader字段,直接输出在frag里,并将参数值设为0.5。输出颜色较亮,

而给参数加上[Gamma]前缀,输出时颜色正常。

结论:因为最终输出时屏幕会有一步gamma0.45处理,所以给常规参数追加一个gamma2.2处理,

这样输出就是原始颜色了(加上[Gamma]相当于pow(x,2.2))。

 

测试5(重要):Unity Linear颜色空间,一张Alpha0.5的纯黑图片,叠在白色背景上,但混合结果颜色并不是0.5的灰色。

尝试加pow(2.2)手动修复,然后换成Alpha0.5的白色图片,叠纯黑背景上。发现仅是对Alpha值修改在混合处理上没有用。

结论:首先明确一点Alpha通道不会进行sRGB矫正。但是Alpha值虽然没问题,Unity的混合处理却有问题。gamma0.45的修正是处理在

混合完成的结果上的,你并不知道混合结果的颜色是来自黑色叠白色,还是白色叠黑色,或是其他颜色相叠。

内建管线下可以创建Gamma RenderTexture,也就是sRGB为true的RT。但URP下似乎有些失效,所以这个问题博主自己目前还没解决。

虽然单改Alpha值没用,但我还是研究出了一个基于经验的公式,通过读取当前颜色和修改Alpha;做到了一部分还原:

float whiteAlpha = pow(color.a, 2.2);
float blackAlpha = 1.0 - pow((1-color.a), 2.2);
float lum = max(color.b, max(color.r, color.g));
color.a = lerp(blackAlpha, whiteAlpha, lum);
color.rgb *= color.a;

若要求不高又不想扩展管线,也可以试试。

 

最后总结下:

不用于图像输出的图片,如噪波,就不需要勾选sRGB(不勾选sRGB也叫做保持Linear)。不用于图像输出的shader字段,如UV偏移值

就不用处理。用于图像输出的shader字段,需要加[Gamma]前缀或者手动调用Gamma22ToLinear。

同样,用于显示输出的图像如果中途要进行逻辑计算,需要调用LinearToGamma22转回原始数值。

例如一些手游项目会合并多张贴图到一张,这就导致了Linear和sRGB混在一张图片内,这时候就需要代码里手动去转了。

 

posted @ 2021-09-24 10:26  HONT  阅读(1290)  评论(1编辑  收藏  举报