关于 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
获取视频教程和源码
推荐: