在OpenGL rendering pipeline中,原始数据和纹理经过处理过后最终会被渲染到屏幕上成为2D像素。
OpenGL pipeline的最终渲染目标就是framebuffer(帧缓存)
OpenGL 使用作为渲染目标的帧缓存是被window 系统生成管理的,这个默认的framebuffer被称为window-system-provided framebuffer.
作为OpenGL的扩展,GL_ARB_framebuffer_object提供了创建addtional nondisplayable framebuffer objects(FBO)。
这个framebuffer被称为application-created framebuffer,目的是用来和window-system-provided framebuffer区分开来。
通过FBO,一个OpenGL 应用可以将(redirect)渲染输出到application-created framebuffer object (FBO),而不是traditional window-system-provided framebuffer.
而且,它是完全被OpenGL控制的。
与window-system-provided framebuffer相似,一个FBO包含了一系列的渲染目标集合,color,depth,stencil buffer(accumulation buffer 没有定义在FBO)
这些FBO的逻辑缓存器被称为framebuffer-attachable images,这些都是可以被赋给一个framebuffer object 的2D像素数组
有两种framebuffer-attachable images,分别是texture images 以及 renderbuffer images
如果一个纹理图像被赋给一个framebuffer,OpenGL执行“render to texture”(纹理渲染);如果是一个渲染缓存对象(renderbuffer object)被赋值给一个framebuffer,那么OpenGL 执行“offscreen rendering”(离屏渲染)
本图展示了framebuffer 对象,texture对象,以及renderbuffer 对象的关系,多个纹理对象和渲染缓存对象都可以连接到一个帧缓存对象上通过attachment 指针。
一个帧缓存对象中有多个color attachment指针(GL_COLOR_ATTACHMENT0,…, GL_COLOR_ATTACHMENTn),一个depth attachment 指针,以及一个stencil attachment指针。
颜色指针实现时都是相互独立的,但是每个FBO都最少包含一个颜色指针。
一个FBO拥有多个颜色指针的原因是允许同时将颜色缓存渲染多个目标,这个“multiple render targets”(MRT)可以被GL_ARB_draw_buffers扩展实现。
#####*注意:framebuffer object 本身不拥有任何图像缓存(array),它拥有的只是多个附着指针。
FBO提供了一种有效的转换机制,将先前的framebuffer-attachable-image 从一个FBO上解绑,然后再附着一个新的framebuffer-attachable-image 。变换framebuffer-attachable-image比FBO之间的相互转换快的多。
FBO提供 glFramebufferTexture2D()去转换2D 纹理对象,并提供glFramebufferRenderbuffer() 去转换渲染缓存对象
生成FBO与生成VBO类似,先是glGenFramebuffers(),
void glGenFramebuffers(GLsizei n, GLuint* ids)
void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
glGenFramebuffers()中第一个参数是要生成的framebuffers数目,第二个参数是标志符。
返回的是还未使用的framebuffer 对象s的IDs,ID 0 是默认framebuffer ,即 window-system-provided framebuffer
当FBO不再使用时,利用 glDeleteFramebuffers()可以将其删除
一旦一个FBO生成后,在使用之前必须先进行绑定
void glBindFramebuffer(GLenum target, GLuint id)
第一个参数,target必须是GL_FRAMEBUFFER,第二个参数是标志符
当不想使用当前FBO时可用默认 window-system-provided framebuffer 也就是在glBindFramebuffer()使用ID 0来解绑
renderbuffer object 是作为离屏渲染被引进的,它允许直接渲染一个场景到一个renderbuffer 对象上,用来替代渲染到一个纹理对象。
renderbuffer 简化了一个数据存储对象包含一个可渲染内部格式的单映像(containing a single image of a renderable internal format),
renderbuffer object 用来存储没有对应的纹理格式的OpenGL 逻辑缓存,如stencil 或depth buffer
void glGenRenderbuffers(GLsizei n, GLuint* ids)
void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
一旦一个renderbuffer 被创建,函数会返回一个非零正整数。ID 0被OpenGL 预先保留
void glBindRenderbuffer(GLenum target, GLuint id)
对于renderbuffer object 而言第一个参数应该是GL_RENDERBUFFER
void glRenderbufferStorage(GLenum target,
GLenum internalFormat,
GLsizei width,
GLsizei height)
当一个renderbuffer object 创建后,它并没有任何数据存储空间,所以我们必须先为它开创内存空间,这可以用glRenderbufferStorage()来实现。
第一个参数必须是GL_RENDERBUFFER,第二个参数应该是color-renderable (GL_RGB, GL_RGBA, etc.), depth-renderable (GL_DEPTH_COMPONENT), 或则 stencil-renderable formats (GL_STENCIL_INDEX)
其中width和height的粒度是像素,而且不能超过GL_MAX_RENDERBUFFER_SIZE,否则会报错
void glGetRenderbufferParameteriv(GLenum target,
GLenum param,
GLint* value)
获取相应的参数,第一个是GL_RENDERBUFFER,第二个是参数名,第三个是存储返回数据的指针
FBO本身没有任何的映象存储(buffer),我们必须连接framebuffer-attachable images (texture or renderbuffer objects)到该FBO。
它可快速变换framebuffer-attachable images ,比在FBOs中相互变换快的多,而且还节省了不必要的数据拷贝和内存消耗。
如:一个纹理可以被连接到多个FBO对象之上,而且它的映像存储可以被多个FBO分享。
Attaching a 2D texture image to FBO
glFramebufferTexture2D(GLenum target,
GLenum attachmentPoint,
GLenum textureTarget,
GLuint textureId,
GLint level)
glFramebufferTexture2D()将一个2D纹理映像连接到一个FBO对象上。
第一个参数必须是GL_FRAMEBUFFER,第二个参数是一个连接到纹理映像的attachment 指针。一个FBO有多个 color attachment points (GL_COLOR_ATTACHMENT0, …, GL_COLOR_ATTACHMENTn), GL_DEPTH_ATTACHMENT, 和 GL_STENCIL_ATTACHMENT.
第三个参数大多数情况下是GL_TEXTURE_2D,第四个参数是纹理对象的ID,最后一个参数是等待连接的纹理的mipmap等级。
如果textureId参数设为0,纹理映像会从该FBO上解除绑定。如果一个纹理对象在还与一个FBO对象连接期间被删除,那么该纹理映像会自动与当前绑定的FBO解除绑定。
但是如果它连接了多个FBO还被删除了,那么只会与当前使用的FBO解除联系,不会从其他未与当前上下文绑定的FBO解除联系
Attaching a Renderbuffer image to FBO
void glFramebufferRenderbuffer(GLenum target,
GLenum attachmentPoint,
GLenum renderbufferTarget,
GLuint renderbufferId)
第三个参数是GL_RENDERBUFFER,其余与上一个近乎相同
当你渲染一个FBO时,抗混叠性能不会自动生效,即使你已经在创建OpenGL rendering context时配置了相关属性(with the multisampling attribute (SAMPLEBUFFERS_ARB) for window-system-provided framebuffer.)
为了激活多样本抗混叠模式,需要准备和联系多样本映像到一个FBO的color 或/和 depth attachement points。
glRenderbufferStorageMultisample() 可用来生成一个Multi Sample Anti Aliasing 模式的renderbuffer image
void glRenderbufferStorageMultisample(GLenum target,
GLsizei samples,
GLenum internalFormat,
GLsizei width,
GLsizei height)
与glRenderbufferStorage()相比,新增了一个参数samples,这是多样本的数目。
如果是0的话,就不再是MSAA模式,会转而调用glRenderbufferStorage() 。
*注意:如果多个images被联系到一个FBO上,那么所有的images必须有相同数目的multisamples。
// create a 4x MSAA renderbuffer object for colorbuffer
int msaa = 4;
GLuint rboColorId;
glGenRenderbuffers(1, &rboColorId);
glBindRenderbuffer(GL_RENDERBUFFER, rboColorId);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_RGB8, width, height);
// create a 4x MSAA renderbuffer object for depthbuffer
GLuint rboDepthId;
glGenRenderbuffers(1, &rboDepthId);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepthId);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_DEPTH_COMPONENT, width, height);
// create a 4x MSAA framebuffer object
GLuint fboMsaaId;
glGenFramebuffers(1, &fboMsaaId);
glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId);
// attach colorbuffer image to FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_COLOR_ATTACHMENT0, // 2. color attachment point
GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER
rboColorId); // 4. rbo ID
// attach depthbuffer image to FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_DEPTH_ATTACHMENT, // 2. depth attachment point
GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER
rboDepthId); // 4. rbo ID
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
fboUsed = false;
当然,glRenderbufferStorageMultisample()只是让MSAA 渲染到FBO,但是你并不能直接从MSAA FBO上使用结果。
如果需要转换结果到一个纹理或者其他non-multisampled framebuffer,必须还要用glBlitFramebuffer()转换成single-sample image .
void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, // source rectangle
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, // destination rect
GLbitfield mask,
GLenum filter)
相应的例子如下,
// copy rendered image from MSAA (multi-sample) to normal (single-sample)
// NOTE: The multi samples at a pixel in read buffer will be converted
// to a single sample at the target pixel in draw buffer.
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMsaaId); // src FBO (multi-sample)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); // dst FBO (single-sample)
glBlitFramebuffer(0, 0, width, height, // src rect
0, 0, width, height, // dst rect
GL_COLOR_BUFFER_BIT, // buffer mask
GL_LINEAR); // scale filter
在使用FBO执行操作之前,需要先验证FBO的状态是否完成,这可以通过glCheckFramebufferStatus()实现。
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
fboUsed = false;
下面是一个使用了纹理和renderbuffer的例子,
// create a texture object
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a renderbuffer object to store depth info
GLuint rboId;
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
TEXTURE_WIDTH, TEXTURE_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// create a framebuffer object
GLuint fboId;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// attach the texture to FBO color attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_COLOR_ATTACHMENT0, // 2. attachment point
GL_TEXTURE_2D, // 3. tex target: GL_TEXTURE_2D
textureId, // 4. tex ID
0); // 5. mipmap level: 0(base)
// attach the renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_DEPTH_ATTACHMENT, // 2. attachment point
GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER
rboId); // 4. rbo ID
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
fboUsed = false;
// switch back to window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
...