OpenGL默认的帧缓存包括:颜色缓存、深度缓存、模板缓存、累积缓存。
OpenGL扩展帧缓存(即FBO)包括:颜色缓存、深度缓存、模板缓存。
下面这幅图显示了帧缓存对象、纹理对象和渲染缓存对象之间的联系。多多个纹理对象或者渲染缓存对象能够通过关联点关联到一个帧缓存对象上。
具体的创建使用过程参见
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; }