
计算机为什么要做gamma校正:


上面一条,实际的物理光强50%位置其实再后面一点的位置。

物理光强相对值21.8。


物理灰阶与美术(视觉)灰阶相对关系
8位每通道一共记录256个数据。
如果均匀分布美术灰阶则如下图所示:

如果均等分布物理灰阶则如下图所示

上图可见,物理中灰过于偏向亮部(绿线),亮部区域过于集中,导致暗部区域样本数缺少。
如果按照物理中灰进行采样,下图中可见红线与


上图可知,如果对8位每通道采用物理灰度进行采样即线性记录物理光强数据,“美术暗部”只会有56个样本,就会导致一个现象——色阶断层。

如果按照非线性记录物理光强数据,则会得到一个人眼看起来较为平滑的画面。


流程图:
渲染器32位每通道(物理数据)-> gamma≈2.2校正到8位每通道(美术数据)->gamma = 1校正8位每通道

原因:
开始如数的数据是“美术数据”输入的gamma≈2.2 ,经过一屏幕的压暗处理后贴图是正常了,但是光线变得很暗,导致画面整体偏暗,然后引擎内部再将整体画面提亮后,光线虽然正常了,但是贴图会变的很亮导致画面渲染错误。
错误的工作流程:


正确的工作流程:




对比图:


8位每通道与32位每通道(生活中的样子)颜色混合对比图

缩放前

缩放后
![]()


32位每通道下进行高斯模糊

8位每通道下进行高斯模糊
直接修改Unity里的色彩空间选项

Gamma空间下效果:

Linner空间下效果:

代码转换:
①调用Unity内部方法GammaToLinearSpace、LinearSpaceToGammaSpace。

转换前:

转换后:

UnityCG.cginc内部源码
inline float GammaToLinearSpaceExact (float value)
{
if (value <= 0.04045F)
return value / 12.92F;
else if (value < 1.0F)
return pow((value + 0.055F)/1.055F, 2.4F);
else
return pow(value, 2.2F);//看灰色的return,调用的GammaToLinearSpaceExact ,rgb大于1时,pow 2.2曲线下压变暗
}
inline half3 GammaToLinearSpace (half3 sRGB)
{
return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);
// Precise version, useful for debugging.
//return half3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
}
inline float LinearToGammaSpaceExact (float value)
{
if (value <= 0.0F)
return 0.0F;
else if (value <= 0.0031308F)
return 12.92F * value;
else if (value < 1.0F)
return 1.055F * pow(value, 0.4166667F) - 0.055F;
else
return pow(value, 0.45454545F); //pow 1/2.2,曲线上突变亮
}
inline half3 LinearToGammaSpace (half3 linRGB)
{
linRGB = max(linRGB, half3(0.h, 0.h, 0.h));
return max(1.055h * pow(linRGB, 0.416666667h) - 0.055h, 0.h);
// Exact version, useful for debugging.
//return half3(LinearToGammaSpaceExact(linRGB.r), LinearToGammaSpaceExact(linRGB.g), LinearToGammaSpaceExact(linRGB.b));
}