HDR与Bloom
HDR
HDR(Hight Dynamic Range,高动态范围):
一般来讲,在我们的屏幕上显示的一个帧(Frame),在OPENGL中是以**帧缓冲(Framebuffer)**的形式存储的,默认情况下它的画面的亮度和颜色的值是被限制在0.0到1.0之间的一个值。
这导致倘若我们在着色器的使用过程中有超过的了1.0的亮度范围,(比如:我们正常使用的点光源亮度为1.0,若有多个点光源叠加照射在物体上,就有可能超过1.0,就会导致一部分片段的光照强度会被约束在1.0,造成画面失真。)
而我们需要做的就是代替系统,将当前的亮度合理的分配至0.0-1.0的屏幕亮度范围,即可使画面恢复正常的显示。
这个亮度分配通常会在片段着色器内进行。但是由于目前我们的渲染过程中,使用了很多个着色器。
如果我们只修改了一个着色器内的亮度分配,其他的着色器却没有更改,就会导致只有一部分的画面显示正常。
所以最懒的方式是将整个画面作为一个纹理导入一个专用的着色器中进行处理,再将画面输出。
那么如何将画面导出为一个纹理呢?
其实很简单,我们的屏幕的每一帧的画面的存储方式就是一个纹理,只不过它处理完成后直接被输出到屏幕上了。
那么我们只需要创建一个帧,这个帧拥有一个可以存储更大颜色范围的纹理,让最初的绘制不再绘制在屏幕上,而是绘制在这个帧的纹理上。
要进行画面亮度的重分配,首先我们需要将原本会显示在 默认帧(屏幕) 上的画面,用一个新的帧作为中间人存储,这个帧应该含有一个颜色范围更大的纹理。
随后将这个纹理,作为默认帧的输入,在绘制过程中调节纹理的亮度,并绘制在默认帧(屏幕) 上即可。
由于我们最后在默认帧上绘制时,只需要绘制一个整幅的经过亮度调节的图像,所以绘制一个带有该纹理的屏幕大小的四边形就可以。
我们预计将会得到如下的结果。
浮点帧缓冲
创建帧缓冲
我们之前一直都是在默认帧渲染,它的默认光照强度是0-1.0。
glBindFramebuffer(GL_FRAMEBUFFER, 0);
我们需要创建一个新的帧,它的纹理应该可以存储那些大于1.0的浮点数据,也就是我们需要它的数据类型可以更大。
像其他创建opengl顶点数组或纹理一样,我们首先需要向系统获取一个可用的该类型的索引,这类索引通常为一个GLuint类型的值,所以我们新建一个GLuint类型的变量fbo(frame buffer object) 来存储。
//创建一个新的帧
GLuint fbo;
//注意传的是地址
glGenFramebuffers(1, &fbo);
随后由于我们要为这个帧进行一些操作,所以需要告诉系统,当前的帧要切换为我们新建的fbo先生。
这个过程我们称为绑定,在OPENGL中大部分的类型的操作都需要在绑定后进行操作,比如顶点数组(vao),顶点缓冲(vbo),纹理,还有接下来将会介绍的渲染缓冲(Render buffer)。
虽然我们可以在对它进行操作的时候再去绑定。但是,我们接下来肯定要对它进行操作的,所以先绑上也没什么坏处,对吧?
//绑定当前的帧缓冲为索引号fbo的帧缓冲
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
一个可用的帧,必须包含一个用于输出的纹理缓冲区,用来存放渲染生成的图像。我们之前使用的默认帧(默认索引为:0) 的纹理缓冲区就是我们的屏幕。
屏幕上印刷的每一帧实际上就是一张2D的图片。
而一个帧还可以包含,深度缓冲和模板缓冲用于相应的需求。
在HDR中我们只需对图片的亮度进行处理,所以只要在新建的帧上挂载纹理缓冲即可。
创建纹理
同样,我们第一步要获取一个可用的纹理索引,随后绑定纹理。