OpenGL系列之十八:FBO离屏渲染

计算机软件开发 2024-9-16 08:22:06 79 0 来自 中国
目次

干系文章

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_HCCFBOHelper.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);        glBindTexture(GL_TEXTURE_2D, m_FboTextureId);        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);        // 绑定 FBO        glBindFramebuffer(GL_FRAMEBUFFER, m_FboId);        // 绑定 FBO 纹理        glBindTexture(GL_TEXTURE_2D, m_FboTextureId);        // 将纹理毗连到 FBO 附着        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_FboTextureId, 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 JNICALLJava_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 JNICALLJava_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 JNICALLJava_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();} 3.gif 案例源码

https://gitee.com/itfitness/opengl-fbo
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-22 00:47, Processed in 0.161988 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表