【Unity3D】伽马校正
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】伽马校正。
【Unity3D】伽马校正的更多相关文章
- 【图形学】我理解的伽马校正(Gamma Correction)
http://blog.csdn.net/candycat1992/article/details/46228771/ 写在前面 我相信几乎所有做图像处理方面的人都听过伽马校正(Gamma Corre ...
- 【视频开发】伽马校正(gamma correction)学习笔记
我相信几乎所有做图像处理方面的人都听过伽马校正(Gamma Correction)这一个名词,但真正明白它是什么.为什么要有它.以及怎么用它的人其实不多.我也不例外. 最初我查过一些资料,但很多文章 ...
- 图像处理gamma修正(伽马γ校正)的原理和实现算法
☞ ░ 前往老猿Python博文目录 ░ 本文转自博客园:淇淇宝贝的文章<图像处理之gamma校正>,原文链接:https://www.cnblogs.com/qiqibaby/p/532 ...
- 伽马变换(一些基本的灰度变换函数)基本原理及Python实现
1. 基本原理 变换形式 $$s=cr^{\gamma}$$ c与$\gamma$均为常数 可通过调整$\gamma$来调整该变换,最常用于伽马校正与对比度增强 2. 测试结果 图源自skimage ...
- 图像增强算法(直方图均衡化、拉普拉斯、Log、伽马变换)
一.图像增强算法原理 图像增强算法常见于对图像的亮度.对比度.饱和度.色调等进行调节,增加其清晰度,减少噪点等.图像增强往往经过多个算法的组合,完成上述功能,比如图像去燥等同于低通滤波器,增加清晰度则 ...
- 基础图像处理之混合空间增强——(Java:拉普拉斯锐化、Sobel边缘检测、均值滤波、伽马变换)
相信看过冈萨雷斯第三版数字图像处理的童鞋都知道,里面涉及到了很多的基础图像处理的算法,今天,就专门借用其中一个混合空间增强的案例,来将常见的几种图像处理算法集合起来,看能发生什么样的化学反应 首先,通 ...
- C++数字图像处理(1)-伽马变换
https://blog.csdn.net/huqiang_823/article/details/80767019 1.算法原理 伽马变换(幂律变换)是常用的灰度变换,是一种简单的图像增强算法 ...
- 对比度增强(二):直方图正规划与伽马变换 cv.normal()函数使用及原理
直方图正规化: 图像为I,宽为W,高为H,I(r,c)代表I的第r行第c列的灰度值:输出图像记为O,为使得输出图像的灰度值在[Omin,Omax]范围里,可用如下公式: ...
- OpenCV计算机视觉学习(3)——图像灰度线性变换与非线性变换(对数变换,伽马变换)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 下面 ...
- Gamma correction 伽马校准及 matlab 实现
matlab 内置实现:imadjust Gamma Correction gamma correction formula : .^(gamma) or .^(1/gamma)? 用以调整图像光照强 ...
随机推荐
- C++模板显示指定类型时使用引用遇到的问题
1.问题 这里我想让模板函数接收int和char类型的参数,并进行相加,显示指定参数类型为int. 第一个调用理论上会自动将char类型强转成int类型,后进行相加: 第二个调用理论上会自动将int类 ...
- [转帖]Nginx 使用与异常处理
http://jartto.wang/2017/04/15/nginx-exception-handling/ 以前总是偷懒使用 Http-Server 来启动一个本地服务,后来花时间学习了一下 Ng ...
- 【转帖】【奇淫技巧】Linux | 查找文件,无所遁形
theme: channing-cyan 本文正在参与 "走过Linux 三十年"话题征文活动 在Linux系统上,最常见的操作莫过于处理文本.常见文件操作陈列.查找.排序.格式转 ...
- Beyond Compare 的比较以及导出的简单设置方法
最近需要对文件进行对比 但是发现对比的工作量比较难搞. 用到了beyond compare 的工具 感觉挺好用的 但是需要注意事项比较多这里记录一下 1. session setting 里面进行设 ...
- 使用rpmbuild打包erlang和rabbitmq进行部署服务的方法
使用rpmbuild打包erlang和rabbitmq进行部署服务的方法 背景说明 1. rabbitmq 是基于 erlang 开发的消息列队, 本身rabbitmq 自己不区分架构. 2. 但是e ...
- 【JS 逆向百例】W店UA,OB反混淆,抓包替换CORS跨域错误分析
关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...
- 手撕Vuex-实现getters方法
经上一篇章介绍,完成了实现共享数据的功能,实现方式是在 Store 构造函数中将创建 Store 时将需要共享的数据添加到 Store 上面,这样将来我们就能通过 this.$store 拿到这个 S ...
- 报错ValueError: Can't find 'adapter_config.json'
前言 在做组内2030项目时,我具体做的一个工作是对大模型进行LoRA微调,在整个过程中有许多坑,其中有些值得记录的问题,于是便产生了这篇博客. 问题 我在得到微调好的模型后,需要对模型进行性能测评. ...
- 7.3 C/C++ 实现顺序栈
顺序栈是一种基于数组实现的栈结构,它的数据元素存储在一段连续的内存空间中.在顺序栈中,栈顶元素的下标是固定的,而栈底元素的下标则随着入栈和出栈操作的进行而变化.通常,我们把栈底位置设置在数组空间的起始 ...
- C/C++ 实现切片免杀的思路
今天突然想到了一个好玩的免杀思路,原理就是想办法切断磁盘特征与内存特征,关于沙盒免杀我寻思着,这样可以将不同的的DLL映射到内存,在内存中他们的特征也是被切断的,在注入器上做判断如果是沙盒则不加载,不 ...