[openGL] 高级光照-Gamma矫正

news2025/1/4 17:27:24

目录

一 Gamma是什么?

二 感知光度和物理光度

2.1 与Gamma的关系

2.3 存在问题和弊端?

三 Gamma矫正(逆Gamma)

3.1 Gamma矫正的两种方法

3.2 sRGB空间

3.3 重复校正

3.3.1 在着色器中处理重复校正

3.3.2 在加载纹理时就重复校正

3.3.3 校正前后效果


 本章节Qt源码点击此处

一 Gamma是什么?

在了解Gamma之前我们应该先知道一种物理特性: 输出亮度 = 输入电压 的 2.2次方幂

  • 这是因为以前大多数的监视器是阴极射线显示器(CRT),这里后面我们就把显示器统称为监视器

这个经过2.2次方幂处理过后就相当于是一种压缩处理(可以理解为将图片变暗了至于为什么要这样处理将图片变暗,这将在后面进行说明,当然理解为压缩处理是不对的,但后面会修正。)\,每种显示设备的这个值都不一样,但是大多数都是2.2,这个2.2就叫做监视器的Gamma。

  • 经过Gamma处理过的颜色都会变暗,但只是中间的颜色,一定要理解的是,他并不会影响全暗(0),以及全亮(1)的光度。

输出亮度 = 输入电压 ^ 2.2

二 感知光度和物理光度

要知道的是无论是感知光度还是物理光度:两边的光度(最暗和最亮的)总是相同的

感知光度: 其实就是人对光的感觉

  • 因为我们人眼对比较暗的光是比较敏感的,而对亮光是不太敏感的,比如再黑暗中,稍微有点亮光我们就会感知出来,但是对于比较亮的环境中,即使增加光度
  • 这样理解:由于人眼感知对较暗的光比较敏感,所以就会给暗光分配更多的精度(暗光的变化随着值的增加不会变化的很快)。

物理光度:

  • 就是真实世界的光度,亮度的效果在0-1之间是线性增加的

在上面的图中,红色框代表的是人眼的感知光的变化,而下面的绿色框代表的是物理的真是光照。

2.1 与Gamma的关系

感知光度的形成:

对与我们输入给显示器也就是我们在程序或者应用中设置的颜色来讲,在传递给监视器后,监视器会根据自己的Gamma来进行处理,也就是对于我们设置的值0.5,他会进行Camma计算,变成0.5^2.2 = 0.218,这就会将光源变暗,从而从物理光照变成了人眼所感知的光照效果。

  • 也就是说我们本身设置的想要他显示物理真实光照,但实际上经过监视器Gamma处理后,他显示出来的光照被放暗了,
  • 颜色传递给监视器后经过监视器Gamma计算,将本该显示的物理光度(中间那条线性变化的值)压缩成凹下去的那条线的值,0.5^2.2 = 0.218。
  • 最上面凸出去的那条线暂时不用管,其实就是一个逆的Gamma操作。

2.3 存在问题和弊端?

这会导致什么问题呢? 如果我们传给监视器前的光照是基于线性空间的,也就是上图的白色虚线

那监视器的Gmama就会给他进行Gmama计算,让他变到下面红色实线(凹下去的那条线),这就导致了,中间的亮度会被变暗,

和上面的例子一样,我们观察白色虚线(线性空间 也就是我们想要设置的真实物理光度)上的0.5,他就会被压缩至0.218,从而变暗.

这种压缩只是一种幂次方比例上的压缩,只是以某种幂次方比例压缩了中间值(Gamma校验无论怎样都不会影响最小的和最大的亮度也就是0和1)

弊端:

由于所有中间的亮度都是在线性空间计算的(传递给监视器处理前) ,所以这几乎导致了我们现在所看到的光照都不在准确的(因为他会进行Gamma计算),不是真实的物理上的光度,这就会导致我们会看到物体的效果并不会很有层次感,也就是说我们会看到更多的较暗的光度,而丢失很多比较亮的光度。

三 Gamma矫正(逆Gamma)

我们这里要先熟悉一下这两个概念

逆Gamma: 将线性的空间上供为上面凸出去的非线性空间

Gamma:将线性的空间下供为下面凹下去的非线性空间

