六、扩充 gamma校正流程
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));
}
普通网友: 写的很好,细节很到位!【我也写了一些相关领域的文章,希望能够得到博主的指导,共同进步!】
普通网友: 每当我阅读你的编程博客文章时,我总能感受到你的专业水平和耐心解答的精神。【我也写了一些相关领域的文章,希望能够得到博主的指导,共同进步!】
普通网友: 博主的文章让我对这个主题有了全新的认识,细节描写非常到位,让我感受到了博主的深厚功底。【我也写了一些相关领域的文章,希望能够得到博主的指导,共同进步!】
普通网友: 这篇文章是优质之作,内容充实,结构明晰,语言流畅且通俗易懂,适合广大读者阅读。【我也写了一些相关领域的文章,希望能够得到博主的指导,共同进步!】
LoneWolf1989: 这里有个问题, content 使用 Layout 组件虽然省事,但在 removeChild 头节点后,所有元素都要向上移动,这样在视觉体验上并不好。