通常来说,在不同设备上看到的颜色是不同的。其中最常提及的概念是高动态光照渲染(High-Dynamic Range,简称 HDR )。它可以使图像在亮度的表现上更丰富。这篇文章讨论设备颜色和校正的相关概念。

眼前的黑不是黑

人眼对亮度的敏感程度不是线性的,因此我们我们更容易看到亮的区域。


上图中左侧是线性渐变的图,右侧是我们实际看到的。在显示器上,输入线性信号就会显示出右图的效果。为了解决这个问题,在显示时会加入一个颜色校正,来保证图片看起来正确,这就是 Gamma Correction,具体说来,这个算法是 pow(color, 1/2.2)。所有的图片和视频都被编码到伽马空间中。可以这样理解,你所看到的一切都不是真的。

伽马校正

通过pow(color, 1/2.2)这个Gamma-encode操作,可以使灰度部分得到更多的色值,得到一张比较“亮”的图片并存储起来。这张图片虽然暗部细节都保留下来了,但是不能直接看这张“亮”的图片,那只是一个中间产物而已。我们需要显示器做一个pow(color, 2.2)的Gamma-decode操作把它压暗。

从上图可以看出当gamma值为2.2时,曲线会上拱,输出值大于实际值,也就使得暗部获得更多的色彩。至于2.2是怎么来的,我只能说是经验数字,没什么科学依据。因此这个值也可以根据自己的实际体验进行调整,不过工业标准就是2.2哦。

虽然这个方案比较完美,但有了伽马校正之后,事情并没有变得简单。因为只有取到线性色值,光线计算才能在正确的线性空间(linear space)中进行,最终显示效果又需要应经过伽马校正。

sRGB

为了规范显示的颜色。微软联合HP、三菱、爱普生等厂商联合开发的sRGB(standard Red GreenBlue)通用色彩标准,绝大多数的数码图像采集设备厂商都已经全线支持sRGB标准,如:数码相机、数码摄像机、扫描仪、显示器等都能看到sRGB的选项。而且几乎所有的打印、投影等成像设备也都支持了sRGB标准。有了这套标准,从理论上保证了各种影音设备上经过校正的颜色显示效果相同。它的校正方式如下图所示:

其中蓝线为经过Gamma-encode的色值,红线为sRGB的值。

Unity中的Gamma

对于PC平台上的程序可以直接设置颜色空间

但移动平台并没有,所以意义并不大。而对于默认的Gamma模式,渲染时shader中读到的颜色和贴图已经应用了gamma-encode。所以它会比实际更亮一些。这也使得模型和场景有种褪色的感觉。对比图如下:

解决它的办法,是在shader中进行Gamma校正:

//input
float3 diffuseCol = pow(tex2D( diffTex, texCoord ), 2.2 );
//output
fragColor.rgb = pow(fragColor.rgb, 1.0/2.2);
return fragColor;

但这也不是万全之策。当混合时,需要用到framebuffer,这时取到的已经是encode的色值。那么两种颜色空间的值(线性和非线性),就会在一起混合。虽然这不是正确的做法,但也只能将就了。

另外也可以通过PostEffect来统一处理颜色校正。这能避免在每个shader中都加入Gamma校正。但其实它是在错误的计算结果上进行修正,并没从根本上还原色彩,而且还产生了性能消耗,因此效果也需要衡量。

由于手机硬件只支持Gamma格式的资源,所以需要使用Gamma工作流。在这种模式下,图和颜色都是Gamma-encode之后的,而引擎将其作为线性输入来处理。为了保证一个合理的输出结果,编辑器在输出结果时也不加Gamma-encode。(错上加错,能是对?我也是醉了,可能是因为图形学第一定律吧)

另一方面,在Unity中还可以直接使用Linear space图元,只要勾选Texture面板中的Bypass sRGB Sample即可。

这样设置后,在线性模式中可以防止其被重复解码。在Gamma模式中,没找到相关记载,我觉得要不就在输出时会对其进行一次encode,要不压根就没什么用。

对于LightMap都是在线性空间下计算,以Gamma color存储的,可以不用担心移动端上色值的问题,记得选中TextureType为Lightmap即可。

最后你要是问Android、IOS支持不支持线性空间?官方表示:

On Android, linear rendering requires at least OpenGL ES 3.0 graphics API and Android 4.3.
On iOS, linear rendering requires the Metal graphics API.

所以基本GG。而且Android机器屏幕也不全是sRGB的,比如华为Mate9就是NTSC。而且有些是1600w色,有些是1670w色,有些厂商偷偷摸摸在后面改个颜色偏向。我觉得只能通过动态调整PostEffect中的Gamma来达到相同的显示效果。

你说的白是什么白

归根到底,出现伽马校正的原因是存储颜色时灰阶色值不够,24位色图片每个通道只有2^8个色阶,总共只能显示2^24种颜色。如果能很精细的映射灰度,就不需要伽马校正。拿白色来说,如果必须用8位色值,白色只能保存为(255,255,255)。但如果用16位浮点数,白色就可以保存为(255.0,255.0,255.0)。这时就可以精确的映射灰度。另一方面,由于有了足够的色值,也可以表现出更亮的白色,具体说就是允许rgb中的值超过1,这就是高动态光照渲染。

HDR

这项技术的核心就在于使用了float16存储颜色数据。在OpenGL中使用

glTexImage2D(GL_TEXTURE_2D, 0, dataType, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);

