对Opengl中的帧缓冲的一些理解(延迟渲染,后处理等)

用最通俗的话来说:

咱们能在屏幕上看到东西,这是默认的帧缓冲的信息输出,这个帧缓冲里面包括,颜色缓冲,深度缓冲,模板缓冲等。

而一个默认的帧缓冲是不够用的,不能灵活的处理一些想要的效果。

所以咱们要创建新的帧缓冲,创建一个普通的帧缓冲,需要至少一个颜色附件、一个缓冲,这个颜色附件也就是一张纹理,在绑定这个帧缓冲之后,渲染的东西会全部存储到这张纹理中,可以把这个纹理理解成一个普通的颜色/深度或模板缓冲一样。

而深度和模板的信息需要一个叫做渲染缓冲对象的东西来存储,这就是前面面说到的一个缓冲,这个是在颜色附件之后引入的,存储的是opengl数据原生格式,速度很快。但是渲染缓冲是只写的,不能读取(使用纹理访问),但我们还是可以用glReadPixels来读取(一个缓冲读取到另一个缓冲)。通常进行深度模板测试的时候用这个附件,因为速度快,也不需要读取。


屏幕后效处理

咱们在得到这张纹理后,进行一些比如模糊,滤镜等一些处理,最后在转换到默认帧缓冲,拿一张和屏幕大小的面片渲染咱们处理后的这张纹理,这些处理后就最终得到了咱们所看到的处理后的画面。

还有更复杂的一些后处理,还需要一些深度法线等信息,这时候一个颜色附件就不够用了,法线信息需要存储到新的颜色附件中,这个时候需要输出到多个纹理(附件)中,这也叫做MRT,不要忘记告诉GPU渲染到哪些附件中。

延迟渲染&前向渲染

延迟渲染也是利用帧缓冲去完成的,不过都叫G-Buffer。

延迟渲染主要有两个阶段:

第一阶段,我们先渲染场景一次,获取场景内物体的几何信息,位置,法线,颜色等信息,并存储再帧缓冲的纹理附件中,如下:

对Opengl中的帧缓冲的一些理解(延迟渲染,后处理等)


第二阶段,进行光照处理,恢复到默认帧缓冲,渲染一个屏幕大小的面片,并使用第一阶段的信息对每个面片进行光照处理。

整体如下:

对Opengl中的帧缓冲的一些理解(延迟渲染,后处理等)

利用帧缓冲进行延迟渲染细节步骤如下:

1.创建帧缓冲,然后绑定三个颜色附件,这三个颜色附件分别用来存储场景中物体的位置向量,法线向量,纹理颜色。外加一个深度渲染缓冲,进行深度写入(留作后用)

2.利用最简单的shader渲染场景,并把上述所需要的信息写入四个附件中。

3.恢复到默认帧缓冲,创建屏幕大小面片

4.利用上述三个颜色附件所存储的信息,再加上场景中所有光源的颜色位置信息,及摄像机信息,在一个shader中进行复杂的光照处理

5.输出到屏幕

这就是基本的延迟渲染(未经管线优化)。


相比较前向渲染,延迟渲染有很多优点,它不需要再重复的对很多片段再进行光照处理,因为这些片段都是进行深度测试之后的最顶层的片段。但是延迟渲染也有缺点,比如,不能混合,因为得到的都是最顶层的一个片段,不存在其他片段,所以无法进行混合操作。另一个缺点是迫使整个延迟渲染的场景使用同一种光照算法。

所以为了解决上述问题,通常把渲染器分割成两个部分,一个部分是延迟渲染,一部分是专门为了混合或者其他不适合延迟渲染管线效果而设计的前向渲染部分。

如下:

再延迟渲染的第4步之后,再添加上一个作,用glReadPixels把G-Buffer中的第四个附件(渲染缓冲对象中的深度信息)copy到默认帧缓冲中,这下就有深度信息了,然后再渲染前向渲染的所有东西,最后输出到屏幕。


下面是我结合延迟渲染和前向渲染的一个demo:

小方块(灯源)和天空盒都是使用前向渲染,人物是使用延迟渲染

对Opengl中的帧缓冲的一些理解(延迟渲染,后处理等)