• 六、扩充 gamma校正流程


    gamma校正流程

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

    1. 人的视觉对光强度的感知是非线性的
    2. 数字图像所能采集和回放的灰阶层次有限的,需要省着点用(节约带宽)

    物理光强相对值

    上面一条,实际的物理光强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));
    }

  • 相关阅读:
    【学习笔记】ABC265/AGC012
    Blazor资源大全,很棒的Blazor
    前端的限流主要是通过什么方式实现的?
    drone的简单使用
    【Pytorch with fastai】第 5 章 :图像分类
    文本的换行与包裹 之可能是全网最详细的 line-break 中文介绍
    在执行对 HDFS 中创建用户目录的指令时,回复的命令如下图所示
    无服务器的无状态性
    【C++进阶】特殊类设计
    如何快速掌握Vuex
  • 原文地址:https://blog.csdn.net/s178435865/article/details/133681656