默认情况下,亮度和颜色值在存储到帧缓冲区时被限制在 0.0 和 1.0 之间。 这个起初看似无害的声明让我们总是在这个范围内的某个地方指定光线和颜色值,试图让它们适应场景。 这工作正常并给出了不错的结果,但是如果我们走在一个非常明亮的区域,有多个明亮的光源,总和超过 1.0 会发生什么? 亮度或颜色总和超过 1.0 的所有片段都会被限制为 1.0,这看起来不太好:

由于大量片段的颜色值被限制为 1.0,因此每个明亮片段在大区域内都具有完全相同的白色值,从而丢失了大量细节并使其看起来很假

这个问题的解决方案是降低光源的强度,并确保场景中的任何片段区域的亮度都不会超过 1.0; 这不是一个好的解决方案,因为这会迫使您使用不切实际的照明参数。 更好的方法是让颜色值暂时超过 1.0,并在最后一步将它们转换回原始范围 0.0 和 1.0,但不会丢失细节。

显示器(非 HDR)仅限于显示 0.0 和 1.0 范围内的颜色,但在光照方程中没有这样的限制。通过允许片段颜色超过 1.0,我们可以在称为high dynamic range高动态范围 (HDR) 的情况下使用更大范围的颜色值。高动态范围,明亮的东西可以很亮,暗的东西可以很暗,两者都可以看到细节。

high dynamic range高动态范围最初仅用于摄影,在这种情况下,摄影师以不同的曝光水平拍摄同一场景的多张照片,捕捉大范围的颜色值。 将这些组合起来形成一个 HDR 图像,其中根据组合的曝光级别或查看它的特定曝光,可以看到大范围的细节。 例如,下图(Colin Smith 提供)在低曝光(看窗户)的明亮区域显示了很多细节,但在高曝光时这些细节消失了。 然而,高曝光现在可以在较暗的区域显示出大量以前不可见的细节

这也非常类似于人眼的工作方式和高动态范围渲染的基础。 当光线不足时,人眼会自我适应,因此较暗的部分变得更加明显,对于明亮的区域也是如此。 这就像人眼有一个基于场景亮度的自动曝光滑块。

高动态范围渲染有点像这样。我们允许渲染更大范围的颜色值,收集场景的大范围暗部和亮部细节,最后我们将所有 HDR 值转换回 [0.0, 1.0]这种将 HDR 值转换为 LDR 值的过程称为色调映射并且存在大量色调映射算法,旨在在转换过程中保留大部分 HDR 细节。这些色调映射算法通常涉及有选择地偏向于暗区或亮区的曝光参数。

在实时渲染方面,高动态范围不仅使我们能够超过 [0.0, 1.0] 的 LDR 范围并保留更多细节,而且还使我们能够通过光源的实际强度来指定其强度。例如,太阳的强度比手电筒之类的东西要高得多,所以为什么不这样配置太阳(例如,漫射亮度为 100.0)。这使我们能够使用更逼真的照明参数更正确地配置场景的照明,这是 LDR 渲染无法实现的,因为它们会直接被限制为 1.0。

由于(非 HDR)显示器仅显示 0.0 和 1.0 之间范围内的颜色,因此我们确实需要将当前高动态范围的颜色值转换回显示器的范围。简单地用一个简单的平均值重新转换颜色对我们没有多大好处,因为更亮的区域会变得更加显着。我们可以做的是使用不同的方程和/或曲线将 HDR 值转换回 LDR,让我们可以完全控制场景的亮度。这是之前称为 tone mapping色调映射的过程,也是 HDR 渲染的最后一步。

1.Floating point framebuffers(浮点帧缓冲区)

为了实现高动态范围渲染,我们需要一些方法来防止片段着色器运行后颜色值被限制。 当帧缓冲区使用归一化定点颜色格式(如 GL_RGB)作为其颜色缓冲区的内部格式时,OpenGL 会在将它们存储到帧缓冲区之前自动将值限制在 0.0 和 1.0 之间。 此操作适用于大多数类型的帧缓冲区格式,浮点格式除外。

当帧缓冲区的颜色缓冲区的内部格式指定为 GL_RGB16FGL_RGBA16FGL_RGB32FGL_RGBA32F 时,帧缓冲区被称为floating point framebuffer浮点帧缓冲区,可以存储默认范围 0.0 和 1.0 之外的浮点值。 这非常适合在高动态范围内渲染!

