前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >渲染缓冲对象——高效帧缓冲附件

渲染缓冲对象——高效帧缓冲附件

作者头像
程序员的园
发布2024-09-10 20:36:05
1710
发布2024-09-10 20:36:05
举报
文章被收录于专栏:程序员的园——原创文章

1. 引言

在上一章节讲解FBO时,使用纹理来存储颜色缓存附件、深度缓存附件、模板缓存附件,但纹理并不是唯一的选择。尤其是针对深度缓存附件、模板缓存附件这类不需要在着色器中读取的缓存数据,OpenGL 还提供了另一种更加高效的缓存区附件——渲染缓冲对象(Renderbuffer Object, RBO)附件,用于存储渲染结果。

2. 渲染缓冲对象?

渲染缓冲对象(RBO)是 OpenGL 提供的一种存储渲染结果的帧缓冲对象(FrameBuffer Object,FBO)附件,与帧缓冲对象(FBO)配合使用。

与可以在着色器中采样的纹理附件不同,渲染缓冲对象的不能被直接读取。由于其不可被直接读取的特性,给了OpenGL很多优化空间:RBO直接存储渲染数据,无需进行额外的向纹理特定格式的转换,从而减少了内存带宽的占用。而深度缓冲区和模板缓冲区这类不需要在后续的着色器阶段中被读取和处理的数据,正是RBO的绝佳应用场景。

由于RBO不能被直接读取,所以无法像操作纹理一样从 RBO 中直接获取(采样)数据。但这并不意味着不可以读取RBO中缓存数据,可以借助 glReadPixels接口获得指定区域内的数据,该接口的详细叙述如下:

代码语言:javascript
复制
 //// 从帧缓冲区中读取像素数据
 /// x: 从帧缓冲区读取的像素的左下角 x 坐标
 /// y: 从帧缓冲区读取的像素的左下角 y 坐标
 /// width: 从帧缓冲区读取的像素的宽度
 /// height: 从帧缓冲区读取的像素的高度
 /// format: 像素数据的格式,GL_STENCIL_INDEX, 
 ///        GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, 
 ///          GL_BGR, GL_RGBA, and GL_BGRA, etc
 /// type: 像素数据的类型,GL_UNSIGNED_BYTE, GL_BYTE, 
 ///       GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, 
 ///       GL_INT,
void glReadPixels(GLint x, GLint y, 
        GLsizei width, 
        GLsizei height, 
        GLenum format, 
        GLenum type, 
          void *pixels);

尽管渲染缓冲对象和纹理都能作为 FBO 的附件,用于存储渲染结果,但它们的功能和性能有所不同。

  • 功能差异:纹理可以被采样,可以在着色器中读取和操作;而 RBO 则只能用于渲染,无法直接读取。这使得 RBO通常用于那些只需要存储但不需要处理的缓冲数据。
  • 性能差异:由于 RBO 不需要执行采样和读取操作,因此在存储如深度缓冲或模板缓冲等临时渲染数据时,它能提供比纹理更好的性能表现。这种性能提升对于实时渲染(如游戏或图形应用程序)尤其重要,因为减少内存带宽占用能够使渲染管线更流畅。
  • 内存占用:RBO 的内存占用通常比纹理要少,因为它们不需要存储额外的纹理元数据(如 mipmap 层级、纹理坐标等)。这对于内存资源有限的设备(如移动设备)来说是一个重要的优势。
  • 应用场景:RBO 通常用于存储深度缓冲和模板缓冲等不需要在后续阶段中被读取和处理的数据。而纹理则更适合用于存储需要被采样的颜色缓冲数据,或者需要被多次使用的图像数据。纹理也能用来存储深度缓冲和模板缓冲。所以RBO的应用场景相对局限。

3. 相关接口

RBO的相关接口涉及到其创建、绑定、分配存储空间、附加到FBO等操作,下面是相关接口的详细说明:

代码语言:javascript
复制
 // 创建渲染缓冲对象
// n: 要创建的 RBO 数量
// renderbuffers: 返回的 RBO ID 数组
void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers);

// 绑定渲染缓冲对象
// target: 要绑定的目标,必须是 GL_RENDERBUFFER
// renderbuffer: 要绑定的 RBO ID
void glBindRenderbuffer(GLenum target, GLuint renderbuffer);


// 删除渲染缓冲对象
// n: 要删除的 RBO 数量
// renderbuffers: 要删除的 RBO ID 数组
void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers);

  
  // 为 RBO 分配存储空间
 // target: 要绑定的目标,必须是 GL_RENDERBUFFER
 // internalformat: RBO 的内部格式,例如 GL_DEPTH_COMPONENT, 
 //                 GL_DEPTH24_STENCIL8, GL_RGBA8 等
 // width: RBO 的宽度
 // height: RBO 的高度
void glRenderbufferStorage(GLenum target, GLenum internalformat, 
            GLsizei width, GLsizei height);
            


 // 将 RBO 附加到帧缓冲对象
 // target: 要绑定的目标,必须是 GL_FRAMEBUFFER
 // attachment: 要附加的附件类型,例如 GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT 等
 // renderbuffertarget: RBO 的目标类型,必须是 GL_RENDERBUFFER
 // renderbuffer: 要附加的 RBO ID
void glFramebufferRenderbuffer(GLenum target, GLenum attachment, 
            GLenum renderbuffertarget, GLuint renderbuffer);

相应的代码实操案例如下:

代码语言:javascript
复制
void CreateAndBindFBO(GLuint& fbo,GLuint &colorTexture, GLuint &rbo, int width, int height)
{

  // 创建 FBO
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

  // 创建并绑定颜色缓冲纹理
    glGenTextures(1, &colorTexture);
    glBindTexture(GL_TEXTURE_2D, colorTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);

  // 创建并绑定深度模板纹理
    glGenRenderbuffers(1,&rbo);
    glBindRenderbuffer(GL_RENDERBUFFER,rbo);
    glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH24_STENCIL8,width,height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_STENCIL_ATTACHMENT,GL_RENDERBUFFER,rbo);

  // 检查 FBO 是否完整
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

  // 解除绑定 FBO
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

在这个例子中,首先我们创建了一个渲染缓冲对象 `rbo`,并为它分配了深度-模板格式的存储空间。然后,我们将这个 RBO 附加到帧缓冲对象的深度-模板附件上。

4. 总结

本文在前一章节(帧缓冲)的基础上,介绍了渲染缓冲对象,并通过对比渲染缓冲对象附件和纹理附件,详细说明了它们的区别和适用场景。然后介绍了渲染缓冲对象的相关接口,并给出了相应的代码实操案例。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档