Android OpenGL ES 帧缓冲FBO

时间:2022-06-14 05:55:29

平时我们都是渲染到的默认的屏幕缓冲,通过swapbuffer来渲染到屏幕上,相对的我们可以同样创建一个离屏的帧缓冲来渲染到纹理。

创建一个fbo
    glGenFramebuffers(1,&frame);
    glBindFramebuffer(GL_FRAMEBUFFER,frame);

fbo需要我们为他准备一个至少一个缓冲(颜色、深度或模板缓冲),我们通常使用的是纹理附件

 glGenTextures(1,&textureFrame);
    glBindTexture(GL_TEXTURE_2D,textureFrame);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,textureFrame,0);

这里我们选择的是颜色缓冲,通过生成一个只分配了控件的纹理对象,并没有填充数据。

我们同样可以为fbo添加渲染缓冲附件,这个缓冲是只写的,如果需要从缓冲中读取数据,还是需要使用纹理。我们这里使用渲染缓冲来作为fbo深度缓冲的附加。

    glGenRenderbuffers(1,&render);

    glBindRenderbuffer(GL_RENDERBUFFER,render);

    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, width);

   glBindFramebuffer(GL_FRAMEBUFFER,frame);
   glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,render);

以上的代码需要注意,需要和纹理附加的缓冲宽高一致。

使用fbo绘制到纹理

创建好了fbo之后的绘制流程就比较正常了

  1. 绑定fbo
  2. 正常绘制
  3. 解绑fbo
  4. 绘制fob绑定的纹理
    //绑定生成的fbo
     picPreviewTexture->bindFrameBuffer();


    glViewport(_backingLeft, _backingTop, _backingWidth, _backingHeight);

    //设置一个颜色状态
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    //使能颜色状态的值来清屏
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glUseProgram(program);
    static const GLfloat _vertices[] = {-1.0f, 1.0f,//左上
                                        -1.0f, -1.0f,//左下
                                        1.0f, 1.0f,//右上
                                        1.0f, -1.0f//右下
    };
    //stride设置为0自动决定步长
    //设置定点缓存指针
    glVertexAttribPointer(ATTRIBUTE_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
    glEnableVertexAttribArray(ATTRIBUTE_VERTEX);
    //注意位置颠倒
    static const GLfloat texCoords[] = {0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f};
    //设置纹理缓存指针,varying变量会被插值传入片元着色器
    glVertexAttribPointer(ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, 0, 0, texCoords);
    glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);
    //绑定纹理
    picPreviewTexture->bindTexture(uniformSampler);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    //切换回屏幕缓冲并绘制fbo之前绑定的空纹理
    glBindFramebuffer(GL_FRAMEBUFFER,0);
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
    glClear(GL_COLOR_BUFFER_BIT);
    picPreviewTexture->bindTextureFrame(uniformSampler);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

帧缓冲就说到这里了,主要的作用可以从纹理中获取对应的数据来进行后期处理,总的来说使用还是非常简单。

源码地址