相关主题:像素缓冲区对象(PBO)
下载: fbo.zip, fboDepth.zip, fboStencil.zip
glGenFramebuffers()
void glGenFramebuffers(GLsizei n, GLuint* ids) void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
glBindFramebuffer()
void glBindFramebuffer(GLenum target, GLuint id)
void glGenRenderbuffers(GLsizei n, GLuint* ids) void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
void glRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
void glGetRenderbufferParameteriv(GLenum target, GLenum param, GLint* value)
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
glFramebufferTexture2D(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint textureId, GLint level)
void glFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbufferId)
GLenum glCheckFramebufferStatus(GLenum target)
- 附加到帧缓冲区镜像的width和height必须是非零的。
- 如果一个镜像被附加到颜色附加点,那么这个镜像必须有一个可渲染颜色(color-renderable)的内部格式。(GL_RGBA,GL_DEPTH_COMPONENT,GL_LUMINANCE等)
- 如果一个镜像被附加到GL_DEPTH_ATTACHMENT,那么这个镜像必须有可渲染深度(depth-renderable)的内部格式。(GL_DEPTH_COMONENT,GL_DEPTH_COPONENT24等)
- 如果一个镜像被附加到GL_STENCIL_ATTACHMENT,那么这个镜像必须有可渲染模板(stencil-renderable)的内部格式。(GL_STENCIL_INDEX,GL_STENCIL_INDEX8等)
- FBO必须至少有一个附加的镜像。
- 所有附加到FBO的镜像必须有相同的宽体和高度。
- 所有附加到颜色附加点的镜像必须有相同的内部格式。
注意即使上面所有的条件都满足,你的OpenGL驱动(GPU)可能不支持某些内部的格式或参数。如果某个特殊的实现不被OpenGL驱动支持,那么glCheckFramebufferStatus()会返回GL_FRAMEBUFFER_UNSUPPORTED。
sample code提供了一些工具函数来显示当前FBO的信息:printFramebufferInfo()和checkFramebufferStatus()。
例子:渲染到纹理
下载源文件和可执行文件:fbo.zip(更新:2012-07-08)
附加:
-只渲染到深度缓冲区: fboDepth.zip
-使用模板缓冲区渲染物体的轮廓: fboStencil.zip
-使用glBlitFramebuffer()在两个FBO中传输:fboBlit.zip
有时,你需要生成动态的纹理。最普遍的例子是生成镜像/反射的效果,动态的立方体/环境映射和阴影映射。动态的纹理可以使用渲染场景到纹理中来生成。一个传统的渲染到纹理的方法是按照正常的步骤绘制一个场景到帧缓冲区中,然后使用glCopyTexSubImage2D()将帧缓冲区中的镜像复制到纹理中。
使用FBO,我们可以直接将一个场景渲染到纹理中,因此我们完全不需要使用”窗口系统提供的“帧缓冲区。除此之外,我们还可以减少额外的数据复制(从帧缓冲区到纹理)。
这个例子程序使用用FBO和不用FBO两种方式执行了渲染到纹理的操作,并比较了它们的性能差异。除了性能方面的区别外,FBO还有另外一个优点,在传统的渲染到纹理的模式中如果纹理的分辨率比渲染窗口大,那么纹理中窗口区域之外的部分会被裁剪掉,然后使用FBO不会产生这种裁剪的问题。你可以创建一个比显示窗口大的可渲染的帧缓冲区镜像。
下面的代码在渲染操作开始之前设置了一个FBO和附加到帧缓冲区的镜像。注意不仅纹理镜像可以附加到FBO中,渲染缓冲区镜像(深度缓冲,模板缓冲)也可以被附加到FBO。我们不会实际使用深度缓冲,然而FBO需要它进行深度测试。如果我们不将深度缓冲附加到FBO中,那么渲染输出的结果会被破坏因为缺少了深度测试。如果在FBO渲染时需要模板测试,那么额外的模板缓冲需要附加到GL_STENCIL_ATTACHMENT附加点。
... // 创建一个纹理对象 GLuint textureId; 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_MIPMAP_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); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // 自动贴图 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); // 创建一个渲染缓冲区对象来存储深度信息 GLuint rboId; glGenRenderbuffers(1, &rboId); glBindRenderbuffer(GL_RENDERBUFFER, rboId); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, TEXTURE_WIDTH, TEXTURE_HEIGHT); glBindRenderbuffer(GL_RENDERBUFFER, 0); // 创建一个帧缓冲区对象 GLuint fboId; glGenFramebuffers(1, &fboId); glBindFramebuffer(GL_FRAMEBUFFER, fboId); // 将纹理对象附加到FBO的颜色附加点上 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) // 将渲染缓冲区对象附加到FBO的深度附加点上 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 // 检查FBO的状态 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) fboUsed = false; // 切换到窗口系统提供的帧缓冲区中 glBindFramebuffer(GL_FRAMEBUFFER, 0); ...
... // 设置FBO为渲染的目的地 glBindFramebuffer(GL_FRAMEBUFFER, fboId); // 清除缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 直接绘制一个场景到纹理中 draw(); // 解除FBO的绑定 glBindFramebuffer(GL_FRAMEBUFFER, 0); // 贴图生成 // 注意:如果GL_GENERATE_MIPMAP被设置成 GL_TRUE, 那么glCopyTexSubImage2D() //会自动生成贴图. 然而, 附加到FBO的纹理需要使用glGenerateMipmap()来生成贴图 glBindTexture(GL_TEXTURE_2D, textureId); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); ...
如果你需要快速地出来纹理,可以联合像素缓冲区对象(PBO)一起修改纹理。