关于 OpenGL FBO 的一些理解

字节流动

共 5947字,需浏览 12分钟

 ·

2021-09-17 07:48

FBO 是 FrameBuffer Object 的首字母简称。翻译过来就是帧缓冲区的意思。根据我的理解,OpenGL 作为图形 API,可以看做是画笔,帧缓冲区可以比作画布。我们使用OpenGL在帧缓冲区上“作画”(渲染)。


首先,我们需要建立 OpenGL Context,即获得一套“作画”的工具。以Win32 OpenGL 为例,我们需要如下流程去建立一个标准的 OpenGL Context:


  1、创建一个窗口类(WNDCLASS/WNDCLASSEX)。

  2、注册窗口类(RegisterClass)。

  3、调用CreateWindow/CreateWindowEx创建新窗口,返回窗口句柄 HWND。

  4、创建设备描述符PIXELFORMATDESCRIPTOR pfd。该结构体中包含即将要创建的OpenGL context的各种信息,包括是否支持双缓冲区、像素位数、Z-buffer位数等各种缓冲区位宽。

  5、获取新生成窗口的Device Context句柄HDC hDC,通过调用GetDC(HWND)获得。

  6、调用ChoosePixelFormat(hDC,&pfd)选择合适的像素格式,如果成功,返回像素格式的索引GLuint nPixelFormat。

  7、利用上一步的结果调用SetPixelFormat(hDC,nPixelFormat,&pfd),设置像素格式。

  8、调用wglCreateContext(hDC)获得 OpenGL Context 句柄 HGLRC hRC;

    9、设置上一步获得的OpenGL Context为当前的Context,通过调用wglMakeCurrent(hDC,hRC);


不总结不知道,一总结发现一步一步下来,步骤还是挺多的。要注意的一点是,上述9步中大部分函数调用是为了生成/申请相关窗口或者句柄,为了提高程序的鲁棒性,需要及时检查返回值的有效性。


注意:在上述第4步中,我们在设备描述符中通过参数设置了各个缓冲区的位宽。位宽为0当然就是没有这个缓冲区的意思啦。

在建立了OpenGL渲染环境之后,相当于获得了一只画笔,而此时我们有一块默认的画布,即我们的屏幕,default framebuffer。


我们渲染的目的地就是我们的屏幕,我们画出来的东西,会显示在屏幕上。这个default framebuffer 是与一系列缓冲区相关联的(具体有哪些缓冲区,多少位的缓冲区,是建立OpenGL Context的时候用户自定义的。一般来讲,必要的是颜色缓冲区,深度缓冲区。模板缓冲区、累加缓冲区这俩哥们儿可选)。


我们需要颜色缓冲区来存储我们渲染物体的颜色,需要深度缓冲区来进行深度测试,等等。具体的渲染过程是如何进行的,就是OpenGL Render Pipeline的东西了。在此不细表。


之后随着新需求的出现和 OpenGL 的发展,off-screen render 技术出现了,即离屏渲染。我去,off-screen render,离屏渲染,乍一听好牛逼的样子,其实很简单。我们把物体直接渲染到屏幕上,就是“在屏渲染”。


同理,我们把物体渲染到别的地方,不渲染到屏幕上,那不就是“离屏渲染”了么。那我们不渲染到屏幕,渲染到哪儿去呢?


OpenGL 从某版本之后,引入了Framebuffer Object。XXXX Object,我们见过很多了,像Vertex Buffer Object, Vertex Array Object。这次的 Framebuffer Object 是什么东西呢?


根据本人的理解,FBO(Framebuffer Object)就是 OpenGL 模拟 default framebuffer的功能和结构创建的一种可以作为“画布”使用的Object。


也就是说,你生成一个FBO,根据你的渲染需要,捯饬捯饬,然后把你想渲染的东西渲染到你刚生成的这个FBO里面,而不是直接渲染到屏幕上,就是这个样子。Default framebuffer 有很多支撑渲染行为的缓冲区,FBO也可以有,但是要你手动去生成、设置和绑定。