简而言之就是给传入的值做一个1/2.2的幂次方计算,把这个值先变大,然后经过Gamma就会变回正常的线性空间的值。也就是真实的物理空间的值

  • 其实Gamma矫正很简单,如果我们本身不存在监视器Gamma这个处理过程,那我们根本无需处理任何东西和计算,得到的就是真实的物理上的光度
  • 但由于有了这个监视器Gamma导致我们看到的光度比实际物理上的光度暗了,那么很简单我们只需要给这个设定的值进行 逆运算,也就是说,你监视器会把我给定的值做做幂次方压缩导致我的线性空间变成了Camma空间(也就是红色实线凹下去的那条线),那我在给监视器之前我就给让我给定的这个值去做一个逆Gamma,也就是将这个线性空间变成上面的凸出去的那条线,这样再传递给监视器的时候,经过Gamma处理,他就还是正常的线性空间的值,显示出来的也就是真实的物理世界的值。

3.1 Gamma矫正的两种方法

  • 让着色器每次运行后自动进行Gamma,这样就不需要人为处理了
glEnable(GL_FRAMEBUFFER_SRGB);
  • 我们直接再发送到帧缓冲前,在每个相关像素着色器运行的最后应用gamma校正
void main()
{
    float gamma = 2.2;
    fragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma));
}

值得注意的是:我们对于Gamma的校正一定要是在最后输出的时候再进行校正,而不要在中间计算的时候就进行校正,因为中间值的一些属性:比如两个光照和的相加,混合等处理是要在线性空间计算的,这要值得注意

3.2 sRGB空间

 监视器总是按照sRGB颜色空间的规则显示颜色,我们可以这样简单的理解:

  • sRGB空间 是一个包含了预设Gamma特性的标准化颜色空间,旨在确保跨设备颜色的一致性。
  • sRGB空间中的值: 我们可以这样理解他是将线性空间中的值进行逆Gamma处理后得到凸起的那条上供的非线性空间中的值。
  • 这种值我们就不能手动在对他进行Gamma校正了。

3.3 重复校正

  • 有的设计师在设计sRGB纹理图案时,会自动的将亮度提高,然后当他经过监视器的Gamma处理之后他就会变成正常的线性空间的颜色值。但此时使用着可能并不知道,手动又给他在最后输出给监视器之前进行了一次逆Gamma,这就导致最终输出在监视器上的亮度被放亮了。所以这就需要我们在进行Gamme校正之前判断。

3.3.1 在着色器中处理重复校正

float gamma = 2.2;
vec3 diffuseColor = pow(texture(diffuse, texCoords).rgb, vec3(gamma));
// 首先调整环境光照和漫反射光照的亮度    
shaderProgramObject.setUniformValue("light.ambient",   QVector3D(0.3f, 0.3f, 0.3f));
shaderProgramObject.setUniformValue("light.diffuse",   QVector3D(0.7f, 0.7f, 0.7f));

// 将漫反射光照进行Gamma处理
    vec3 diffuseTexColor=vec3(texture(material.texture_diffuse1,TexCoords));
    float gamma = 2.2;
    diffuseTexColor = pow(diffuseTexColor,gamma);
  • 但是为每个sRGB空间的纹理这样设置是很烦人的,

3.3.2 在加载纹理时就重复校正

OpenGL给我们提供了另一个方案来解决我们的麻烦,这就是GL_SRGB和GL_SRGB_ALPHA内部纹理格式。

如果我们在OpenGL中创建了一个纹理,把它指定为以上两种sRGB纹理格式其中之一,OpenGL将自动把颜色校正到线性空间中,这样我们所使用的所有颜色值都是在线性空间中的了。我们可以这样把一个纹理指定为一个sRGB纹理:


    QImage wall = QImage(":/wood.png").convertToFormat(QImage::Format_RGB888);
    m_planeTex = new QOpenGLTexture(QOpenGLTexture::Target2D);
    glBindTexture(GL_TEXTURE_2D,m_planeTex->textureId());

    glTexImage2D(GL_TEXTURE,0,GL_SRGB,wall.width(),wall.height(),
                 0,GL_RGB,GL_UNSIGNED_BYTE,wall.bits());
    glGenerateMipmap(GL_TEXTURE_2D);
    m_planeMesh = processMesh(planeVertices,6,m_planeTex->textureId());

