【OpenGL】LearnOpenGL学习笔记16 - 帧缓冲(FBO)、渲染缓冲(RBO)

上接:https://blog.csdn.net/weixin_44506615/article/details/150696667?spm=1001.2014.3001.5501
完整代码:https://gitee.com/Duo1J/learn-open-gl | https://github.com/Duo1J/LearnOpenGL

在这之前我们已经使用过了深度缓冲 (Depth Buffer)模板缓冲 (Stencil Buffer) 以及最初我们用来写入颜色值的颜色缓冲 (Color Buffer)
这一系列的缓冲结合起来就叫做帧缓冲 (Frame Buffer)

先来了解几个概念,最后我们会应用在 屏幕后处理 (Post Processing)

一、帧缓冲 (Frame Buffer)

GLFW为我们创建了一个默认帧缓冲,所以我们之前从未关注过它。接下来我们来自己创建一个帧缓冲并实现一些特殊的效果

类比之前,我们可以这样来创建和删除一个帧缓冲

unsigned int fbo;
glGenFramebuffers(1, &fbo);
glDeleteFramebuffers(1, &fbo);

绑定帧缓冲

// GL_FRAMEBUFFER,读取和写入都会影响
// GL_READ_FRAMEBUFFER 仅读取
// GL_DRAW_FRAMEBUFFER 仅写入
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// 绑定到默认的帧缓冲
glBindFramebuffer(GL_FRAMEBUFFER, 0);

帧缓冲创建并绑定好了,但是目前它还不完整,一个完整的帧缓冲需要满足以下条件 (这里的中文翻译不是很确切,最好记住英文名)

  1. 附加至少一个缓冲 (颜色、深度、模板)
  2. 至少有一个附件 (Attachment)
  3. 所有的附件都必须完整 (保留了内存)
  4. 每个缓冲都应该有相同的样本数 (Sampler)

二、纹理附件 (Texture Attachment)

我们可以把一个纹理附加到帧缓冲,所有的渲染指令都将会写入到这个纹理中,我们之后在着色器中就可以很方便的使用它

创建纹理附件和创建普通纹理差不多

unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

接下来附加到帧缓冲上

// 附加帧缓冲目标
// 附件类型
// 纹理类型
// 纹理
// Mipmap级别
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

这里附件类型我们还可以附加:
深度缓冲 (GL_DEPTH_ATTACHMENT),纹理格式需要变成GL_DEPTH_COMPONENT
模板缓冲 (GL_STENCIL_ATTACHMENT),纹理格式需要变成GL_STENCIL_INDEX

同时我们也可以将深度和模板缓冲合二为一来节省资源,纹理的32位中将包含24位深度信息和8位的模板信息

glTexImage2D(
  GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, 
  GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);

三、渲染缓冲对象附件 (Renderbuffer Object Attachment)

渲染缓冲对象 (Renderbuffer Object / RBO) 是在纹理之后引入OpenGL的,它会将数据存储为OpenGL原生的渲染格式,它是为离屏渲染 (渲染到一个不同的帧缓冲,而非默认帧缓冲) 到帧缓冲优化过的
它是一个更快的可写存储介质,不会做任何针对纹理格式的转换。通常不可读,但仍然可以使用 glReadPixels 来读取,这会从当前绑定的帧缓冲中读取,而非附件本身

创建渲染缓冲对象

unsigned int rbo;
glGenRenderbuffers(1, &rbo);

绑定

glBindRenderbuffer(GL_RENDERBUFFER, rbo);

由于RBO通常是只写的,所以经常用作深度和模板附件
创建一个深度和模板渲染缓冲对象

glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, screenWidth, screenHeight);

附加到帧缓冲

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);

四、屏幕后处理 (Post Processing)

接下来我们将上面的知识点应用到屏幕后处理上
屏幕后处理 就是将整个场景渲染到一张纹理上之后,再通过对该纹理的修改来创建一些效果,例如模糊、反色、泛光、暗角等等

接下来我们需要创建一个帧缓冲,然后创建并附加纹理附件和渲染缓冲对象附件,接着渲染整个场景到纹理附件上
然后在默认帧缓冲中绘制一个覆盖屏幕的矩形并采样纹理附件

创建帧缓冲、纹理附件、渲染缓冲附件并附加
Main.cpp

// 帧缓冲
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

// 纹理附件
unsigned int framebufferTex;
glGenTextures(1, &framebufferTex);
glBindTexture(GL_TEXTURE_2D, framebufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值