值得注意的是 FBO 的角色更像是一个管理者,管理着所有支撑渲染的RenderBuffers和Textures,OpenGL没有为FBO分配内存空间去存储渲染所需的几何、像素数据等。


但是,FBO有很多Attachment Point,顾名思义,我们把真正起作用的、具有实际内存空间占用的Renderbuffer和Texutures依附在FBO上,FBO起到管理的作用。这点跟VAO有点类似,是一批量“状态”的集合。VAO的事情我觉得有必要再整理下思路,但是此处暂且按下不表。


最近爱上了 Viso 作图,如下:

  

貌似不能插pdf,只能插图片。不清晰,此处有

pdf: http://files.cnblogs.com/chandler00x/FBO.pdf


下面简单说下两种情况的用法:

下面这段代码说明如何将 Renderbuffer 与 FBO 绑定


    GLuint hFbo,hTex,hDepth,hColor;

    glGenFramebuffers(1,&hFbo);
    glBindFramebuffer(GL_FRAMEBUFFER,hFbo);

    glGenRenderbuffers(1,&hDepth);
    glBindRenderbuffer(GL_RENDERBUFFER,hDepth);

    //为当前的Renderbuffer分配空间,格式为GL_DEPTH_COMPONENT,顾名思义
    //这个Renderbuffer肯定是与depth test相关的。
    glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,m_width,m_height);

    //将当前的Renderbuffer与Framebuffer Object的GL_DEPTH_ATTACHMENT的连接点
    //连接起来。再顾名思义,肯定是与Depth test相关的。
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,hDepth);

    glGenRenderbuffers(1,&hColor);
    glBindRenderbuffer(GL_RENDERBUFFER,hColor);

    //为当前的Renderbuffer分配空间,格式为GL_RGBA
    glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA,m_width,m_height);

    //与FBO的GL_COLOR_ATTACHMENT0连接起来。
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,hColor);

    //检查Framebuffer的完整性,十分必要!!!!!
    //十分必要!!!!!
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if( status != GL_FRAMEBUFFER_COMPLETE)
        printf("Framebuffer incomplete!\n");
    else
        printf("Framebuffer complete!\n");


下面这段代码说明如何将 Texture 与 FBO 绑定 


    GLuint hFbo,hTex,hDepth,hColor;

    glGenFramebuffers(1,&hFbo);
    glBindFramebuffer(GL_FRAMEBUFFER,hFbo);

    glGenRenderbuffers(1,&hDepth);
    glBindRenderbuffer(GL_RENDERBUFFER,hDepth);

    //为当前的Renderbuffer分配空间,格式为GL_DEPTH_COMPONENT,顾名思义
    //这个Renderbuffer肯定是与depth test相关的。
    glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,m_width,m_height);

    //将当前的Renderbuffer与Framebuffer Object的GL_DEPTH_ATTACHMENT的连接点
    //连接起来。再顾名思义,肯定是与Depth test相关的。
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,hDepth);

    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1,&hTex);
    glBindTexture(GL_TEXTURE_2D,hTex);

    //为纹理分配空间。
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,m_width,m_height,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);

    //与FBO的GL_COLOR_ATTACHMENT0绑定,Color。。color。。
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,hTex,0);


    //检查Framebuffer的完整性,十分必要!!!!!
    //十分必要!!!!!
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if( status != GL_FRAMEBUFFER_COMPLETE)
        printf("Framebuffer incomplete!\n");
    else
        printf("Framebuffer complete!\n");


来源:https://www.cnblogs.com/chandler00x/p/3886062.html


-- END --


进技术交流群,扫码添加我的微信:Byte-Flow



获取视频教程和源码



推荐:

Android FFmpeg 实现带滤镜的微信小视频录制功能

全网最全的 Android 音视频和 OpenGL ES 干货,都在这了

你还不知道 OpenGL ES 和 EGL 的关系?

OpenGL ES 3.0  FBO 离屏渲染

面试中经常被问到的 OpenGL ES 对象,你知道的有哪些?

浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报