要创建floating point framebuffer浮点帧缓冲区,我们唯一需要更改的是其颜色缓冲区的内部格式参数:

glBindTexture(GL_TEXTURE_2D, colorBuffer);
//设置格式GL_RGBA16F
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);  

OpenGL 的默认帧缓冲区(默认情况下)每个颜色分量仅占用 8 位。 对于每个颜色分量为 32 位的浮点帧缓冲区(当使用 GL_RGB32F 或 GL_RGBA32F 时),我们使用 4 倍的内存来存储颜色值。 由于 32 位并不是真正必要的(除非您需要高精度),因此使用 GL_RGBA16F 就足够了

通过附加到帧缓冲区的浮点颜色缓冲区,我们现在可以将场景渲染到该帧缓冲区中,因为知道颜色值不会被限制在 0.0 和 1.0 之间。 在本章的示例演示中,我们首先将光照场景渲染到浮点帧缓冲区中,然后在屏幕填充的四边形上显示帧缓冲区的颜色缓冲区; 它看起来有点像这样:

//常规绑定framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // [...] render (lit) scene
glBindFramebuffer(GL_FRAMEBUFFER, 0);// now render hdr color buffer to 2D screen-filling quad with tone mapping shader
hdrShader.use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, hdrColorBufferTexture);
RenderQuad();

这里场景的颜色值被填充到浮点颜色缓冲区中,该缓冲区可以包含任何任意颜色值,可能超过 1.0。 在本章中,创建了一个简单的演示场景,其中一个大的拉伸立方体充当隧道,带有四个点光源,一个位于隧道尽头的非常明亮:

std::vector<glm::vec3> lightColors;
//超级亮的一个颜色
lightColors.push_back(glm::vec3(200.0f, 200.0f, 200.0f));
lightColors.push_back(glm::vec3(0.1f, 0.0f, 0.0f));
lightColors.push_back(glm::vec3(0.0f, 0.0f, 0.2f));
lightColors.push_back(glm::vec3(0.0f, 0.1f, 0.0f));  

渲染到浮点帧缓冲区与我们通常渲染到帧缓冲区完全相同。 新的是 hdrShader 的片段着色器,它渲染带有浮点颜色缓冲区纹理的最终 2D 四边形。 让我们首先定义一个简单的传递片段着色器:

#version 330 core
out vec4 FragColor;in vec2 TexCoords;uniform sampler2D hdrBuffer;void main()
{             //常规的fragment渲染vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;FragColor = vec4(hdrColor, 1.0);
}  

这里我们直接对浮点颜色缓冲区进行采样,并将其颜色值用作片段着色器的输出。 然而,由于 2D 四边形的输出被直接渲染到默认的帧缓冲区中,所有片段着色器的输出值最终仍会被限制在 0.0 和 1.0 之间,即使我们在浮点颜色纹理中有几个值超过 1.0。

白色部分的细节完全看不清了

很明显,隧道末端的强光值被限制为 1.0,因为它的很大一部分是完全白色的,在此过程中有效地丢失了所有照明细节。 当我们直接将 HDR 值写入 LDR 输出缓冲区时,就好像我们没有启用 HDR。 我们需要做的是在不丢失任何细节的情况下将所有浮点颜色值转换为 0.0 - 1.0 范围。 我们需要应用一个称为tone mapping色调映射的过程。

2.Tone mapping(色调映射)

Tone mapping色调映射是将浮点颜色值转换为预期的 [0.0, 1.0] 范围的过程,称为低动态范围,而不会丢失太多细节,通常伴随着特定的风格色彩平衡。

更简单的色调映射算法之一是 Reinhard Tone mapping色调映射,它涉及将整个 HDR 颜色值划分为 LDR 颜色值。 Reinhard 色调映射算法将所有亮度值均匀地平衡到 LDR 上。 我们将 Reinhard Tone mapping色调映射包含在之前的片段着色器中,并且还添加了一个gamma correction伽马校正过滤器以获得良好的度量(包括使用 sRGB 纹理):

void main()
{             const float gamma = 2.2;vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;// reinhard tone mapping// 简单粗暴的直接按比例映射到0-1的范围vec3 mapped = hdrColor / (hdrColor + vec3(1.0));// gamma correction mapped = pow(mapped, vec3(1.0 / gamma));FragColor = vec4(mapped, 1.0);
}    