即可增加图片的存储精度。

它的优点在于:

  • 强光部分颜色不会损失
  • bloom和glow效果支持更好
  • Reduction of banding in low frequency lighting areas

劣势在于:

  • 浮点数渲染会更慢,并且需要更多显存。
  • 不支持硬件抗锯齿。
  • 不是所有硬件都支持。

Unity中的配置

通过在Camera上勾选可以开启:

总结

总的说来,如果感觉褪色严重,就需要进行Gamma校正。在制作流程中,如果希望规避,就改对应的shader,在这个过程中注意性能消耗与视觉效果的性价比。如果性能允许,就打开HDR。如果要使用bloom或glow,也要打开哦,反正都要费性能了,就不差这点显存啦。

参考文献:

  • https://docs.unity3d.com/Manual/LinearLighting.html
  • https://docs.unity3d.com/Manual/HDR.html
  • https://www.zhihu.com/question/27467127/answer/111973548
  • https://www.zhihu.com/question/20602284
  • http://blog.csdn.net/candycat1992/article/details/46228771

OpenGL(十八)Gamma校正 色域 与 HDR相关推荐

  1. OpenGL核心技术之Gamma校正

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  2. OpenCV 【十】——Gamma校正 ——图像灰度变化

    Gamma校正(C++.OpenCV实现) 1.作用: Gamma校正是对输入图像灰度值进行的非线性操作,使输出图像灰度值与输入图像灰度值呈指数关系: 伽玛校正由以下幂律表达式定义: 2.函数原型 v ...

  3. OpenCV 【十四】改变图像的对比度和亮度高度关联章节:OpenCV 【十】——Gamma校正 ——图像灰度变化

    目录 0 提问 1.1 原理 trick: 1.2 代码 1.3 结果 0 提问 访问像素值 用0初始化矩阵 saturate_cast 是做什么用的,以及它为什么有用 1.1 原理 图像处理 一般来 ...

  4. NeHe OpenGL第二十八课:贝塞尔曲面

    NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( ogapo@ithink. ...

  5. OpenGL Gamma校正 (Gamma Correction)

    OpenGL Gamma校正 Gamma校正简介 Gamma校正 sRGB纹理 Gamma校正简介 当我们计算出场景中所有像素的最终颜色以后,我们就必须把它们显示在监视器上.过去,大多数监视器是阴极射 ...

  6. OpenGL基础45:光照矫正(下)之Gamma校正

    接上文:OpenGL基础44:光照矫正(上) 四.Gamma矫正 4.1.人的视觉特性 和很多错视图一样,对于下面这张灰阶图,如果1表示纯白,0表示纯黑,那么这张图片的哪个位置代表的是0.5,也就是自 ...

  7. QT+OpenGL高级光照 Blinn-Phong和Gamma校正

    QT+OpenGL高级光照1 本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主 Blinn-Phong 冯氏光照:视线与反射方向 ...

  8. opengl高级光照之gamma校正

    官方文章 gamma校正 gamma校正概念 一个渐变的效果 通过以下网站调整Gamma值可以观察到效果 色彩管理网 gamma校正 Gamma校正(Gamma Correction)的思路是在最终的 ...

  9. NeHe OpenGL教程 第四十八课:轨迹球

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

最新文章

  1. Hacker News与Reddit的算法比较
  2. ---WebCam网络摄像头12 ---图像编码解码,视频编码解码
  3. 卸载mongodb_【数据库】mongodb数据库安装
  4. 使用 cx recipe 安装 Hybris Commerce Cloud 之后,遇到 indexer workder failed 错误
  5. SQLserver2000 实例管理工具
  6. 实用插件_精选 10 个非常实用的 VS Code 插件
  7. 山东大学 2020级数据库系统 实验一
  8. C++之文件操作探究(一):写文件——文本文件
  9. 史上最全计算机毕业设计题目4(10万套,大部分全国唯一)
  10. 计算机音乐专业学什么软件有哪些内容,电脑音乐入门装备(软件篇)
  11. 系统架构设计师-考试大纲
  12. (TeamTalk服务端源码分析一)TeamTalk服务端部署
  13. MATLAB角度转换为弧度
  14. 穷学生自白:爱情如此奢侈 穷孩子哪有爱的能力
  15. 欢迎使用Markdown编辑器
  16. 【三国演义】——诸葛亮
  17. js简单实现拦截访问指定网址
  18. 关于计算机方面的英语ppt,计算机专业英语ppt.ppt
  19. Android平台TCP网络转发实现方案(redsocks+iptables+socks5)
  20. 赛门铁克SEP架构部署十大常见问题解答

热门文章

  1. “复制”马斯克(二):“一无所有”的世界首富想要什么?
  2. 第三篇:动态 8位数码管显示---亚龙236电路
  3. 盘点2021年针对我国的网络安全事件!
  4. 利用MTurk和Qualtrics发放问卷与数据分析,设置survey code,使用vlookup或python合并csv文件
  5. 服务器压力测试_性能测试新手误区(四):一切来自录制
  6. 测试案例:如何测试一把椅子?
  7. c语言课程设计 水电费,广东工业大学水电费系统C语言设计(文件操作部分)
  8. 帝国cms 调用指定栏目 名称 链接 别名
  9. 群辉docker安装树莓派镜像_群辉docker安装树莓派镜像_如何在树莓派安装Docker
  10. Unity学习笔记:私有变量private如何在编译器可见 公有变量public在编译器隐藏