3.3.3 校正前后效果

  • 未处理重复校正前的效果:我们会发现这个亮度很高,这是因为漫反射纹理的颜色空间已经在sRGB中空间(说明他已经进行了逆Gamma处理)了,但是我们在着色器的最后又进行了一次逆Gamma处理,两次的逆Gamma处理就会导致亮度异常大。

  • 处理后的效果: 我们要注意 漫反射纹理已经在sRGB空间中了,我们在着色器最后又给他逆Gamma那肯定会异常亮
  • 并且我们要保证中间的光照计算要在线性空间中,所以我们需要在获取到漫反射纹理后,对他进行Gamma处理,把他变到线性空间中,这样保证了他后续的计算不会出问题,然后在再着色器最后输出时进行一次逆Gamma处理这样就能得到正确的颜色了。

值得注意的:

  • 不是所有的纹理都是在sRGB空间中的所有我们如果要把纹理指定为sRGB纹理时一定要注意
  • 一般像漫反射光照这种为物体上色的纹理几乎都是在sRGB空间中的
  • 但是像镜面光贴图和法线贴图几乎都在线性空间中,所以如果你把它们也配置为sRGB纹理的话,光照就会连续被衰弱两次,这样光照几乎就坏掉了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1601996.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于python的二手房数据分析建模及可视化研究,爬取链家二手房数据,可视化分析,房价预测模型

介绍 主要涉及通过爬取济南市链家二手房数据,然后对数据进行处理,包括缺省值处理,高德地图获取二手房地址所属市区,经纬度等数据处理。然后通过python的flask框架编写后端接口,把数据响应给前端。然后前端通过AJAX请求…

AI决策与专家决策,您更喜欢哪种决策方式?

HI,我是AI智能小助手CoCo。 CoCode开发云智能助手CoCo “大家好,我是CoCode开发云的AI智能小助手CoCo,现在为大家播放关于CoCode开发云AI大家庭的最新消息: 欢迎AI家庭新成员:AI自动决策”。 AI自动决策发布 CoCode开…

信息系统安全,陈萍,王金双习题

第一章 填空题 机密性、完整性、可用性设备安全、数据安全、内容安全、行为安全通信保密、信息安全、信息安全保障保护、检测、响应、恢复健康、法律法规网络和通信协议的脆弱性、信息系统的缺陷、黑客的恶意攻击稳定性、可靠性、可用性硬件和软件的底层整体性、分层性、最小…

Zabbix监控Windows

1.在虚拟机中安装zabbix 安装系统一直托不进虚拟机中;因为没安装Tools组件 点击虚拟机,选择安装VMware Tools 2.配置zabbix

SpringBoot之JWT令牌校验

SpringBoot之JWT令牌校验 本文根据黑马b站springboot3vue3课程 JWT (JSON Web Token)是一种开放标准(RFC 7519),用于在不同实体之间安全地传输信息。它由三个部分组成:头部(Header)…

dnspy逆向和de4dot脱壳

拿到一个软件,使用dnspy查看,发现反汇编后关键部分的函数名和代码有很多乱码: 这样的函数非常多,要想进一步调试和逆向,就只能在dnspy中看反汇编代码了,而无法看到c#代码,当时的整个逆向过程只剩…

程序,进程,进程管理的相关命令

程序 程序是执行特定任务的代码 1.是一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具 2.用于描述进程要完成的功能,是控制进程执行的指令集 进程的状态 为了对进程进行管理,操作系统首先定义…

【GDB调试技巧】提高gdb的调试效率

目录 🌞gdb的启动 🌞gdb技巧 🌼1. gdb小技巧汇总 🌼2. 打印输出指定地址的值 🌼3. 查看当前执行到哪行代码代码内容 3.1 方式一:info line 结合 list 。 3.2 方式二:f 3.3 方式三&#…

算法与数据结构要点速学——排序算法

排序算法 所有主要的编程语言都有一个内置的排序方法。假设并说排序成本为 O(n*log n),通常是正确的,其中 n 是要排序的元素数。为了完整起见,这里有一个图表,列出了许多常见的排序算法及其完整性。编程语言实现的算法各不相同&a…