应用 Reinhard 色调映射后,我们不再丢失场景明亮区域的任何细节。 它确实倾向于稍微偏向于较亮的区域,使较暗的区域看起来不那么详细和清晰:

在这里,您可以再次看到隧道尽头的细节,因为木材纹理图案再次变得可见。 使用这种相对简单的色调映射算法,我们可以正确地看到存储在浮点帧缓冲区中的整个 HDR 值范围,从而使我们能够精确控制场景的照明而不会丢失细节。

色调映射的另一个有趣用途是允许使用exposure parameter曝光参数。 您可能还记得在介绍中,HDR 图像包含许多在不同曝光水平下可见的细节。 如果我们有一个具有昼夜循环的场景,那么在白天使用较低的曝光度并在夜间使用较高的曝光度是有意义的,类似于人眼的适应方式。 有了这样的曝光参数,我们就可以配置在白天和晚上在不同照明条件下工作的照明参数,因为我们只需要更改曝光参数。

一个相对简单的exposure tone mapping曝光色调映射算法如下所示:

uniform float exposure;void main()
{             const float gamma = 2.2;vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;// exposure tone mapping//exp(x)返回x的指数,e^x ,exp(0)= 1, exp(1) = 2.7......//这里的exp指的是 e^(-hdrColor*exposure) ,反正就是曝光度越大,mapped越大,无限接近于1vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);// gamma correction // 伽马矫正,适应人眼mapped = pow(mapped, vec3(1.0 / gamma));FragColor = vec4(mapped, 1.0);
} 

在这里,我们定义了默认为 1.0 的曝光统一,并允许我们更准确地指定我们是否希望更多地关注 HDR 颜色值的暗区或亮区。 例如,在高曝光值下,隧道的较暗区域显示的细节明显更多。 相比之下,低曝光在很大程度上消除了黑暗区域的细节,但让我们可以在场景的明亮区域看到更多细节。 看看下面的图片,看看在多个曝光级别的隧道:

该图像清楚地显示了高动态范围渲染的好处。 通过更改曝光级别,我们可以看到场景的许多细节,否则这些细节会因低动态范围渲染而丢失。 以隧道尽头为例。 在正常曝光下,木结构几乎看不到,但在低曝光下,详细的木纹清晰可见。 这同样适用于附近的木制图案,在高曝光下更明显。

3.More HDR(更多HDR)

所示的两种色调映射算法只是大量(更高级)色调映射算法中的一小部分,每个算法都有自己的优点和缺点。一些色调映射算法偏爱某些颜色/强度高于其他颜色,一些算法同时显示低曝光和高曝光颜色以创建更丰富多彩和更详细的图像。还有一组称为 automatic exposure adjustment or eye adaptation 自动曝光调整或眼睛适应技术的技术,它们确定前一帧场景的亮度并(缓慢)调整曝光参数,使场景在黑暗区域变亮或在明亮区域变暗模仿人眼。

HDR 渲染的真正优势真正体现在具有大量照明算法的大型复杂场景中。由于很难在保持可访问性的同时创建用于教学目的的如此复杂的演示场景,因此本章的演示场景很小且缺乏细节。虽然相对简单,但它确实展示了 HDR 渲染的一些好处:高光和暗区的细节不会丢失,因为它们可以通过色调映射恢复,添加多个灯不会导致区域被限制,并且可以指定光值通过不受 LDR 值限制的真实亮度值。此外,HDR 渲染还使其他几种有趣的效果更加可行和逼真;其中一个影响就是bloom,我们将在下一章讨论。

