目录
相关文章
OpenGL系列之一:OpenGL第一个程序
OpenGL系列之二:绘制三角形
OpenGL系列之三:三角形顶点增加颜色
OpenGL系列之四:绘制四边形
OpenGL系列之五:绘制点和线
OpenGL系列之六:绘制立方体
OpenGL系列之七:纹理贴图
OpenGL系列之八:立方体纹理贴图
OpenGL系列之九:glsl着色器语言
OpenGL系列之十:VAO、VBO、EBO的应用
OpenGL系列之十一:Shader图片转场切换动画
OpenGL系列之十二:Shader燃烧动画
OpenGL系列之十三:实现Shader绚丽动画
OpenGL系列之十四:实现相机抖音特效
OpenGL系列之十五:实现美颜相机
OpenGL系列之十六:实现大眼特效
OpenGL系列之十七:实现人脸贴纸
简单介绍
FBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO)。
使用 FBO 可以让渲染操作不用再渲染到屏幕上,而是渲染到离屏 Buffer 中,然后可以使用 glReadPixels 或者 HardwareBuffer 将渲染后的图像数据读出来,从而实现在后台利用 GPU 完成对图像的处理。
实现步骤
1.创建FBO
这里我们是以OpenGL系列之十四:实现相机抖音特效,这篇文章的代码为基础
这里我封装在了CCFBOHelper中,如下所示(这里可以进行多次离屏渲染,因此我这里创建了两个,如果只需要一次那就创建一个就行)
CCFBOHelper.h
#ifndef OPENGLCAMERA_CCFBOHELPER_H
#define OPENGLCAMERA_CCFBOHELPER_H
#include "CCGLPrimitivesDef.h"
class CCFBOHelper {
public:
GLuint m_FboTextureId[2];
GLuint m_FboId[2];
int textureWidth;
int textureHeight;
CCFBOHelper();
~CCFBOHelper();
void bindFBO(int index);
void unBindFBO();
bool createFBO(int textureWidth,int textureHeight);
};
#endif //OPENGLCAMERA_CCFBOHELPER_H
CCFBOHelper.cpp
#include "CCFBOHelper.h"
CCFBOHelper::CCFBOHelper(){
}
CCFBOHelper::~CCFBOHelper(){
}
bool CCFBOHelper::createFBO(int width,int height) {
textureWidth = width;
textureHeight = height;
for(int i = 0 ; i < 2 ; i++){
//创建一个 2D 纹理用于连接 FBO 的颜色附着
glGenTextures(1, &m_FboTextureId[i]);
glBindTexture(GL_TEXTURE_2D, m_FboTextureId[i]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
// 创建 FBO
glGenFramebuffers(1, &m_FboId[i]);
// 绑定 FBO
glBindFramebuffer(GL_FRAMEBUFFER, m_FboId[i]);
// 绑定 FBO 纹理
glBindTexture(GL_TEXTURE_2D, m_FboTextureId[i]);
// 将纹理连接到 FBO 附着
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_FboTextureId[i], 0);
// 分配内存大小
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// 检查 FBO 的完整性状态
if (glCheckFramebufferStatus(GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE) {
LOGE("FBOSample::CreateFrameBufferObj glCheckFramebufferStatus status != GL_FRAMEBUFFER_COMPLETE");
return false;
}
// 解绑纹理
glBindTexture(GL_TEXTURE_2D, GL_NONE);
// 解绑 FBO
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
}
return true;
// LOGE("FBO创建");
}
void CCFBOHelper::bindFBO(int index){
// 绑定 FBO
glBindFramebuffer(GL_FRAMEBUFFER, m_FboId[index]);
}
void CCFBOHelper::unBindFBO(){
// 解绑 FBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
2.使用FBO
使用FBO我们只需要在渲染之前绑定FBO即可,如果要想渲染到屏幕上,只需要在渲染前解绑FBO即可,具体如下(这里只展示了部分代码,这里我离屏渲染了两次,第一次为渲染获取相机数据,第二次为渲染为抖音特效):
extern "C"
JNIEXPORT void JNICALL
Java_com_itfitness_openglcamera_render_GLRender_ndkResizeGL(JNIEnv *env, jobject thiz, jint width,
jint height) {
ccRender->resizeGL(width,height);
bool result = ccfboHelper.createFBO(width,height);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_itfitness_openglcamera_render_GLRender_ndkPaintGL(JNIEnv *env, jobject thiz,
jint texture_id) {
ccfboHelper.bindFBO(0);
ccRender->paintGL(texture_id);
ccfboHelper.unBindFBO();
ccfboHelper.bindFBO(1);
ccRenderDy->paintGL(ccfboHelper.m_FboTextureId[0]);
ccfboHelper.unBindFBO();
//最后我们将与 FBO绑定的纹理渲染到屏幕
ccRender2d->paintGL(ccfboHelper.m_FboTextureId[1]);
}
效果如下
3.获取FBO数据
我们也可以获取FBO中的数据,使用OpenCV进行处理,如下所示:
void* pixelBuffer = NULL;
extern "C"
JNIEXPORT void JNICALL
Java_com_itfitness_openglcamera_render_GLRender_ndkPaintGL(JNIEnv *env, jobject thiz,
jint texture_id) {
ccfboHelper.bindFBO(0);
ccRender->paintGL(texture_id);
if(pixelBuffer == NULL){
pixelBuffer = malloc(ccfboHelper.textureWidth * ccfboHelper.textureHeight * 4);
} else{
memset(pixelBuffer,0,ccfboHelper.textureWidth * ccfboHelper.textureHeight * 4);
}
glReadPixels(
0,
0,
ccfboHelper.textureWidth,
ccfboHelper.textureHeight,
GL_RGBA,
GL_UNSIGNED_BYTE,
pixelBuffer
);
cv::Mat imageSrc(ccfboHelper.textureHeight, ccfboHelper.textureWidth, CV_8UC4, pixelBuffer);
cv::flip(imageSrc, imageSrc, 0);
cv::cvtColor(imageSrc,imageSrc,cv::COLOR_RGBA2BGR);
//去色滤镜
cv::cvtColor(imageSrc,imageSrc,cv::COLOR_RGBA2GRAY);
cv::cvtColor(imageSrc,imageSrc,cv::COLOR_GRAY2RGBA);
cv::cvtColor(imageSrc,imageSrc,cv::COLOR_BGR2RGBA);
glActiveTexture(ccfboHelper.m_FboTextureId[0]);
glBindTexture(GL_TEXTURE_2D,ccfboHelper.m_FboTextureId[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSrc.cols, imageSrc.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageSrc.data);
ccfboHelper.unBindFBO();
ccRender2d->paintGL(ccfboHelper.m_FboTextureId[0]);
imageSrc.release();
}
案例源码
https://gitee.com/itfitness/opengl-fbo