N皇后问题(DFS解决)

文章目录 一、题目分析二、对角线判断&#xff08;分两种&#xff09;三、代码演示 先赞后看&#xff0c;养成习惯&#xff01;&#xff01;&#xff01;^ _ ^<3 ❤️ ❤️ ❤️ 码字不易&#xff0c;大家的支持就是我坚持下去的动力。点赞后不要忘了关注我哦&#xff01; 一…

Go 单元测试之HTTP请求与API测试

文章目录 一、httptest1.1 前置代码准备1.2 介绍1.3 基本用法 二、gock2.1介绍2.2 安装2.3 基本使用2.4 举个例子2.4.1 前置代码2.4.2 测试用例 一、httptest 1.1 前置代码准备 假设我们的业务逻辑是搭建一个http server端&#xff0c;对外提供HTTP服务。用来处理用户登录请求…

抢抓新机遇,助力资源暴增,CBTC上海储能展邀您报名参加

伴随全球能源革命提速&#xff0c;推动能源革命、构建新型电力系统成为全球共识。新型储能作为协调“源网荷储”互动、平衡电力动态供需的核心环节&#xff0c;已成为实现“碳达峰、碳中和”国家战略的重要支撑。经历“十三五”国家多维政策的持续孕育&#xff0c;“十四五”新…

“打呼噜”用英语怎么说?柯桥成人英语培训

泓畅教育&#xff1a;#18757519765# 失眠的英文表达&#xff0c;一般有以下几种&#xff1a; 1. 如果只是偶尔睡不着&#xff0c;最简单的表达就是&#xff1a; 例句&#xff1a; I cant sleep. Are you still up? 我睡不着。你睡了吗&#xff1f; I cant fall asleep. …

LeetCode 179 in Python. Largest Number (最大数)

寻找最大数的逻辑简单&#xff0c;但如何对两数比较组成更大的整数是一个重点。例如示例2中如何区分3与30谁放在前面以及3与34谁放在前面是一个难点&#xff0c;本文通过采用functools中的自定义排序规则cmp_to_key()来判断上述情况&#xff0c;并给出代码实现。 示例&#xf…

CTFshow-PWN-前置基础(pwn17)

有些命令好像有点不一样&#xff1f; 不要一直等&#xff0c;可能那样永远也等不到flag nc 上后&#xff0c;经过简单测试&#xff0c;1 和 4 并没有什么重要信息 3 会陷入一个等待&#xff0c;题目有说明不要一直等 &#xff0c;而 5 是退出&#xff0c;因此猜测突破口在 2 键…

基于springboot实现知识管理系统项目【项目源码+论文说明】

基于springboot实现知识管理系统演示 摘要 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个专门适应师生作业交流形式的网站。本文介绍了知识管理系统的开发全过程。通过分析企业对于知识管理系统的需求&#xff0c;创建了…

FANUC发那科机器人示教器维修A05B-2490-C176

维修的fanuc发那科产品包括&#xff1a;发那科cnc数控系统,发那科伺服驱动器和伺服电机维修,发那科机器人维修&#xff0c;以及fanuc主轴驱动模块维修,发那科模块电源维修,数控系统电路板维修等。 1 发那科示教器液晶屏不好、花屏、白屏、黑屏、闪屏、竖线、摔破 2 FANUC示教…

[leetcode] 55. 跳跃游戏

文章目录 题目描述解题方法模拟java代码复杂度分析 相似题目 题目描述 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 tr…

Redis中的订阅发布(一)

订阅发布 概述 Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成。通过执行SUBSCRIBER命令&#xff0c;客户端可以订阅一个或多个频道&#xff0c;从而成为这些频道的订阅者(subscribe)&#xff1a; 每当有其他客户端向被订阅的频道发送消息(message)时&…

springboot源码解析(一):启动过程

springboot源码解析(一):启动过程 1、springboot的入口程序 SpringBootApplication public class StartupApplication {public static void main(String[] args) {SpringApplication.run(StartupApplication.class, args);} }当程序开始执行之后&#xff0c;会调用SpringAppli…