Learn OpenGL 笔记6.7 HDR(高动态范围)相关推荐

  1. Learn OpenGL 笔记6.8 Bloom(高动态范围)

    由于monitor监视器的强度范围有限,明亮的光源和明亮的区域通常难以传达给观看者. 区分显示器上明亮光源的一种方法是让它们发光: 然后光线在光源周围流淌. 这有效地为观看者提供了这些光源或明亮区域非 ...

  2. Learn OpenGL 笔记7.3 PBR-IBL-Diffuse irradiance(Image based lighting-漫反射辐照度)

    IBL,或image based lighting基于图像的照明,是一组照明对象的技术,不是像前一章那样通过直接分析光,而是将周围环境视为一个 big light source大光源.这通常通过操纵立 ...

  3. Learn OpenGL 笔记7.1 PBR Theory(physically based rendering基于物理的渲染 理论)

    PBR,或更通常称为基于物理的渲染,是一组渲染技术,它们或多或少基于与物理世界更接近的相同基础理论.由于基于物理的渲染旨在以物理上合理的方式模拟光线,因此与我们的原始光照算法(如 Phong 和 Bl ...

  4. Learn OpenGL 笔记7.4 PBR-Specular IBL(Image based lighting-特殊的基于图像的照明)

    在上一章中,我们通过预先计算辐照度贴图作为照明的间接漫反射部分,将 PBR 与基于图像的照明相结合. 在本章中,我们将关注反射方程的specular part镜面反射部分: 您会注意到 Cook-To ...

  5. Learn OpenGL 笔记5.11 Anti Aliasing(抗锯齿)

    这种清晰地看到边缘组成的像素结构的效果称为锯齿. 有很多称为抗锯齿技术的技术可以通过产生更平滑的边缘来对抗这种锯齿行为.(小时候打开一个新游戏,第一件事情就是把抗锯齿给关了,开抗锯齿太卡了) 起初,我 ...

  6. learn opengl 笔记 1.2

    1.GLFW GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口.它允许用户创建OpenGL上下文,定义窗口参数以及处理用户输入. 2.GLAD 由于OpenGL驱 ...

  7. Learn OpenGL 笔记6.9 Deferred Shading(延迟着色)

    到目前为止,我们进行照明的方式称为forward rendering前向渲染或forward shading前向着色.我们渲染对象,根据场景中的所有光源对其进行照明.我们为场景中的每个对象分别为每个对 ...

  8. Learn OpenGL 笔记6.5 Normal Mapping(法线贴图)

    我们通过在这些平面三角形上包裹 2D 纹理来增强真实感,隐藏多边形只是很小的平面三角形的事实. 从照明技术的角度来看,确定对象形状的唯一方法是通过其垂直法向量. 这种使用每片段法线与每表面法线相比的技 ...

  9. Learn OpenGL 笔记6.10 SSAO(Screen Space Ambient Occlusion屏幕空间环境光遮蔽)

    我们在基本照明一章中简要介绍了该主题:ambient lighting环境光. Ambient lighting环境光是一个固定的光常数,我们添加到场景的整体照明中以模拟光的scattering散射. ...

最新文章

  1. 推荐阅读的多核编程技术书籍
  2. GentleNet使用之详细图解[语法使用增强版]
  3. 为RecyclerView添加下拉刷新(PullToRefresh)功能
  4. c++ 0x8000ffff灾难性故障_《可靠性设计》——故障模式影响分析
  5. 全分布式集群搭建总结
  6. mysql启动失败2005_数据库2005服务启动不了
  7. P问题 NP问题 和 NPC问题
  8. python怎么直接操作git_基于python实现操作git过程代码解析
  9. android google 下拉刷新 csdn,使用google自带包实现下拉刷新功能
  10. 掌握 3 个搜索技巧,在 GitHub 上快速找到实用软件资源
  11. AWS新用户入门学习必备知识
  12. 王之泰 201771010131《面向对象程序设计(java)》第十六周学习总结
  13. VS2022解决方案及项目重命名
  14. 英伟达RTX 2060发布:《战地5》光追超60帧,349美元(转载自IT之家)
  15. oracle+ebs+fsg报表,EBS 11i FSG报表用XML publish输出问题!!!!
  16. 打印显示打印机未安装
  17. python卷积神经网络图像,python卷积神经网络代码
  18. 【大数据处理技术】实验3
  19. Hack The Box——Remote
  20. 如何在VScode中利用git来下载GitHub上的源码

热门文章

  1. 【无标题】大数据建模、分析、挖掘技术应用
  2. 企业服务行业内容哪些,怎样开展业务,获取精准客户
  3. 15-自己写库函数构建库函数雏形
  4. 基于php的家装主题装修网站-计算机毕业设计
  5. 舍得 舍得 有舍才有得
  6. 初中英语语法总结一览表
  7. jquery autocomplete 实现搜索提示功能,中文/拼音也没问题
  8. HTML期末作业-仿家居装饰公司HTML网站模板(HTML+CSS+JavaScript)
  9. 机器学习——特征工程——交互特征(多项式特征)
  10. 内网多个DHCP Server无法获取到地址上网的解决办法