| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> sRGB标准与伽马校正 理解 -> 正文阅读 |
|
[游戏开发]sRGB标准与伽马校正 理解 |
srgb : 颜色值会以非线性的方式存储如一个颜色值在线性空间中,rgb=(1,1,1), 在gamma空间中,rgb会变为(1的2.2幂次,1的2.2幂次,1的2.2幂次),颜色值会发生改变,这样方便在显示器中显示的时候,正确显示(因为在显示器中显示时,会使得图像变暗) 如果一个图片的颜色格式为srgb,则说明这张图片存储的颜色值是encode gamma之后的颜色值 在unity中设置为gamma空间时,图片颜色值会在导入时变成非线性的颜色值 srgb标准是图片颜色值固定按照2.2分之一(0.45)次幂的颜色变化 所有显示器硬件在进行颜色值的转换时固定按照2.2次幂来对颜色值进行转换 对渲染的意义 渲染中用到的光照都是在线性空间的。所以所有的计算都需要转换到线性空间计算 下面时参考文章: sRGB标准与伽马校正sRGB标准 人眼对亮度的感知不是线性的,其对较暗区域的变化更加敏感? ?参见:Computer Color is Broken 基于人眼该特点,sRGB标准要求图像(各通道为8bits,最多存储256个亮度值)使用编码伽马,把更多地空间用来存储更多暗部区域,来最大化地利用表示亮度的数据位或带宽 在早期,阴极射线管(CRT)显示器是唯一的电子显示设备,但它的输入电压和显示出来的亮度关系不是线性的,而是一个类似幂律(pow-law)曲线的关系,使得信号被压暗 巧合地是,sRGB标准的编码伽马是一个将图像变亮的幂率曲线,正好与其形成互补,使得不需要再做调整就可以让sRGB图像在CRT上显示出与现实场景一致的亮度 后来出现的LCD和等离子显示器,为了保证兼容,在硬件上也都选择了和当年CRT一样的非线性特性 类似于sRGB标准的编码伽马(encoding Gamma),由于能校正CRT的显示伽马(display Gamma,标准值 γ = 2.2),因此又被称为伽马校正(Gamma correction) ? 对渲染的意义 渲染中用到的光照都是在线性空间的。因为在设计光照的时候都是认为1的亮度是0.5的2倍 光照如此,texture又如何呢?渲染中用到的 texture一般有两个来源,一个是照片,一个是artist手工画的 前文提到了,照片是gamma = 1/2.2的。一般图象处理软件也都是在gamma空间工作的,所以artist画的图一般也可以认为是gamma = 1/2.2的 所以,我们在pixel shader常可以见到这样的代码: float4 diff = tex2D(diffuse_texture, uv); return diff * max(0, dot(light_dir, normal)); 这样的代码对吗?不对也对。 说其不对,是因为这里没显式地做gamma校正。做校正的话应该是这样的: float4 diff = pow(tex2D(diffuse_texture, uv), 2.2f); // 对输入的纹理进行display gamma,转到线性空间 return pow(diff * max(0, dot(light_dir, normal)), 1 / 2.2f); // 对输出进行encoding gamma,再次转回gamma = 1/2.2空间 也就是说,gamma校正的过程就是把输入的texture都转换到线性空间,并把输出的调整到gamma = 1/2.2的空间 说其对,是因为如果diffuse texture如果是sRGB格式的,那么再读取的时候硬件会把它自动转到线性空间 glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); 如果render target的texture也是sRGB格式的,在输出的时候硬件也会把它自动转到gamma = 1/2.2空间 glEnable(GL_FRAMEBUFFER_SRGB); 所以,如果输入和输出纹理都是sRGB,那么原先那段shader就是正确的。对于不支持sRGB的老硬件,就必须自己做pow了 除了渲染,另一个需要注意gamma的地方就是mipmap。如果原texture是gamma = 1/2.2空间的,那么在建立mipmap chain的时候,需要将原texture先转到线性空间,来计算各级mipmap;完成计算后,再将各级mipmap转到gamma = 1/2.2空间 另外,gamma变换只作用于RGB通道,Alpha透明度则不受影响 对于normal?texture、mask?texture等存放的不是颜色信息,这类texture不应勾选为sRGB 总之,计算都要发生在线性空间,所以输入的纹理要先进行display gamma。如果输出的render target是sRGB格式,输出时要进行encoding gamma 输出时encoding gamma,会导致写入color buffer的颜色是非线性的,这样混合就发生在非线性空间中。解决方法是,在中间计算时不要对输出进行encoding gamma,在最后进行一个屏幕后处理操作对最后的输出进行encoding gamma 最佳选择是采用sRGB格式,这样pow是硬件内自动实现,速度更快,代码也简单。鉴于目前很多texture的数据是gamma = 1/2.2的,而纹理格式却被错误地标记成没有sRGB的,所以需要修改它们的格式标记,并重新建立mipmap 如果在gamma空间中进行着色计算,会造成了渲染出来的游戏总是暗沉沉的(如下右图所示),和真实世界不像 参考 klayge:gamma的传说 candycat1992:【图形学】我理解的伽马校正(Gamma Correction) Unity:LinearRendering-LinearOrGammaWorkflow? Gamma Correction and Why It Matters learnopengl:Gamma Correction (1条消息) 【图形学】我理解的伽马校正(Gamma Correction)_candycat-CSDN博客_gamma校正 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 21:05:40- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |