OpenGL帧缓冲区多线(FBO)基本概念

时间:2022-02-09 05:00:09
    帧缓存:它是屏幕所显示画面的一个直接映象,又称为位映射图(Bit Map)或光栅。帧缓存的每一存储单元对应屏幕上的一个像素,整个帧缓存对应一帧图像。     帧缓冲区是指服务器(显存)中存储像素相关信息(颜色、深度)的存储空间。系统提供了帧缓冲区对象包括多个缓冲区,有颜色缓冲区、深度缓冲区、模板缓冲区等。
一、缓存的分类
1. 颜色缓存
指程序员绘图所用的缓存,分为:
左、右缓存——用于立体感视图(必须要有左缓存);
前、后缓存——用于双缓存(必须要有前缓存);
4个辅助缓存——可选择的、不可显示(程序员可以自己定义和使用它们)。
2. 深度缓存
用来存储每个象素的深度值,也称为Z缓存。
3. 模板缓存
可以将作图限制在屏幕的某些部分中进行。
4.累积缓存
包含RGBA颜色数据,通常用于将一系列图象累加成一幅最终的合成图象。
象素不能直接绘制到累积缓存中,累加操作常常先在矩形块中进行,然后再与颜色缓存交换数据。

二、缓存的操作
1. 清空缓存
(1). 指定要写入缓存的清除值:
glClearColor()——为颜色缓存设置清除值(red,green,blue,alpha);
glClearIndex()——为颜色索引缓存设置清除值(index);
glClearDepth()——为深度缓存设置清除值(默认为1.0);
glClearStencil()——为模板缓存设置清除值(默认为0.0);
glClearAccum()——为累积缓存设置清除值(red,green,blue,alpha);
(2). 清除指定的缓存:
glClear(GLbitfield mask);
mask的值是GL_COLOR_BUFFER_BIT、GL_DEPTH_BUFFER_BIT、GL_STENCIL_BUFFER_BIT和GL_ACCUM_BUFFER_BIT等常数的按位逻辑或(OR)。可以一次清除多个缓存,如硬件支持同时清除这些缓存,则操作同时进行;否则,按顺序清除各个缓存。
2. 为读写操作选择颜色缓存
    绘图操作的结果可以放入任何一个颜色缓存中:前、后、左前、左后、右前、右后或任意辅存,程序员可选择单个缓存作为绘图目标或读取目标。对绘制图形而言,也可将目标同时绘制到几个缓存中,用glDrawBuffer()函数来选择将要写入的缓存;用glReadBuffer()函数来选择缓存,作为glReadPixels()、glCopyPixels()、glCopyTexImage*()和glCopyTexSubImage*()的应用目标。
3. 缓存的屏蔽(掩码)
    OpenGL在向激活的颜色、深度和模板缓存中写入数据之前,需按下面函数指定的掩码对这些数据进行屏蔽操作。每个掩码要与对应的待写数据进行按位逻辑与(AND)操作。
void glIndexMask(GLuint mask);
mask默认为1。若掩码中出现1,则颜色索引模式中相应的位被写入;而在0出现的位,则不写。 
void glColorMask(GLboolean red,green,blue,alpha);
默认为GL_TRUE,表示相应的分量已写入;若为GL_FALSE,则没写入。
void glDepthMask(GLboolean flag);
默认为GL_TRUE,表示深度缓存被激活用于写操作;若为GL_FALSE,则取消。
void glStencilMask(GLuint mask);
默认为1,和颜色索引类似。

二、片元的测试和操作
    在OpenGL确定了应该生成的片元及绘制颜色后,仍然需要几个处理过程来控制如何将该片元作为一个象素绘制到帧缓存中,以及确定是否需要这样做。本节描述了在放入帧缓存之前,片元所必须通过的完整测试集合,并且描述了在片元写入时可能进行的最后操作。测试和操作按下列次序进行,若在前面的测试中片元被删除,则不再进行后面的测试或操作。
·剪取测试
·alpha测试
·模板测试
·深度测试
·混合
·抖动
·逻辑操作

1 .剪取测试
剪取测试只是使用屏幕矩形区域进行的模板测试的翻版,但是由于很容易用硬件快速实现,所以比以软件方式执行的模板要快。
利用glScissor()函数,可以定义窗口中的一个矩形区域,并将作图限制在其中。若片元落在该矩形区,则剪取测试通过,否则片元被删除。
void glScissor(GLint x,GLint y,GLsizei width,GLsizei height);
glEnable(GL_SCISSOR_TEST):激活剪取测试;
glDisable(GL_SCISSOR_TEST):取消剪取测试。
默认情况下,矩形与窗口的大小相同,剪取处于取消状态。

2. alpha测试
在RGBA模式下,根据alpha测试中的alpha值,来确定是接收还是拒绝一个片元。
glEnable/glDisable(GL_DEPTH_TEST):激活/取消alpha测试
glAlphaFunc设置alpha测试的参考值和比较函数:
void glAlphaFunc(GLenum func,GLclampf ref);
参考值ref取值在0和1之间截取。参数func的可能值及其含义如下:
GL_NEVER:总不接受该片元;GL_ALWAYS:总是接受该片元;
GL_LESS:若片元alpha<参考alpha ,接受该片元;GL_LEQUAL:片元alpha≤参考alpha,接受;
GL_EQUAL:片元alpha=参考alpha,接受;GL_GEQUAL:片元alpha≥参考alpha,接受;
GL_GREATER:片元alpha>参考alpha,接受;GL_NOTEQUAL:片元alpha≠参考alpha,接受;

