OpenGL 编程指南 (3.2)

1、帧缓冲对象

  帧缓冲对象对于离屏渲染、纹理贴图更新、缓存乒乓技术(buffer ping-pongqing,GPGPU的一种数据传输方式)的实现意义非凡,它减少了大量的数据拷贝工作。

  建立帧缓冲需要负责建立帧缓冲使用的其它缓冲内容,也就是说,新建的帧缓冲只是一个空壳,具体的渲染缓冲对象被称之为帧缓冲附件。下面是一个简单的可用帧缓冲建立示例:

  帧缓冲是比较消耗内存的,所以OpenGL提供了可以将帧缓冲一部分或者全部无效化从而立即释放内存的操作

  void glInvalidFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attackments)//numAttachments是附件的数目,attachments是附件的id

  void glInvalidSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attackments, GLint x, GLint y, GLsizei width, GLsizei height)

2、帧缓冲附件

  GL_COLOR_ATTACHMENTi:第i个颜色缓冲,取值范围从0到GL_MAX_COLOR_ATTACHMENT-1

  GL_DEPTH_ATTACHMENT:深度缓冲

  GL_STENCIL_ATTACHMENT:模板缓冲

  GL_DEPTHx_STENCILy_ATTACHMENT:深度缓冲与模板缓冲的压缩格式(x、y是占用的空间以 位 为单位)

 需要注意的一点是,GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER是等价的,只是在字面意义上使用起来会比较鲜明。由上面的帧缓冲示例可以看出,最后一步是检查它的完整性,结果又以下几种:

3、渲染缓冲(render buffer)

  渲染缓冲内容的存储格式是是格式化后的图像数据,GPU能够直接使用,因此它是一个高效的内存缓冲。同时它也是依附于帧缓冲,只有被关联到帧缓冲对象之后它才有意义。首先分配存储空间

  void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)//target必须是GL_RENDERBUFFER,internalformat是内容的存储格式作为颜色缓冲时应该为下面众多中的一种:

作为深度缓冲、模板缓冲等应该是GL_DEPTH_COMPONENT、GL_DEPTH_COMPONENT16、GL_STENCIL_INDEX、GL_STENCIL_INDEX16、GL_DEPTH_STENCIL等中的一种

  void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)//samples是多采样的数目

 

3.5、framebuffer的存储需求巨大,因此OpenGL提供了一些能够将FBO部分或者整体声明为不在使用的操作并且可以立即释放。

  void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)

  void glInvalidateSubFramebuffer(GLenum target, GLsize numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height)

 

4、多重缓冲

  帧缓冲对象的多渲染缓冲特性是在一个fragment shader中同时写入多个缓冲的能力,也叫MRT(Multiple-Render Target)渲染,能够避免对统一组数据进行多次光栅化等行为。常被用于GPGPU领域,也能能够用于生成几何体或其它信息(如纹理、法线贴图)。fragment shader中使用layout区分多缓冲,如下:

  layout (location = 0) out vec4 normal;

  layout (location = 1) out vec4 color;

  建议在shader中使用layout限定符来确保输出与帧缓冲的附件互相关联,否则OpenGL会在shader的链接阶段完成这项工作。也可以在代码来进行设置

  void glBindFragDataLocation(GLuint program, Gluint colorNumber, const GLchar* name)//colorNumber对应于shader的变量name

  void glBindFragDataLoactionIndexed(GLuint program, Gluint colorNumber, GLuint index, const GLchar* name)//index的取值只能是0或1

  设置正确,shader程序链接完成后可以通过下面方法获取索引、位置

  GLint glGetFragDataLocation(GLuint program, const GLchar* name)

  GLint glGetFragDataIndex(GLuint program, const GLchar* name)

 1)选择颜色缓冲进行读写

  绘制或读取通常与下面几种颜色缓冲内容关联:(1)默认帧缓冲的前、后、左前、左后、右前、右后

                                    (2)自定义帧缓冲的前缓冲,或是任意渲染缓冲附件

  void glDrawBuffer(GLenum mode)//model是上面的关联内容,有GL_FRONT、GL_LEFT、GL_BACK_LEFT等,如果当前绑定的帧缓冲不是默认的,只能使用GL_NONE或者GL_COLOR_ATTACHMENTi

  void glDrawBuffers(Glsizei n, const GLenum* buffers)//buffers只接受GL_NONE、GL_FRONT_LEFT、GL_FRONT_RIGHT、GL_BACK_LEFT、GL_BACK_RIGHT这几种

 2)双源融混

  同一个片元的两个输出作用于同一个帧缓冲中的同一个颜色缓冲,通过fragment shader的第二个输出量实现。

  layout (location = 0, index = 0) out vec4 first_output;

  layout (location = 0, index = 1) out vec4 second_output;

  混合(blend)时glBlendFunc等设置状态使用GL_SRC_COLOR、GL_SRC_ALPHA、GL_ONE_MINUS_SRC_COLOR等时,这些参数作用于第一个输出first_output;GL_SRC1_COLOR、GL_SRC1_ALPHA等则会作用于第二个输出second_output。

  双源融混的实现使用了fragment shader第二个输出,同时这个变量可能关联到多个帧缓冲附件上,因此fragment shader的总输出变量数目会减少,需要对GL_MAX_DUAL_SOURCE_DRAW_BUFFERS进行查询,如果为1,说明这两种功能只能取其一使用。

 

5、读取像素中的数据

 1)使用glReadPixels读取目标内容

  void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)

 读取的是以(x, y)为起点(width, height)为宽度的矩形区域,

 2)如果需要在不同区域之间进行拷贝则需要使用glBlitFramebuffer

  void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield buffers, GLenum filter)

 前面四个src的参数表示的是源数据区域,后四个表示目标数据区域,buffers是GL_COLOR_BUFFER_BIT、GL_DEPTH_BUFFER_BIT、GL_STENCIL_BUFFER_BIT之间的组合来确定需要读取的信息,filter是滤波类型,目标区域与源区域一样大小时并不会发生插值行为,filter并不会发生作用

posted @ 2020-02-24 17:46  no-being  阅读(664)  评论(0编辑  收藏  举报