平时我们都是渲染到的默认的屏幕缓冲,通过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之后的绘制流程就比较正常了
- 绑定fbo
- 正常绘制
- 解绑fbo
- 绘制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);
帧缓冲就说到这里了,主要的作用可以从纹理中获取对应的数据来进行后期处理,总的来说使用还是非常简单。