3. 模板测试
只在有模板缓存的情况下才会发生。如果没有模板缓存,则模板测试总能通过。模板化适用于这样的测试,这种测试对存储于模板缓存中的象素值与参考值进行比较,根据比较的结果,对模板缓存中的值进行修改。void glStencilFunc(GLenum func,GLint ref,GLuint mask);此函数为模板测试设置比较函数(func)、参考值(ref)以及掩码(mask)。利用比较函数可以对参考值和模板缓存中的值进行比较,而比较仅适用于掩码的相应位为1的位。比较函数的可能值与glAlphaFunc()中的比较函数的可能值相同,但含义相反。void gltencilOp(GLenum fail,GLenum zfail,GLenum zpass);
此函数说明当片元通过或未通过模板测试时,如何对模板缓存中的数据进行修正。三个参数fail、zfail、zpass
可以为:
GL_KEEP:保持当前值
GL_ZERO:以0替换
GL_REPLACE:以参考值替换
GL_INCR:增加该值(在0~最大无符号整数值之间)
GL_DECR:减小该值(在0~最大无符号整数值之间)
GL_INVERT:对该值按位取反
若片元未通过模板测试,则应用fail函数;
若片元通过模板测试,但深度测试失败,则应用zfail函数;
若片元通过模板测试,且通过深度测试,或没有深度测试,则应用zpass函数。
默认情况下,三个模板操作都是GL_KEEP。
模板测试最典型的应用就是屏蔽掉屏幕的不规则区域,以避免在该区域作图。

4. 深度测试
对于屏幕上的每个象素,深度缓存时刻追踪视点与占据该象素的物体之间的距离。若通过了深度测试,输入的深度值就将取代深度缓存中的相应值。
深度缓存通常用于消除隐藏表面的操作。最初,深度缓存通常是以距离视点尽可能远的值来填充的,因此任何物体的深度都比初始状态更近。
glEnalbe(GL_DEPTH_TEST);//激活深度测试
glClearDepth(1.0);//清除深度缓存
可以用glDepthunc()函数为深度测试选择不同的比较函数。
void glDepthFunc(GLenum func);
此函数为深度测试设置比较函数。func的值必须为GL_NEVER、GL_ALWAYS、GL_LESS、GL_LEQUAL、GL_EQUAL、
GL_GEQUAL、GL_GREATER或GL_NOTEQUAL。如果z值与深度缓存中的值满足确定的关系,则输入片元通过深度测试。

5. 混合、抖动和逻辑操作
一旦输入的片元通过了所有的测试,它就可以与颜色缓存中的当前内容按某种方式合并起来。最简单的方法,也是默认操作,就是将当前值覆盖掉。
在RGBA模式中,如果希望片元是半透明的或是消除了锯齿现象的,程序员可以将该片元值与缓存中的值作一平均,即混合。
对于可用颜色较少的系统,可以以牺牲分辨率为代价,通过颜色值的抖动来增加可用颜色数量。抖动操作是和硬件相关的,OpenGL允许程序员所做的操作就只有打开或关闭抖动操作。实际上,若机器的分辨率已经相当高,激活抖动操作根本就没有任何意义。要激活或取消抖动,可以用glEnable(GL_DITHER)和glDisable(GL_DITHER)函数。默认情况下,抖动是激活的。在颜色索引模式中,可以利用任意的按位逻辑操作,将输入片元与已写入的象素进行合成。

 同时可以使用自定义的帧缓冲区对象来存储绘制结果,而不是直接放到系统缓冲区中渲染,如红宝书中P337页的例子。

     方法是,先自定义一个帧缓冲区对象,并指定其附加的渲染缓冲区(真正放颜色和深度值的地方),使用glBindFramebuffer(GLenum target, GLuint framebuffer); 来使用自定义的帧缓冲区 framebuffer,附加上glFramebufferRenderbuffer() 后,之后的绘制结果就会被保存到该缓冲区对象指定的附加渲染缓冲区中;

     也可以使用glFramebufferTexure2D(GLenum traget, GLenum attachment, GLenum texturetarget, GLuint texure, GLint level);来将某一附加缓冲区attachment与某纹理对象texuretarget(事先定义好)相关联,这样绘制的结果被自动保存到该2D纹理对象中。

    有个文章解释了帧缓冲区对象(Frame buffer Object)  和 纹理对象 以及 渲染缓冲区对象 的关系。 http://blog.csdn.net/zhihuier/article/details/8060266

    也就是说,一个帧缓冲区对象一般由  GL_COLOR_ATTACHMENTi (可多个,i从0起)、 GL_DEAPTH__ATTACHMENT等附加缓冲区构成,这些附加缓冲区可以使用

 (1) glFramebufferRenderbuffer()与自定义的渲染缓冲区对象联系起来

 (2) glFramebufferTexure2D/1D/3D()与自定义纹理对象联系起来

    注意:FBO本身并没有图像数据存储区,只有多个关联(多个渲染缓冲区对象及纹理对象)。


转载地址:http://www.cnblogs.com/wenshanzh/archive/2013/04/16/3024607.html