简介:
OpenGL默认的帧缓存包括:颜色缓存、深度缓存、模板缓存、累积缓存。
OpenGL扩展帧缓存(即FBO)包括:颜色缓存、深度缓存、模板缓存。
用途:
1、渲染到纹理:将纹理图像关联到帧缓存,opengl执行渲染到纹理2、离线渲染:将renderbuffer关联到帧缓存,opengl执行离线渲染
下面这幅图显示了帧缓存对象、纹理对象和渲染缓存对象之间的联系。多多个纹理对象或者渲染缓存对象能够通过关联点关联到一个帧缓存对象上。
使用方法:
具体的创建使用过程参见
http://blog.csdn.net/xiajun07061225/article/details/7283929
http://www.cnblogs.com/lizhengjin/archive/2010/12/23/1914795.html
代码:
#include <iostream>
#include <gl/glew.h>
#include <gl/glut.h>
using namespace std;
GLuint textureId; // Storage For 6 face Textures
GLuint fboId;
GLuint rboId;
//camera
float cameraAngleX;
float cameraAngleY;
float cameraDistance = -6.0;
//mouse
bool mouseLeftDown;
bool mouseRightDown;
float LastXPos;
float LastYPos;
const int IMAGE_WIDTH = 256;
const int IMAGE_HEIGHT = 256;
bool checkFramebufferStatus()
{
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE:
std::cout << "Framebuffer complete." << std::endl;
return true;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
std::cout << "[ERROR] Framebuffer incomplete: Attachment is NOT complete." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
std::cout << "[ERROR] Framebuffer incomplete: No image is attached to FBO." << std::endl;
return false;
/*
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
std::cout << "[ERROR] Framebuffer incomplete: Attached images have different dimensions." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
std::cout << "[ERROR] Framebuffer incomplete: Color attached images have different internal formats." << std::endl;
return false;
*/
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
std::cout << "[ERROR] Framebuffer incomplete: Draw buffer." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
std::cout << "[ERROR] Framebuffer incomplete: Read buffer." << std::endl;
return false;
case GL_FRAMEBUFFER_UNSUPPORTED:
std::cout << "[ERROR] Framebuffer incomplete: Unsupported by FBO implementation." << std::endl;
return false;
default:
std::cout << "[ERROR] Framebuffer incomplete: Unknown error." << std::endl;
return false;
}
}
void initGL()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // 0 is near, 1 is far
glDepthFunc(GL_LEQUAL);
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, IMAGE_WIDTH, IMAGE_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// create a renderbuffer object to store depth info
// NOTE: A depth renderable image should be attached the FBO for depth test.
// If we don't attach a depth renderable image to the FBO, then
// the rendering output will be corrupted because of missing depth test.
// If you also need stencil test for your rendering, then you must
// attach additional image to the stencil attachement point, too.
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, IMAGE_WIDTH, IMAGE_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// attach a texture to FBO color attachement point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
// attach a renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId);
checkFramebufferStatus();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void draw()
{
glBindTexture(GL_TEXTURE_2D, textureId);
glColor4f(1, 1, 1, 1);
// Front Face
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();
// Back Face
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f,-1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glEnd();
// Top Face
glBegin(GL_QUADS);
glNormal3f( 0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glEnd();
// Bottom Face
glBegin(GL_QUADS);
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glEnd();
// Right face
glBegin(GL_QUADS);
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glEnd();
// Left Face
glBegin(GL_QUADS);
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
}
void display()
{
glLoadIdentity();
glTranslatef(0, 0, cameraDistance);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(-1.1, -1.875f, 0);
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
glutWireTeapot(0.7f);
glPopMatrix();
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind
// trigger mipmaps generation explicitly
// NOTE: If GL_GENERATE_MIPMAP is set to GL_TRUE, then glCopyTexSubImage2D()
// triggers mipmap generation automatically. However, the texture attached
// onto a FBO should generate mipmaps manually via glGenerateMipmap().
glBindTexture(GL_TEXTURE_2D, textureId);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glLoadIdentity();
glTranslatef(0, 0, cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0); // pitch
glRotatef(cameraAngleY, 0, 1, 0); // heading
// clear framebuffer
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glPushMatrix();
// draw a cube with the dynamic texture
draw();
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat)w/(GLfloat)h, 0.01f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouseLeftDown = true;
LastXPos = x;
LastYPos = y;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
{
mouseRightDown = true;
}
}
void mouseMotion(int x, int y)
{
if (mouseLeftDown)
{
cameraAngleX += GLfloat(y - LastYPos)/GLfloat(20.0);
cameraAngleY += GLfloat(x - LastXPos)/GLfloat(20.0);
LastYPos = y;
LastXPos = x;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(480, 640);
glutInitWindowPosition(100, 100);
glutCreateWindow("FBO");
glewInit();
if(!glewIsSupported("GL_VERSION_2_0"))
{
fprintf(stderr, "ERROR: Support for necessary OpengGL extensions missing.");
}
initGL();
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutMainLoop();
glDeleteTextures(1, &textureId);
glDeleteFramebuffers(1, &fboId);
glDeleteRenderbuffers(1, &rboId);
return 0;
}
another sample
#include <iostream>
#include <gl/glew.h>
#include <gl/glut.h>
using namespace std;
GLuint textureId; // Storage For 6 face Textures
GLuint fboId;
GLuint rboId;
//camera
float cameraAngleX;
float cameraAngleY;
float cameraDistance = -6.0;
//mouse
bool mouseLeftDown;
bool mouseRightDown;
float LastXPos;
float LastYPos;
const int IMAGE_WIDTH = 256;
const int IMAGE_HEIGHT = 256;
bool checkFramebufferStatus()
{
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE:
std::cout << "Framebuffer complete." << std::endl;
return true;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
std::cout << "[ERROR] Framebuffer incomplete: Attachment is NOT complete." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
std::cout << "[ERROR] Framebuffer incomplete: No image is attached to FBO." << std::endl;
return false;
/*
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
std::cout << "[ERROR] Framebuffer incomplete: Attached images have different dimensions." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
std::cout << "[ERROR] Framebuffer incomplete: Color attached images have different internal formats." << std::endl;
return false;
*/
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
std::cout << "[ERROR] Framebuffer incomplete: Draw buffer." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
std::cout << "[ERROR] Framebuffer incomplete: Read buffer." << std::endl;
return false;
case GL_FRAMEBUFFER_UNSUPPORTED:
std::cout << "[ERROR] Framebuffer incomplete: Unsupported by FBO implementation." << std::endl;
return false;
default:
std::cout << "[ERROR] Framebuffer incomplete: Unknown error." << std::endl;
return false;
}
}
void createFBO()
{
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_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_RGBA8, IMAGE_WIDTH, IMAGE_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, IMAGE_WIDTH, IMAGE_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
//attach a texture to FBO color attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
//attach a renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId);
checkFramebufferStatus();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void deleteFBO()
{
if (textureId)
glDeleteTextures(1, &textureId);
if (fboId)
glDeleteFramebuffers(1, &fboId);
if (rboId)
glDeleteFramebuffers(1, &rboId);
}
void initGL()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // 0 is near, 1 is far
glDepthFunc(GL_LEQUAL);
createFBO();
}
void draw()
{
glBindTexture(GL_TEXTURE_2D, textureId);
glColor4f(1, 1, 0, 1);
glBegin(GL_QUADS);
{
glTexCoord2f( 0.0f, 0.0f);
glVertex2f(-1, -1);
glTexCoord2f( 1.0f, 0.0f);
glVertex2f( 1, -1);
glTexCoord2f( 1.0f, 1.0f);
glVertex2f( 1, 1);
glTexCoord2f( 0.0f, 1.0f);
glVertex2f(-1, 1);
}
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
}
void display()
{
glLoadIdentity();
glTranslatef(0, 0, cameraDistance);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(-1.1, -1.875f, 0);
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
//glutWireTeapot(0.7f);
glutSolidTeapot(0.7);
glPopMatrix();
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind
// trigger mipmaps generation explicitly
// NOTE: If GL_GENERATE_MIPMAP is set to GL_TRUE, then glCopyTexSubImage2D()
// triggers mipmap generation automatically. However, the texture attached
// onto a FBO should generate mipmaps manually via glGenerateMipmap().
glBindTexture(GL_TEXTURE_2D, textureId);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glLoadIdentity();
glTranslatef(0, 0, cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0); // pitch
glRotatef(cameraAngleY, 0, 1, 0); // heading
// clear framebuffer
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glPushMatrix();
// draw a cube with the dynamic texture
draw();
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat)w/(GLfloat)h, 0.01f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouseLeftDown = true;
LastXPos = x;
LastYPos = y;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
{
mouseRightDown = true;
}
}
void mouseMotion(int x, int y)
{
if (mouseLeftDown)
{
cameraAngleX += GLfloat(y - LastYPos)/GLfloat(20.0);
cameraAngleY += GLfloat(x - LastXPos)/GLfloat(20.0);
LastYPos = y;
LastXPos = x;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(480, 640);
glutInitWindowPosition(100, 100);
glutCreateWindow("FBO");
glewInit();
if(!glewIsSupported("GL_VERSION_2_0"))
{
fprintf(stderr, "ERROR: Support for necessary OpengGL extensions missing.");
}
initGL();
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutMainLoop();
deleteFBO();
return 0;
}