gamma校正流程

计算机为什么要做gamma校正:
- 人的视觉对光强度的感知是非线性的
- 数字图像所能采集和回放的灰阶层次有限的,需要省着点用(节约带宽)
物理光强相对值

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

物理光强相对值21.8。


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

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

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


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

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


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

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


正确的工作流程:
-
- 首先渲染器对输入的贴图使用下压的gamma曲线将贴图的数值还原会gamma=1的数值——De-Gamma操作。
- 然后对线性的贴图数据,线性的光照数据进行操作,得到线性结果
- 通过屏幕输出后,屏幕会将图片压暗
- 通过引擎内置按钮,再将图片进行一遍gamma校正,得到最终正确的图像




对比图:

PS操作中的误区
颜色混合

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

缩放前

缩放后
- 在8位每通道环境下进行测试

- 缩放后看到的是在“美术色阶”(gamma约等于2.2)的图像,美术中灰0.5,则实际物理中灰是0.2
- 本来我们想要的是一个物理中灰,但是PS算出一个物理中灰

高斯模糊

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

8位每通道下进行高斯模糊
PS中的线性工作流程
- 现在32位每通道中进行色彩运算,然后切换到8位每通道,再进行保存导出即可。
- 图像->模式->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));
}
文章详细阐述了计算机图像处理中的gamma校正过程,解释了由于人眼视觉非线性,需要将8位每通道的图像从物理灰阶转换到美术灰阶以避免色阶断层。介绍了正确的工作流程,包括De-Gamma、线性处理和最终的gamma校正,以及在Unity中的应用实例。

8163

被折叠的 条评论
为什么被折叠?



