HDR

Framebuffer中的亮度和颜色值的范围被限制在0.0和1.0之间。我们在场景中设置光和颜色的时,也只能这个范围取值。这么做大部分情况下是OK的,结果也还可以,但是当场景中有一块多光源,亮度总合超过1.0的区域时,结果是什么样的?答案是所有的亮度或颜色值超过1.0的片段被直接截断到1.0。这并不是我们想要的结果!

由于大量的片段亮度或颜色被直接截断到1.0,所以这些被截断的片段存的值都是白色值,得到的画面是看起来白白的一大块,很明显的丢失了大量的细节,看起来不真实。

这种问题的一种解决方式是降低光源强度并保证场景中没有区域亮度超过1.0,但这不是一个好的解决方式,因为这样场景的光源亮度被限制,自然而然真实度就会降低。好的解决方式是允许颜色值暂时超过1.0,输出时才变换它到0.0和1.0之间,这样做才不会丢失细节。

虽然显示器只能显示0.0到1.0范围的颜色,但光照计算时没有这个范围限制。我们可以使用高动态范围(HDR)来保存片段颜色超过1.0的值。HDR的颜色范围值可模拟从最亮的太阳直射到最暗的阴影,并且细节可见。

HDR最早用于拍摄,摄像师通过拍摄多张同一场景下不同曝光度的照片来合成最终的HDR图像,基于这些不同曝光度,使得HDR照片有大范围的细节被保留。举个例子,下面的图像展示了长曝光下获取了大量的场景细节,这些细节在短曝光下是拍摄不到的。

这和人眼的工作原理很像,当光线微弱或强烈时,人眼会自我调节来看清楚那些很黑或者很亮的区域,人眼的这种调节机制就好像人眼有一个根据场景亮度自动设置曝光度的滑条。

HDR渲染跟上述原理很相似。我们用精度更高的值来保存大范围的黑到亮的区间对应的颜色值,最后图像输出时把HDR值转换回低动态范围(LDR)[ 0.0, 1.0]范围。这个转换过程称为色调映射(tone mapping),而且目前已经有大量的tone mapping算法使得转换过程尽可能的保留更多的HDR细节。

实时渲染中的HDR不仅可以使用超出LDR的[0.0, 1.0]的值范围和保留更多的细节,而且还可以指定光源的真实亮度。比如,太阳比其他的东西比如闪电来得亮,那么可以指定太阳的亮度为10.0。这样我们可以在场景中设置更加真实的光照参数,而这些参数是没法在LDR渲染中用的,因为它们被直接截断到1.0。

因为显示器只能显示0.0到1.0范围的值,我们需要把当前的HDR颜色值转换回显示器的范围。简单的用平均算法不够好,因为会使得结果还是一片白的情况。我们可以采用其他的公式或者曲线来做HDR到LDR的转换,这个转换过程就是前面提到的 色调映射(tone mapping),它是HDR渲染的最后阶段。

Floating point framebuffers

为了实现HDR渲染,我们需要避免颜色值在片段着色处理时被截断。当framebuffer使用标准化的 fixed-point的颜色格式(比如 GL_RGB)作为colorbuffer的内置格式时,OpenGL会在保存颜色值到framebuffer前,自动截断颜色值到0.0 到 1.0。这个截断操作对大部分的颜色格式都会执行,floating point格式除外,这样它可以用来保存HDR值。

当framebuffer的colorbuffer的格式被设置为GL_RGB16F, GL_RGBA16F, GL_RGB32F 或GL_RGBA32F时,framebuffer便可以存储0.0 到 1.0范围外的颜色值,完美满足HDR渲染的要求。

创建浮点framebuffer只需要改变colorbuffer的内部格式参数:

OpenGL默认的framebuffer的颜色格式是8位表示一个颜色分量。 GL_RGB32F 或GL_RGBA32F格式的浮点framebuffer用32位表示一个颜色分量,内存占用是默认颜色格式的4倍。大部分情况下,32位精度过于高,确实没啥必要,GL_RGBA16F格式16位在实际应用中已经足够。

场景的颜色值包含可能超过1.0的任意值被放进浮点colorbuffer。这篇教程的简单演示场景中,用一个大型的拉长的盒子来模拟一个隧道,里面放置4个点光源,其中在隧道尽头放置的点光源非常亮。

渲染浮点framebuffer跟正常渲染framebuffer基本一样。区别是片段着色器不同。我们先暂时定义一个简单的pass-through片段着色器:

这里我们直接对浮点colorbuffer采样,并用于片段着色器的输出。这样会导致输出值被截断到0.0到1.0,尽管浮点颜色贴图的存值有些超过1.0。

很明显,隧道尽头的光源强度值被截断到1.0,因为大部分的区域是全白,在处理过程失去了超过1.0的值,因为我们直接把HDR转换到LDR。我们需要改进这个转换过程,使得转换到LDR后,保留更多的细节。我们称这个过程为色调映射tone mapping。

Tone mapping

色调映射是把HDR浮点颜色值转换到最后的LDR[0.0, 1.0]颜色区间的过程,并尽量不丢失过多细节。

最简单的tone mapping算法是Reinhard tone mapping,我们把Reinhard tone mapping放到早版本的片段着色器中,并且做了伽马矫正(gamma correction)

Reinhard tone mapping算法使得明亮区域不再丢失细节,但它简单的反比例降低亮度值,使得黑的区域丢失了细节,降低了黑的区域的区分度。

这里可以重新看见隧道尽头木板的材质纹理。

