HDR

一 什么是HDR?

了解HDR前需要先了解什么是LDR。通常受限制与人的视觉系统,通常显示器让显示器支持1670 万(24位)的颜色值,这些颜色值通常可以足够表示一个物体的颜色。显示器屏幕每个像素由3种颜色通道R、G、B组成,每种各占8位,组合起来就是24位,表示值的范围也就是0-255,那么对应的每个颜色通道的对比率范围也就是1:256。我们就称作这样的范围的颜色值叫做 LDR低动态范围 。

对比与LDR,HDR 是 Hight Dynamic Range 的缩写,中文名字叫高动态范围。最初来自摄影技术来自摄影技术,摄影师对一个场景采用不同曝光多张相片,捕捉大范围的色彩,这些图片最终合成为hdr图片。高动态范围可以表示的每个基础颜色的范围超出1:256,那么HDR就可以这样定义了通常把使用颜色对比度超出1:256的颜色值的渲染方式叫做HDR渲染。

二 为什么需要HDR或者说它有什么用 回答问题前先看一下图

 左边的图片没有使用HDR看起来颜色很单调,后面的图片使用了HDR看起来很靓丽,亮的部分和暗的部分对比很明显。明亮的部分细节很丰富。

由于渲染着色中(使用shader)最终的颜色值被限制在0 -1 范围内,所以如果一部分颜色值超出1的值都会被渲染出纯白色,那么亮部的细节就会丢失了。所以为了保留更多的颜色细节尤其是明亮部分的我们需要使用HDR。

三  HDR使用方法

采样一个HDR图片,让后使用某种算法把颜色值限制到LDR输出。

流程图:

1. HDR 格式图片

Radiance:1985年,GregWard创建了Radiance文件格式。今天还在使用。这些文件使用RGBE格式,每像素32位。其概念是使用共享红色,绿色和蓝色指数。它可以处理非常明亮的像素而不损失精度的暗的颜色。可以使用简单的代码快速加载.hdr文件。

OpenEXR:于2003年由Industrial Light and Magic (ILM)作为开放标准发布。该HDR文件格式健壮、高效,主要用于电影生产。OpenEXR支持各种颜色格式,并打包了一套操作HDR图像的工具(库、查看器……)。

在后处理中我们通过帧缓冲的方式处理hdr颜色:

    //定义一个帧缓冲
    unsigned int hdrFBO;
	//初始化帧缓冲
    glGenFramebuffers(1, &hdrFBO);
    // 生成一个包含16位的浮点类型信息的颜色值的图片(GL_RGBA16F),并把它作为hdr的帧缓冲的颜色附件
	//颜色附件可以理解成帧缓冲可以包含的颜色信息的载体
    unsigned int colorBuffer;
    glGenTextures(1, &colorBuffer);
    glBindTexture(GL_TEXTURE_2D, colorBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

不使用hdr时候我们通常生成图片使用数据格式为GL_RGB(A),在上面代码中我们生成图片的时候采用的图片数据类型为GL_RGBA16也可以为 GL_RGB16(不保留透明通道信息),每一个RGB颜色通道存储的类型为16位那么表示的范围就是0.0 -65 536.0 这么多范围已经足够了,此外opengl还支持每一个颜色通道值最大颜色范围为32位(GL_RGBA32F),一般情况下是不需要的因为它会占据很多的内存。

2. 色调映射

色调映射(Tone Mapping)是一个损失很小的转换浮点颜色值至我们所需的LDR[0.0, 1.0]范围内的过程,通常会伴有特定的风格的色平衡(Stylistic Color Balance)。

Reinhard色调映射 

最简单的色调映射算法是Reinhard色调映射,它涉及到分散整个HDR颜色值到LDR颜色值上,所有的值都有对应。Reinhard色调映射算法平均得将所有亮度值分散到LDR上。我们将Reinhard色调映射应用到之前的片段着色器上,并且为了更好的测量加上一个Gamma校正过滤(包括SRGB纹理的使用)。OpenGL着色器代码如下:

void main()
{             
    const float gamma = 2.2;
    //hdrBuffer 为hdr贴图
    vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;

    // Reinhard色调映射
    vec3 mapped = hdrColor / (hdrColor + vec3(1.0));
    // Gamma校正
    mapped = pow(mapped, vec3(1.0 / gamma));
    //颜色输出
    color = vec4(mapped, 1.0);
}   

带有可控曝光度的色调映射

//曝光度
uniform float exposure;

void main()
{             
    const float gamma = 2.2;
    vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;

    // 曝光色调映射
    vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);
    // Gamma校正 
    mapped = pow(mapped, vec3(1.0 / gamma));

    //颜色输出
    color = vec4(mapped, 1.0);
} 

结论:

曝光值越大,图片呈现越亮,暗部的细节越明显。

曝光值越小,图片越暗,亮部的细节越明显。

合理控制曝光度来显示丰富的图片信息。

Reference :https://sudonull.com/post/12412-Learn-OpenGL-Lesson-57-HDR

 

 

 

 

 

 

 

 

 

。 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值