OpenGL缓冲区对象之FBO
1. 概述
在OpenGL渲染管线中几何数据和纹理经过变换和一些测试处理,最终会被展示到屏幕上。OpenGL渲染管线的最终位置是在帧缓冲区中。帧缓冲区是一系列二维的像素存储数组,包括了颜色缓冲区、深度缓冲区、模板缓冲区以及累积缓冲区。默认情况下OpenGL使用的是窗口系统提供的帧缓冲区。
OpenGL的GL_ARB_framebuffer_object这个扩展提供了一种方式来创建额外的帧缓冲区对象(FBO)。使用帧缓冲区对象,OpenGL可以将原先绘制到窗口提供的帧缓冲区重定向到FBO之中。
和窗口提供的帧缓冲区类似,FBO提供了一系列的缓冲区,包括颜色缓冲区、深度缓冲区和模板缓冲区(需要注意的是FBO中并没有提供累积缓冲区)这些逻辑的缓冲区在FBO中被称为 framebuffer-attachable images说明它们是可以绑定到FBO的二维像素数组。
FBO中有两类绑定的对象:纹理图像(texture images)和渲染图像(renderbuffer images)。如果纹理对象绑定到FBO,那么OpenGL就会执行渲染到纹理(render to texture)
的操作,如果渲染对象绑定到FBO,那么OpenGL会执行离屏渲染(offscreen rendering)
FBO可以理解为包含了许多挂接点的一个对象,它自身并不存储图像相关的数据,他提供了一种可以快速切换外部纹理对象和渲染对象挂接点的方式,在FBO中必然包含一个深度缓冲区挂接点和一个模板缓冲区挂接点,同时还包含许多颜色缓冲区挂节点(具体多少个受OpenGL实现的影响,可以通过GL_MAX_COLOR_ATTACHMENTS使用glGet查询),FBO的这些挂接点用来挂接纹理对象和渲染对象,这两类对象中才真正存储了需要被显示的数据。FBO提供了一种快速有效的方法挂接或者解绑这些外部的对象,对于纹理对象使用 glFramebufferTexture2D
,对于渲染对象使用glFramebufferRenderbuffer
具体描述参考下图:
2. 使用方法
2.1 创建FBO
创建FBO的方式类似于创建VBO,使用glGenFramebuffers
void glGenFramebuffers( GLsizei n,GLuint *ids);
- 1
- 2
- 3
n:创建的帧缓冲区对象的数量
ids:保存创建帧缓冲区对象ID的数组或者变量
其中,ID为0有特殊的含义,表示窗口系统提供的帧缓冲区(默认)
FBO不在使用之后使用glDeleteFramebuffers删除该FBO
创建FBO之后,在使用之前需要绑定它,使用glBindFramebuffers
void glBindFramebuffer(GLenum target, GLuint id)
- 1
target:绑定的目标,该参数必须设置为 GL_FRAMEBUFFER
id:由glGenFramebuffers创建的id
2.2 渲染对象
渲染对象是用来绑定的缓冲区对象FBO上做离屏渲染的。它可以让场景直接渲染到这个对象中(而不是到窗口系统中显示),创建它的方法与创建FBO有点类似:
- void glGenRenderbuffers(GLsizei n, GLuint* ids) 创建
- void glDeleteRenderbuffers(GLsizei n, const Gluint* ids) 删除
- void glBindRenderbuffer(GLenum target, GLuint id) 绑定
绑定完成之后,需要为渲染对象开辟一块空间,使用下面函数完成:
void glRenderbufferStorage(GLenum target,GLenum internalformat,GLsizei width,GLsizei height);
- 1
- 2
- 3
- 4
target:指定目标,必须设置为GL_RENDERBUFFER
internalformat:设置图像格式(参考《OpenGL图像格式》)
width和height:设置渲染对象的长和宽(大小必须小于 GL_MAX_RENDERBUFFER_SIZE)
可以使用glGetRenderbufferparameteriv函数来获取当前绑定的渲染对象
void glGetRenderbufferParameteriv(GLenum target,GLenum param,GLint* value)
- 1
- 2
- 3
target:参数必须是GL_RENDERBUFFER
param:取值如下(根据查询的不同选择相应的值)
GL_RENDERBUFFER_WIDTH
GL_RENDERBUFFER_HEIGHT
GL_RENDERBUFFER_INTERNAL_FORMAT
GL_RENDERBUFFER_RED_SIZE
GL_RENDERBUFFER_GREEN_SIZE
GL_RENDERBUFFER_BLUE_SIZE
GL_RENDERBUFFER_ALPHA_SIZE
GL_RENDERBUFFER_DEPTH_SIZE
GL_RENDERBUFFER_STENCIL_SIZE
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2.3 挂接对象到FBO
FBO本身并不包含任何图像存储空间,它需要挂接纹理对象或者渲染对象到FBO,挂接图像对象到FBO使用下面的方式:
2.3.1 挂接2D纹理到FBO
glFramebufferTexture2D(GLenum target,GLenum attachmentPoint,GLenum textureTarget,GLuint textureId,GLint level)
- 1
- 2
- 3
- 4
- 5
target:挂接的目标,必须指定为 GL_FRAMEBUFFER
attachmentPoint:挂接点位,取值:GL_COLOR_ATTACHMENT0到GL_COLOR_ATTACHMENTn,GL_DEPTH_ATTACHMENT,GL_STENCIL_ATTACHMENT
对应着上图中颜色缓冲区点位和深度以及模板缓冲区点位
textureTarget:设置为二维纹理(GL_TEXTURE_2D)
textureId:纹理对象的ID值(如果设置为0,那么纹理对象从FBO点位上解绑)
level:mipmap的层级
2.3.2 挂接渲染对象到FBO
void glFramebufferRenderbuffer(GLenum target,GLenum attachmentPoint,GLenum renderbufferTarget,GLuint renderbufferId)
- 1
- 2
- 3
- 4
第一个和第二个参数与挂接到纹理一样,第三个参数必须设置为GL_RENDERBUFFER,第四个参数是渲染对象的ID值。(如果设置为0,那么该渲染对象从当前点位上解绑)
2.4 检查FBO状态
当挂接完成之后,我们在执行FBO下面的操作之前,必须检查一下FBO的状态,使用以下的函数:
GLenum glCheckFramebufferStatus(GLenum target)
- 1
target:取值必须是GL_FRAMEBUFFER,当返回GL_FRAMEBUFFER_COMPLETE时,表示所有状态都正常,否则返回错误信息。
3. 示例程序
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>int windowWidth = 0;
int windowHeight = 0;const int TexWidth = 512;
const int TexHeight = 512;bool leftMouseDown = false;
float mouseX, mouseY;
float cameraAngleX, cameraAngleY;
float xRot, yRot;GLuint textureID;
GLuint frameBufferID;
GLuint renderBufferID;void drawCube()
{glBindTexture(GL_TEXTURE_2D, textureID);glColor4f(1, 1, 1, 1);glBegin(GL_QUADS);//FrontglNormal3d(0, 0, 1);glVertex3d(-1,-1, 1); glTexCoord2d(0,0);glVertex3d(1, -1, 1); glTexCoord2d(1,0);glVertex3d(1, 1, 1); glTexCoord2d(1,1);glVertex3d(-1, 1, 1); glTexCoord2d(0,1);//BackglNormal3d(0, 0, -1);glVertex3d(1, -1 , -1); glTexCoord2d(0, 0);glVertex3d(-1, -1, -1); glTexCoord2d(1, 0);glVertex3d(-1, 1, -1); glTexCoord2d(1, 1);glVertex3d(1, 1, -1); glTexCoord2d(0, 1);//LeftglNormal3d(-1, 0, 0);glVertex3d(-1, -1, -1); glTexCoord2d(0, 0);glVertex3d(-1, -1, 1); glTexCoord2d(1, 0);glVertex3d(-1, 1, 1); glTexCoord2d(1, 1);glVertex3d(-1, 1, -1); glTexCoord2d(0, 1);//RightglNormal3d(1, 0, 0);glVertex3d(1, -1, 1); glTexCoord2d(0, 0);glVertex3d(1, -1, -1); glTexCoord2d(1, 0);glVertex3d(1, 1, -1); glTexCoord2d(1, 1);glVertex3d(1, 1, 1); glTexCoord2d(0, 1);//TopglNormal3d(0, 1, 0);glVertex3d(-1, 1, 1); glTexCoord2d(0, 0);glVertex3d(1, 1, 1); glTexCoord2d(1, 0);glVertex3d(1, 1, -1); glTexCoord2d(1, 1);glVertex3d(-1, 1, -1); glTexCoord2d(0, 1);//BottomglNormal3d(0, -1, 0);glVertex3d(1, -1, 1); glTexCoord2d(0, 0);glVertex3d(-1, -1, 1); glTexCoord2d(1, 0);glVertex3d(-1, -1, -1); glTexCoord2d(1, 1);glVertex3d(1, -1, -1); glTexCoord2d(0, 1);glEnd();glBindTexture(GL_TEXTURE_2D, 0);
}void ChangeSize(int w, int h)
{windowWidth = w;windowHeight = h;if (h == 0)h = 1;
}void SetupRC()
{glGenTextures(1, &textureID);glBindTexture(GL_TEXTURE_2D, textureID);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexWidth, TexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);glBindTexture(GL_TEXTURE_2D, 0);glGenRenderbuffers(1, &renderBufferID);glBindRenderbuffer(GL_RENDERBUFFER, renderBufferID);glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, TexWidth, TexHeight);glBindRenderbuffer(GL_RENDERBUFFER, 0);glGenFramebuffers(1, &frameBufferID);glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBufferID);glBindFramebuffer(GL_FRAMEBUFFER, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);if (status != GL_FRAMEBUFFER_COMPLETE){fprintf(stderr, "GLEW Error: %s\n", "FRAME BUFFER STATUS Error!");return;}glEnable(GL_DEPTH_TEST);glEnable(GL_TEXTURE_2D);
}void RenderScene(void)
{//设置渲染到纹理的视口和投影矩阵glViewport(0, 0, TexWidth, TexHeight);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(60.0f, (float)(TexWidth) / TexHeight, 1.0f, 100.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();//渲染到纹理glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);glClearColor(1, 1, 1, 1);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glColor3f(1, 0, 1);glPushMatrix();glTranslated(0, 0.0, -5);glRotated(xRot, 1, 0, 0);glRotated(yRot, 0, 1, 0);glutSolidTeapot(1.0);glPopMatrix();//切换到窗口系统的帧缓冲区glBindFramebuffer(GL_FRAMEBUFFER, 0);glBindTexture(GL_TEXTURE_2D, 0);glViewport(0, 0, windowWidth, windowHeight);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(60.0f, (float)(windowWidth) / windowHeight, 1.0f, 100.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glClearColor(0, 0, 0, 0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glTranslated(0, 0, -5);glRotated(cameraAngleY*0.5, 1, 0, 0);glRotated(cameraAngleX*0.5, 0, 1, 0);glColor3d(1.0, 1.0, 1.0);drawCube();glutSwapBuffers();
}void MouseFuncCB(int button, int state, int x, int y)
{mouseX = x;mouseY = y;if (button == GLUT_LEFT_BUTTON){if (state == GLUT_DOWN){leftMouseDown = true;}else if (state == GLUT_UP){leftMouseDown = false;}}}void MouseMotionFuncCB(int x, int y)
{if (leftMouseDown){cameraAngleX += (x - mouseX);cameraAngleY += (y - mouseY);mouseX = x;mouseY = y;}glutPostRedisplay();
}void TimerFuncCB(int value)
{xRot += 2;yRot += 3;glutPostRedisplay();glutTimerFunc(33, TimerFuncCB, 1);
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);glutInitWindowSize(800, 600);glutCreateWindow("OpenGL");glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);glutMouseFunc(MouseFuncCB);glutMotionFunc(MouseMotionFuncCB);glutTimerFunc(33, TimerFuncCB, 1);GLenum err = glewInit();if (GLEW_OK != err) {fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));return 1;}SetupRC();glutMainLoop();return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
该程序演示了使用FBO作“渲染到纹理”的技术,将茶壶场景作为窗口场景的纹理,运行的效果图如下所示:
OpenGL缓冲区对象之FBO相关推荐
- OpenGL缓冲区对象之EBO
简介 EBO(Element Buffer Object,也叫IBO:Index Buffer Object)索引缓冲区对象,这个缓冲区主要用来存储顶点的索引信息. 考虑这样一种情况,我们需要绘制一个 ...
- 【OpenGL ES】帧缓冲区对象FBO
1.FBO 使用OpenGL ES,一般要通过EGL来配置本地窗口系统,关于EGL的介绍可参照"[OpenGL ES]EGL简介"http://blog.csdn.net/ieea ...
- 【OpenGL】蓝宝书第八章——缓冲区对象:存储尽在掌握
前言 缓冲区对象概念允许应用程序方便地将数据从一个渲染管线移动到另一个渲染管线,以及从一个对象绑定到另一个对象,它可以在无需CPU介入情况下完成.帧缓冲区对象能真正让我们控制像素,而不受操作系统环境影 ...
- OpenGL ES之离屏渲染的帧缓冲区对象FBO的说明和使用
一.什么是 FBO ? FBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO). FBO 本身不能用于渲染,只有添加 ...
- OpenGL ES 3.0(六)缓冲区对象、PBO、FBO
缓冲区对象 创建: Gluint pixBuffObjs[1]; glGenBuffers(1, pixBuffObjs); 绑定: glBindBuffer(GL_PIXEL_PACK_BUFFER ...
- 帧缓冲区对象 FBO
帧缓冲区对象 FBO(Frame Buffer Object). 1.FBO(framebuffer object) (我习惯于把EGL创建的framebuffer称为framebuffer,也叫做w ...
- OpenGL深入探索——像素缓冲区对象 (PBO)
英文原文地址 wiki解释 概述 OpenGL ARB_pixel_buffer_object 扩展与ARB_vertex_buffer_object.很相似.为了缓冲区对象不仅能存储顶点数据,还能存 ...
- Android OpenGL ES 3.0 PBO像素缓冲区对象
1.什么是PBO OpenGL PBO(Pixel Buffer Object),被称为像素缓冲区对象,主要被用于异步像素传输操作.PBO 仅用于执行像素传输,不连接到纹理,且与 FBO (帧缓冲区对 ...
- OPenGL中的缓冲区对象
引自:http://blog.csdn.net/mzyang272/article/details/7655464 在许多OpenGL操作中,我们都向OpenGL发送一大块数据,例如向它传递需要处理的 ...
- GLSL着色器实现多重纹理与帧缓冲对象(FBO)
还记得我前面几篇博客上写的东西都是将纹理直接渲染到屏幕上,就是产生一个和纹理尺寸大小相同的窗口进行渲染,那么渲染完了就正好完整的显示了纹理图案.但是在做数值计算的时候,一般是不需要输出到屏幕上的,这就 ...
最新文章
- C++11中auto的使用
- R语言编程艺术(1)快速入门
- Linux别名的创建删除【alias】和【unalias】
- golang中的aliyunoss
- 前端python和go_Python_前端网页+前后端交互-Go语言中文社区
- Python3 数字类型转换
- Java的超类/基类Object
- 打印机计算机故障或繁忙,为什么打印机可以通过电脑打印可不能扫描呢
- 想要轻松入门数据分析,这些知识不得不看!
- 【转】用photoshop批量修改图片尺寸
- 12.python之pymsql模块
- db9针232接口波特率标准_RS-232串口使用的DB9螺钉,螺纹规格是什么?
- 实现收藏本站和设为首页功能
- 英国留学经验分享:发下呆会被拒 有特长受欢迎
- 「Do.024」如何更高效使用MacBook
- Android App屏幕旋转要点
- 石墨笔记,幕布和Effie哪个更适合记者?
- mybatis面试题集锦
- 网络安全——文件上传
- jenkins shell 权限_Jenkins在shell脚本运行docker权限报错解决
热门文章
- JSHOP2详细使用教程 -- 原创
- npm启动报错Eorror:ENOENT no such file or directory ‘/node-sass/vender‘
- AXUI百度地图坐标拾取系统超强升级,功能更多更实用!
- poi批量导入导出Excel(一、需要建数据库表)
- 如何定义线程数线程数
- Java实现json报文的比对(不考虑内部顺序 + 可设置跳过部分字段比对)
- SV基础知识4----随机化和约束
- linux 卸载dnw命令,linux下面安装dnw
- IOS平台开发实战培训
- neural networks logistic regression 神经网络逻辑回归