另一个tone mapping的有趣应用是允许使用曝光参数。在前文HDR图像的介绍中,提到了不同的曝光度可得到更多的细节。如果我们场景中有白天夜晚循环天气系统,明智的做法是白天使用低曝光度,晚上使用高曝光度,就像人眼的自我适应。这个曝光参数我们可以调节以适应白天黑夜不同的的光照条件。
一种相对简单的exposure tone mapping算法如下:

这里我们定义了exposure uniform变量,初始值时1.0,并允许我们可以根据黑或亮来调节它。比如,高exposure 值使得黑的区域很明显的显示出更多的细节,低exposure 值使得黑的区域的细节大量丢失,但我们看到亮的区域更多的细节。见下图:

上面的图像很好的展示了HDR渲染的优势。通过调节曝光度我们获取了场景中不同的细节,这些在LDR渲染中是没法做得的。举隧道尽头为例,普通曝光度下木头纹理很难看见,但在低曝光度下木头纹理很清楚。

More HDR

上述介绍的两种tone mapping算法只是大量tone mapping算法的小部分,不同的算法都有其优势和不足。有的算法关注特定的颜色或强度的处理,有的算法同时处理低和高曝光度来创建色彩和细节丰富的图像。还有一种称为自动曝光调节或自适应的技术用来模拟人眼的自我调节,它根据场景中上一帧的亮度来(慢慢的)调节曝光系统,黑的区域逐渐变得没那么黑,亮的区域逐渐变得没那么亮。

更进一步,HDR渲染使得很多有趣的画面效果变成可能和更加真实。这些效果中的一种就是bloom,我们下次再来讨论。

附原文地址,代码原文中有下载!
http://learnopengl.com/#!Advanced-Lighting/HDR

附Unity里根据本文实现的HDR前后对比图:

HDR in OpenGL相关推荐

  1. [转]HDR渲染器的实现(基于OpenGL)

    http://dev.gameres.com/Program/Visual/3D/HDRTutorial/HDRTutorial.htm 作者:何咏(欢迎和大家交流,我的QQ:35574585,Ema ...

  2. OpenGL HDR色调映射的实例

    OpenGL HDR色调映射 先上图,再解答. 正常显示 按下M键 完整主要的源代码 源代码剖析 先上图,再解答. 正常显示 按下M键 完整主要的源代码 #

  3. OpenGL HDR曝光的实例

    OpenGL HDR曝光 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <string> #include <vmath.h& ...

  4. OpenGL HDR渲染

    OpenGL HDR渲染 HDR渲染简介 浮点帧缓冲 色调映射 HDR渲染简介 一般来说,当存储在帧缓冲(Framebuffer)中时,亮度和颜色的值是默认被限制在0.0到1.0之间的.这个看起来无辜 ...

  5. OpenGL基础50:HDR

    一.HDR与LDR 由于显示器只能显示值为0.0到1.0间的颜色,因此当数据存储在帧缓冲(Framebuffer)中时,亮度和颜色的值也是默认被限制在0.0到1.0之间的,这个颜色范围即是LDR(Lo ...

  6. OpenGL(十八)Gamma校正 色域 与 HDR

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

  7. OpenGL核心技术之HDR

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

  8. OpenGL之HDR

    参考: https://learnopengl.com/Advanced-Lighting/HDR 当亮度和颜色存储在帧缓冲中时,它们的默认值被限定在0.0和1.0之间,由于这个原因导致我们总是在这个 ...

  9. Learn OpenGL 笔记6.7 HDR(高动态范围)

    默认情况下,亮度和颜色值在存储到帧缓冲区时被限制在 0.0 和 1.0 之间. 这个起初看似无害的声明让我们总是在这个范围内的某个地方指定光线和颜色值,试图让它们适应场景. 这工作正常并给出了不错的结 ...

最新文章

  1. LeetCode 1 两数之和
  2. 韩顺平循序渐进学java 第10.11讲 继承.重载.覆盖
  3. Java语言中的-----访问修饰符
  4. POJ 1952 BUY LOW, BUY LOWER
  5. 杭州之行--记杭电网新恩普杯程序设计邀请赛
  6. 计算机网络双向传输,计算机网络:传输层(2)
  7. python复制csv数据_如何使用Python将CSV数据复制到现有xlsx文件
  8. 51单片机开发软件keil4的安装(win10)
  9. 批量生成PDF417码
  10. python+selenium自动化测试环境搭建步骤(selenium环境搭建)-绝不浪费您的时间
  11. mysql pxc集群介绍_MySQL中PXC集群的介绍
  12. 什么是嵌入式开发?嵌入式是什么?初学者必看。
  13. 矢量绘图界的性价比之王-Affinity Designer
  14. 操作ADS1115进行4个通道AD值的读取
  15. 最佳牛栏(前缀和+二分)
  16. 关于TI XDS100V1和XDS100V3仿真器电脑无法识别的解决办法
  17. C7:如何使用JEPG Simulation进行ColorTuning?
  18. 如何区分自己mac电脑的CUP型号
  19. Android 换肤指南
  20. TMC2208电机驱动简介

热门文章

  1. Keil实例仿真AT89C51串口UART收发数据(附程序)
  2. MCC 移动设备国家代码 (Mobile country code) 概述 MCC 国家/地区代码 注释 概述 移动设备国家代码 ( Mobile country code / MCC ) 定义于国际
  3. 联想主板9针开关接线图_家用配电箱安装接线图解
  4. Python_Example_ Data Structures and Algorithm Analysis 学习/示例
  5. docker容器使用/bin/bash命令
  6. vr虚拟现实视频软件有哪些
  7. Creo三维模型导出成SolidWorks格式
  8. 如何在ppt中插入另一张ppt 的内容
  9. 单片机编程自己编写的一个很简单的传感器控制代码
  10. 科研经验001:文献筛选下载和管理