美文网首页Unity3D
【Unity3D】伽马校正

【Unity3D】伽马校正

作者: LittleFatSheep | 来源:发表于2023-10-13 15:26 被阅读0次

1 伽马相关概念

1.1 人眼对亮度变化的感知

人眼对亮度变化的感知不是线性的,如下图,人眼对亮区的亮度变化不太敏感,对暗区的亮度变化较敏感。另外,我们可以想象一下,在一个黑暗的房间里,由 1 根蜡烛到 2 根蜡烛的变化,我们很容易感知到,但是由 100 根蜡烛到 101 根蜡烛的变化,我们就不容易感知到。因此,对于固定的存储空间,我们应该给暗区分配更多的存储空间,而给亮区少分配些空间,这样能让更多的细节在暗区呈现,而亮区不必呈现太多细节(因为人眼感知不到亮区的细微变化,呈现太多细节只会浪费空间)。

1.2 伽马编码和伽马解码

1)伽马函数

伽马函数公式如下,因其指数部分 γ 读音为伽马(gamma)而来。

当 0 < γ < 1 时,伽马函数的图像从左往右逐渐平缓,通常作为伽马编码处理;当 γ > 1 时,伽马函数的图像从左往右逐渐陡峭,通常作为伽马解码处理。如下是 γ 值为 0.45 和 2.2 的函数图像。

2)伽马函数在图像捕捉****和显示中的应用

一般情况下,一个像素使用 8 位存储,可以表示 256 种颜色。为了尽可能线性化人眼感知的亮度变化(人眼对暗区的亮度变化更敏感,需要使用更多的存储空间,对亮区的亮度变化不太敏感,可以少分配些空间),对相机采集到的图像进行伽马编码处理后,再存入 jpeg 等格式图片文件中,在读取图片文件时,通过伽马解码处理后再显示,如下图所示。

在早期,CRT(Cathode Ray Tube,阴极射线管)几乎是唯一的显示设备,它有一个特性,输入电压和显示亮度不是线性关系,而是伽马函数关系,并且其 γ 值刚好是伽马编码函数的 γ 值的倒数,这正好补偿了图像捕捉设备的伽马编码造成的亮度非线性问题。因此,显示设备只需要输入线性变化的电压,就可以还原线性变化的亮度,而不需要进行伽马解码处理。现在 CRT 设备很少见了,并且后来的显示设备有着不同的伽马曲线(γ 值不同),但人们仍在硬件上做了调整来提供兼容性。

注意:透明通道不参与伽马编码和伽马解码。

3)sRGB 颜色标准

微软联合爱普生、惠普制定了 sRGB 颜色空间标准,推荐相机的伽马编码函数的 γ 值为 0.45,显示器的伽马解码函数的 γ 值为 2.2(因为 2.2 × 0.45 ≈ 1)。绝大多数的摄像机、PC 和打印机都使用了 sRGB 标准。

1.3 颜色空间

Unity 中材质渲染的颜色空间分为伽马空间(默认)和线性空间,如下。

伽马空间中,Unity 不会对 Shader 的输入和输出进行任何处理,因此,输入的像素可能是非线性的,输出的像素经过显示器的伽马解码处理后可能会得到非预期的亮度,通常表现为场景整体变暗。

线性空间中,Unity 会把输入纹理设置为 sRGB 模式,在该模式下,硬件在对纹理进行采样时会自动进行伽马解码,在 Shader 写入颜色缓冲前自动进行伽马编码(HDR 除外)。

用户可以在【Edit→Project Settings→Player→Other Settings→Rendering→Color Space】中设置颜色空间,如下。

2 伽马对亮度和混合的影响

当颜色空间使用默认在伽马空间时,如果不进行伽马矫正,可能会出现场景整体偏暗、混合异常等问题。本节实验完整资源见→Unity3D伽马校正对比实验

2.1 伽马对亮度的影响

新建一个场景,调整相机位置和旋转角度分别为 (0, 0, -1.5)、(0, 0, 0),调整直射光旋转角度为 (45, -90, 0),使得直射光从右上角 45° 射向左下角;新建一个 Sphere,调整其位置为 (0, 0, 0),新建一个材质,重命名为 DiffuseMat,设置其 Shader 为【Legacy Shaders / Diffuse】,将该材质拖拽给 Sphere;设置环境光为全黑(在【Window→Rendering→Lighting→Environment→Ambient Color】中设置),使得渲染只受漫反射影响。伽马空间和线性空间中 Sphere 渲染如下。

由于球体的渲染只受漫反射影响,并且直射光从右上角 45° 射向左下角,因此右边的渲染才更符合要求。另外,左侧图像相比右侧图像,整体偏暗一些。

2.2 伽马对混合的影响

新建一个场景,创建 3 个 Quad 和 3 个材质,将这些材质分别拖拽到 3 个 Quad 中,将以下 Shader 绑定到这些材质中,将边缘渐变的圆形图片拖拽到 3 个材质中,调整 3 个材质的颜色分别为红、绿、蓝。

SimpleBlend.shader

Shader "MyShader/SimpleBlend" {
    Properties {
        _MainTex ("Main Tex", 2D) = "white" {}
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
    }

    SubShader {
        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}

        Pass {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            
            CGPROGRAM

            #include "UnityCG.cginc"

            #pragma vertex vert_img
            #pragma fragment frag

            sampler2D _MainTex;
            fixed4 _Color;

            fixed4 frag(v2f_img i) : SV_Target {
                return fixed4(_Color.rgb, tex2D(_MainTex, i.uv).a);
            }

            ENDCG
        }
    }

    FallBack "Transparent/VertexLit"
}

伽马空间和线性空间中 3 个 Quad 的渲染如下。

左侧图片边缘较硬,右侧图片边缘较柔和,更符合实际情况。

3 伽马校正策略

在线性空间下,系统自动进行了伽马校正;在伽马空间下,需要用户手动校正。另外,Unity 的线性空间并不是所有平台都支持,如:移动平台就无法使用线性空间。

对非线性的输入纹理,进行伽马解码校正如下:

float3 tex = pow(tex2D(_Tex, i.uv).rgb, 2.2);

在片元着色器输出前,进行伽马编码校正如下:

fragColor.rgb = pow(fragColor.rgb, 0.45);
return fragColor;

注意:当场景中存在半透明物体时,上述校正会导致混合在非线性空间中进行,影响混合效果,一种有效的解决方法是:将伽马编码校正放在屏幕后处理中进行。

声明:本文转自【Unity3D】伽马校正

相关文章

  • OpenGL学习27——伽马校正

    伽马校正(Gamma Correction) 在旧的数字图像时代,大部分显示器都是显像管显示器。这些显示器的物理属...

  • QT+OPenGL二十Gamma校正

    为什么需要Gamma(伽马)校正 因为肉眼对于亮度的感知是非线性的,即对较暗的亮度感知灵敏,对于较亮的亮度感知度逐...

  • 伽马函数和伽马分布

    伽马函数 伽马函数可以通过欧拉(Euler)第二类积分定义:其中参数 伽马函数的性质: 伽马分布 若随机变量X的密...

  • 【脑洞故事】这个世界是假的!

    “早啊,伽马。” “早啊,贝塔。” 伽马笑着与贝塔打了个招呼,当两人擦肩而过后笑容立刻消失。 ······ 我叫伽...

  • 地球保卫战

    3999年伽马星人入侵太阳系。随着一颗陨石撞击月球。伽马星球对地球的入侵正式开始。银河系地球的盟友星球已被伽马星人...

  • 连续型概率分布

    连续随机变量 期望和方差 伽马函数 伽马分布 指数分布 卡方分布 正态分布

  • UnityShader精要笔记二十四 全局光照 伽马校正 HDR

    本文继续对《UnityShader入门精要》——冯乐乐 第十八章 基于物理的渲染 进行学习 在https://gi...

  • 伽马函数

    概率论

  • 马哈拉奇节选(七)

    尼萨伽达塔马哈拉奇节选(七) Sri Nisargadatta Maharaj's I AM THAT 尼萨伽达塔...

  • “万里”消化道 ~ 牙得好好的

    伽马飞到了蛀斑的边上,观察了起来。 颜色偏黄,算是黄褐色吧。“还好,还好,没蛀的太厉害,还有的救。”伽马自言自语道...

网友评论

    本文标题:【Unity3D】伽马校正

    本文链接:https://www.haomeiwen.com/subject/uvlabdtx.html