天天看点

Android OpenGL ES 帧缓冲FBO

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

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

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

glGenTextures(,&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, , GL_RGBA, width, width, , GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,textureFrame,);
           

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

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

glGenRenderbuffers(,&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(, , , );
    //使能颜色状态的值来清屏
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glUseProgram(program);
    static const GLfloat _vertices[] = {-, ,//左上
                                        -, -,//左下
                                        , ,//右上
                                        , -//右下
    };
    //stride设置为0自动决定步长
    //设置定点缓存指针
    glVertexAttribPointer(ATTRIBUTE_VERTEX, , GL_FLOAT, GL_FALSE, , _vertices);
    glEnableVertexAttribArray(ATTRIBUTE_VERTEX);
    //注意位置颠倒
    static const GLfloat texCoords[] = {, , , , , , , };
    //设置纹理缓存指针,varying变量会被插值传入片元着色器
    glVertexAttribPointer(ATTRIBUTE_TEXCOORD, , GL_FLOAT, , , texCoords);
    glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);
    //绑定纹理
    picPreviewTexture->bindTexture(uniformSampler);
    glDrawArrays(GL_TRIANGLE_STRIP, , );
    //切换回屏幕缓冲并绘制fbo之前绑定的空纹理
    glBindFramebuffer(GL_FRAMEBUFFER,);
    glClearColor(, , , ); // 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, , );
           

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

源码地址