WebGL学习之HDR与Bloom

HDR (High Dynamic Range,高动态范围),在摄影领域,指的是可以提供更多的动态范围和图像细节的一种技术手段。简单讲就是将不同曝光拍摄出的最佳细节的LDR (低动态范围) 图像合成后,就叫HDR,它能同时反映出场景最暗和最亮部分的细节。为什么需要多张图片?因为目前的单反相机的宽容度还是有限的,一张照片不能反映出高动态场景的所有细节。一张图片拍摄就必须要在暗光和高光之间做出取舍,只能亮部暗部两者取其一。但是通过HDR合成多张图片,却能达到我们想要的效果。

hdr

那么在WebGL中,HDR具体指的是什么。它指的是让我们能用超过1.0的数据表示颜色值。到目前为止,我们用的都是LDR(低动态范围),所有的颜色值都被限制在了 [0,1] 范围。在现实当中,太阳,灯光这类光源它们的颜色值肯定是远远超出1.0的范围的。

本节实现的效果请看hdr & bloom

hdr & bloom

浮点帧缓冲

当帧缓冲使用标准化的定点格式(像gl.RGB)为其颜色缓冲的内部格式,WebGL会在将这些值存入帧缓冲前自动将其约束到0.0到1.0之间。这一操作对大部分帧缓冲格式都是成立的,除了专门用来存放被拓展范围值的浮点格式。

WebGL扩大颜色值范围的方法就是:把颜色的格式设置成16位浮点数或者32位浮点数,即把帧缓冲的颜色缓冲的内部格式设定成 gl.RGB16F, gl.RGBA16F, gl.RGB32F 或者 gl.RGBA32F,这些帧缓冲被叫做浮点帧缓冲(Floating Point Framebuffer),浮点帧缓冲可以存储超过0.0到1.0范围的浮点值,所以非常适合HDR渲染。

创建浮点帧缓冲,我们只需要改变颜色缓冲的内部格式参数就行了(注意 gl.FLOAT参数):

gl.bindTexture(gl.TEXTURE_2D, colorBuffer); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, gl.RGB, gl.FLOAT, NULL);

帧缓冲默认一个颜色分量只占用8位(bits)。当使用一个使用32位每颜色分量时(使用gl.RGB32F 或者 gl.RGBA32F),我们需要四倍的内存来存储这些颜色。所以除非你需要一个非常高的精确度,32位不是必须的,使用 gl.RGB16F就足够了。

色调映射

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

最简单的色调映射算法是Reinhard色调映射,它涉及到分散整个HDR颜色值到LDR颜色值上,所有的值都有对应。Reinhard色调映射算法平均地将所有亮度值分散到LDR上。将Reinhard色调映射应用到之前的片段着色器上,并且加上一个Gamma校正过滤:

void main() { const float gamma = 2.2; 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); }

有了Reinhard色调映射的应用,我们不再会在场景明亮的地方损失细节。当然,这个算法是倾向明亮的区域的,暗的区域会不那么精细也不那么有区分度。

另一个色调映射应用是曝光(Exposure)参数的使用。HDR图片包含在不同曝光等级的细节。如果我们有一个场景要展现日夜交替,我们当然会在白天使用低曝光,在夜间使用高曝光,就像人眼调节方式一样。有了这个曝光参数,我们可以去设置可以同时在白天和夜晚不同光照条件工作的光照参数,我们只需要调整曝光参数就行了。

一个简单的曝光色调映射算法会像这样:

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); } 什么是Bloom

Bloom 泛光 (或者眩光),是用来模拟光源那种发光或发热的技术。区分明亮光源的方式是使它们发出光芒,光源的光芒向四周发散,这样观察者就会产生光源或亮区的确是强光区。Bloom使我们感觉到一个明亮的物体真的有种明亮的感觉。而Bloom和HDR的结合使用能非常完美地展示光源效果。

bloom

泛光的品质很大程度上取决于所用的模糊过滤器的质量和类型。下面这几步就是泛光后处理特效的过程,它总结了实现泛光所需的步骤。

泛光处理过程

提取亮色

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdzjz.html