OpenGL帧缓冲区:可以清除它,但不能绘制它

发布于 2024-12-03 00:14:37 字数 2079 浏览 1 评论 0原文

在 Mac 上,我有一个 OpenGL 设置,除了帧缓冲区外,它工作得很好 - 纹理工作等。所以我知道纹理已启用,我有一个有效的上下文,等等。所有工作都完美,直到我尝试创建一个帧缓冲区。

我使用 glGenFramebuffers、glBindFramebuffer 和 glFramebufferTexture2D 创建了一个帧缓冲区,并且 glCheckFramebufferStatus 返回 GL_FRAMEBUFFER_COMPLETE。如果我随后调用 glClear,然后调用 glGetTexImage,则返回的数据显示 glClear 按其应有的方式作用于绑定到帧缓冲区的纹理。我可以将 glClearColor 设置为我想要的任何内容,并且 glClear 正确设置纹理数据。

但好消息就到此为止了。无论我使用 VBO 还是 glBegin/glEnd,我都无法将任何内容绘制到帧缓冲区中。绑定到帧缓冲区的纹理中的纹理数据不会受到绘制调用的影响(尽管 glClear 结果仍然出现)。即使我在调用 glGetTexImage 之前调用 glFlush 和 glFinish 也是如此。另外,glGetError 对于我的任何调用都没有返回错误。

我在下面发布了一些示例代码,这些代码是我在程序中的相关点添加的,只是为了尝试解决这个问题,以防给任何人一个想法。 (这不包括 glClear 调用,但我从同一点的单独测试中知道它可以正常工作)。

    glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbTexID, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
if(status != GL_FRAMEBUFFER_COMPLETE)
    Debugger(); 

glEnable(GL_TEXTURE_2D); 
glCullFace(GL_NONE); 
glGenTextures(1,(GLuint*)&tex); 
glBindTexture(GL_TEXTURE_2D,tex); 
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,1024,1024,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); 
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1024, 1024, 0, -5000, 5000); 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
glViewport(0, 0, 1024, 1024); 
glColor4f(1,1,1,1); 
glBegin(GL_TRIANGLES);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(1, 0);
    glVertex2f(1024, 0);
    glTexCoord2f(0, 1);
    glVertex2f(0, 1024);
glEnd();
glFlush();
glFinish(); 
unsigned char *dd = new unsigned char[1024*1024*4]; 
glBindTexture(GL_TEXTURE_2D, fbTexID); //I've tried calling glBindFramebuffer(GL_FRAMEBUFFER,0) before this bind - makes no difference
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dd);
delete dd; 

On a Mac, I've got an OpenGL setup that is working just fine apart from framebuffers - texturing works, etc. So I know that texturing is enabled, I have a valid context, etc. All works flawlessly until I try to create a framebuffer.

I created a framebuffer with glGenFramebuffers, glBindFramebuffer, and glFramebufferTexture2D, and glCheckFramebufferStatus is returning GL_FRAMEBUFFER_COMPLETE. If I then call glClear, followed by a call to glGetTexImage, the returned data shows that the glClear acted on the texture bound to the framebuffer just as it should. I can set glClearColor to anything I want, and the glClear sets the texture data correctly.

But that's where the good news stops. I can't draw anything into the framebuffer, whether I use VBOs or glBegin/glEnd. The texture data from the texture bound to the framebuffer is untouched by the draw calls (though the glClear results still appear). This is all true even if I call glFlush and glFinish before the glGetTexImage call. Also, glGetError is returning no error as to any of my calls.

I've posted below some sample code that I added at a relevant point in the program just to try to work on this issue, in case that gives anyone an idea. (This doesn't include the glClear call, but I know from separate testing at the same point that that works OK).

    glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbTexID, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
if(status != GL_FRAMEBUFFER_COMPLETE)
    Debugger(); 

glEnable(GL_TEXTURE_2D); 
glCullFace(GL_NONE); 
glGenTextures(1,(GLuint*)&tex); 
glBindTexture(GL_TEXTURE_2D,tex); 
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,1024,1024,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); 
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1024, 1024, 0, -5000, 5000); 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
glViewport(0, 0, 1024, 1024); 
glColor4f(1,1,1,1); 
glBegin(GL_TRIANGLES);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(1, 0);
    glVertex2f(1024, 0);
    glTexCoord2f(0, 1);
    glVertex2f(0, 1024);
glEnd();
glFlush();
glFinish(); 
unsigned char *dd = new unsigned char[1024*1024*4]; 
glBindTexture(GL_TEXTURE_2D, fbTexID); //I've tried calling glBindFramebuffer(GL_FRAMEBUFFER,0) before this bind - makes no difference
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dd);
delete dd; 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沉睡月亮 2024-12-10 00:14:37

您的纹理不起作用,因为它已被绑定!
您不能将 FBO 上的绑定纹理作为渲染目标!
这是没有太多记录的事情,但是当你思考它时就有意义了
驱动程序开发人员也需要一些保护措施,以防万一您做了一些奇怪的事情,例如同时读取和写入同一纹理

Your texture did not work because it was bound!
You cannnot have a bound texture work on a FBO as a rendertarget!
This is something that isn't very documented, but makes sense when you think about it
The driver developers need some safeguards too, just in case you do something weird like reading and writing to the same texture at the same time

与风相奔跑 2024-12-10 00:14:37

好的,回答了我自己的问题。看来您生成的作为帧缓冲区绘制的表面的纹理必须在生成帧缓冲区之后生成。所以,这可行:

glGenFramebuffers...
glBindFramebuffer...
glGenTextures...
glBindTexture...
glTexParameterf etc.
glFramebufferTexture2D...

但这不行:

glGenTextures...
glBindTexture...
glGenFramebuffers
glBindFramebuffer...
glFramebufferTexture2D...

我在任何地方都没有看到这个问题,这似乎令人惊讶,但我的代码仅通过移动纹理的生成就从不工作变为工作。

OK, answered my own question. It seems that the texture you generate to be the surface that the frame buffer draws to must be generated after the frame buffer is generated. So, this works:

glGenFramebuffers...
glBindFramebuffer...
glGenTextures...
glBindTexture...
glTexParameterf etc.
glFramebufferTexture2D...

but this does not:

glGenTextures...
glBindTexture...
glGenFramebuffers
glBindFramebuffer...
glFramebufferTexture2D...

I don't see this addressed anywhere, and it seems surprising, but my code went from not working to working just by moving the generation of the texture.

那一片橙海, 2024-12-10 00:14:37

这是我前段时间写的 FBO 测试:

#include <GL/glew.h>
#include <GL/glut.h>

#include <cmath>
#include <iostream>

using namespace std;

namespace render
{
    int width, height;
    float aspect;

    void init();
    void reshape(int width, int height);
    void display();

    int const fbo_width = 512;
    int const fbo_height = 512;

    GLuint fb, color, depth;
};

void idle();

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );

    glutCreateWindow("FBO test");
    glutDisplayFunc(render::display);
    glutReshapeFunc(render::reshape);
    glutIdleFunc(idle);

    glewInit();

    render::init();
    glutMainLoop();

    return 0;
}

void idle()
{
    glutPostRedisplay();
}

void CHECK_FRAMEBUFFER_STATUS()
{                                                         
    GLenum status;
    status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); 
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE:
        break;

    case GL_FRAMEBUFFER_UNSUPPORTED:
    /* choose different formats */
        break;

    default:
        /* programming error; will fail on all hardware */
        throw "Framebuffer Error";
    }
}

namespace render
{
    float const light_dir[]={1,1,1,0};
    float const light_color[]={1,0.95,0.9,1};

    void init()
    {
        glGenFramebuffers(1, &fb);
        glGenTextures(1, &color);
        glGenRenderbuffers(1, &depth);

        glBindFramebuffer(GL_FRAMEBUFFER, fb);

        glBindTexture(GL_TEXTURE_2D, color);
        glTexImage2D(   GL_TEXTURE_2D, 
                0, 
                GL_RGBA, 
                fbo_width, fbo_height,
                0, 
                GL_RGBA, 
                GL_UNSIGNED_BYTE, 
                NULL);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);

        glBindRenderbuffer(GL_RENDERBUFFER, depth);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbo_width, fbo_height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);

        CHECK_FRAMEBUFFER_STATUS();
    }

    void reshape(int width, int height)
    {
        render::width=width;
        render::height=height;
        aspect=float(width)/float(height);
        glutPostRedisplay();
    }

    void prepare()
    {
        static float a=0, b=0, c=0;

        glBindTexture(GL_TEXTURE_2D, 0);
        glEnable(GL_TEXTURE_2D);
        glBindFramebuffer(GL_FRAMEBUFFER, fb);

        glViewport(0,0,fbo_width, fbo_height);

        glClearColor(1,1,1,0);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, 1, 1, 10);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);

        glLightfv(GL_LIGHT0, GL_POSITION, light_dir);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);

        glTranslatef(0,0,-5);

        glRotatef(a, 1, 0, 0);
        glRotatef(b, 0, 1, 0);
        glRotatef(c, 0, 0, 1);

        glutSolidTeapot(0.75);

        a=fmod(a+0.1, 360.);
        b=fmod(b+0.5, 360.);
        c=fmod(c+0.25, 360.);
    }

    void final()
    {
        static float a=0, b=0, c=0;

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        glViewport(0,0, width, height);

        glClearColor(1.,1.,1.,0.);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, aspect, 1, 10);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0,0,-5);

        glRotatef(b, 0, 1, 0);

        b=fmod(b+0.5, 360.);

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, color);

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glDisable(GL_LIGHTING);

        float cube[][5]=
        {
            {-1, -1, -1,  0,  0},
            { 1, -1, -1,  1,  0},
            { 1,  1, -1,  1,  1},
            {-1,  1, -1,  0,  1},

            {-1, -1,  1, -1,  0},
            { 1, -1,  1,  0,  0},
            { 1,  1,  1,  0,  1},
            {-1,  1,  1, -1,  1},
        };
        unsigned int faces[]=
        {
            0, 1, 2, 3,
            1, 5, 6, 2,
            5, 4, 7, 6,
            4, 0, 3, 7,
            3, 2, 6, 7,
            4, 5, 1, 0
        };

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glVertexPointer(3, GL_FLOAT, 5*sizeof(float), &cube[0][0]);
        glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), &cube[0][3]);

        glCullFace(GL_BACK);
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);

        glCullFace(GL_FRONT);
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    }

    void display()
    {
        prepare();
        final();

        glutSwapBuffers();
    }
}

也许这个参考有帮助

This is a FBO test I wrote some time ago:

#include <GL/glew.h>
#include <GL/glut.h>

#include <cmath>
#include <iostream>

using namespace std;

namespace render
{
    int width, height;
    float aspect;

    void init();
    void reshape(int width, int height);
    void display();

    int const fbo_width = 512;
    int const fbo_height = 512;

    GLuint fb, color, depth;
};

void idle();

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );

    glutCreateWindow("FBO test");
    glutDisplayFunc(render::display);
    glutReshapeFunc(render::reshape);
    glutIdleFunc(idle);

    glewInit();

    render::init();
    glutMainLoop();

    return 0;
}

void idle()
{
    glutPostRedisplay();
}

void CHECK_FRAMEBUFFER_STATUS()
{                                                         
    GLenum status;
    status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); 
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE:
        break;

    case GL_FRAMEBUFFER_UNSUPPORTED:
    /* choose different formats */
        break;

    default:
        /* programming error; will fail on all hardware */
        throw "Framebuffer Error";
    }
}

namespace render
{
    float const light_dir[]={1,1,1,0};
    float const light_color[]={1,0.95,0.9,1};

    void init()
    {
        glGenFramebuffers(1, &fb);
        glGenTextures(1, &color);
        glGenRenderbuffers(1, &depth);

        glBindFramebuffer(GL_FRAMEBUFFER, fb);

        glBindTexture(GL_TEXTURE_2D, color);
        glTexImage2D(   GL_TEXTURE_2D, 
                0, 
                GL_RGBA, 
                fbo_width, fbo_height,
                0, 
                GL_RGBA, 
                GL_UNSIGNED_BYTE, 
                NULL);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);

        glBindRenderbuffer(GL_RENDERBUFFER, depth);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbo_width, fbo_height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);

        CHECK_FRAMEBUFFER_STATUS();
    }

    void reshape(int width, int height)
    {
        render::width=width;
        render::height=height;
        aspect=float(width)/float(height);
        glutPostRedisplay();
    }

    void prepare()
    {
        static float a=0, b=0, c=0;

        glBindTexture(GL_TEXTURE_2D, 0);
        glEnable(GL_TEXTURE_2D);
        glBindFramebuffer(GL_FRAMEBUFFER, fb);

        glViewport(0,0,fbo_width, fbo_height);

        glClearColor(1,1,1,0);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, 1, 1, 10);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);

        glLightfv(GL_LIGHT0, GL_POSITION, light_dir);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);

        glTranslatef(0,0,-5);

        glRotatef(a, 1, 0, 0);
        glRotatef(b, 0, 1, 0);
        glRotatef(c, 0, 0, 1);

        glutSolidTeapot(0.75);

        a=fmod(a+0.1, 360.);
        b=fmod(b+0.5, 360.);
        c=fmod(c+0.25, 360.);
    }

    void final()
    {
        static float a=0, b=0, c=0;

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        glViewport(0,0, width, height);

        glClearColor(1.,1.,1.,0.);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, aspect, 1, 10);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0,0,-5);

        glRotatef(b, 0, 1, 0);

        b=fmod(b+0.5, 360.);

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, color);

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glDisable(GL_LIGHTING);

        float cube[][5]=
        {
            {-1, -1, -1,  0,  0},
            { 1, -1, -1,  1,  0},
            { 1,  1, -1,  1,  1},
            {-1,  1, -1,  0,  1},

            {-1, -1,  1, -1,  0},
            { 1, -1,  1,  0,  0},
            { 1,  1,  1,  0,  1},
            {-1,  1,  1, -1,  1},
        };
        unsigned int faces[]=
        {
            0, 1, 2, 3,
            1, 5, 6, 2,
            5, 4, 7, 6,
            4, 0, 3, 7,
            3, 2, 6, 7,
            4, 5, 1, 0
        };

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glVertexPointer(3, GL_FLOAT, 5*sizeof(float), &cube[0][0]);
        glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), &cube[0][3]);

        glCullFace(GL_BACK);
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);

        glCullFace(GL_FRONT);
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, faces);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    }

    void display()
    {
        prepare();
        final();

        glutSwapBuffers();
    }
}

Maybe this reference helps

ゞ记忆︶ㄣ 2024-12-10 00:14:37

这是我不久前编写的 FBO“基准”。 set_fbo_size() 有一个 Works For Me(TM) 的创建序列。

/////////////////////////////////////////////////////////////////////////////
// INCLUDES /////////////////////////////////////////////////////////////////

#include <GL/glew.h>
#include <GL/glut.h>

#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;


/////////////////////////////////////////////////////////////////////////////
// CLASSES //////////////////////////////////////////////////////////////////

// http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
class ExpAvg 
{
public:
    ExpAvg(float initial, unsigned int time_periods) : avg(initial), alpha(2.0f / ( time_periods + 1 )) {}
    void Update(float nextval) { avg = alpha*nextval + (1.0f-alpha)*avg; }
    float Get() { return avg; }
private:
    float avg;
    float alpha;
};

class gl2D
{
public:
    gl2D() {
        int viewport[4];
        glGetIntegerv(GL_VIEWPORT, viewport);
        glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
        gluOrtho2D(0, viewport[2], 0, viewport[3]);
        glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
    }
    ~gl2D() {
        glMatrixMode(GL_PROJECTION); glPopMatrix();
        glMatrixMode(GL_MODELVIEW); glPopMatrix();
    }
};


/////////////////////////////////////////////////////////////////////////////
// GLOBALS //////////////////////////////////////////////////////////////////

int screen_width = 1024;
int screen_height = 768;
int mouse_x, mouse_y;
bool mouse_left, mouse_right;
float camera_angle_x = 45;
float camera_angle_y = 45;
float camera_distance = 0;

int texture_width, texture_height;
GLuint tex, fbo, rbo;  // object IDs


/////////////////////////////////////////////////////////////////////////////
// UTILITIES ////////////////////////////////////////////////////////////////

bool get_fbo_status()
{
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE_EXT: 
        cout << "Framebuffer complete." << endl; return true;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
        cerr << "[ERROR] Attachment is NOT complete." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
        cerr << "[ERROR] No image is attached to FBO." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
        cerr << "[ERROR] Attached images have different dimensions." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
        cerr << "[ERROR] Color attached images have different internal formats." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
        cerr << "[ERROR] Draw buffer." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
        cerr << "[ERROR] Read buffer." << endl; return false;
    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
        cerr << "[ERROR] Unsupported by FBO implementation." << endl; return false;
    default:
        cerr << "[ERROR] Unknow error." << endl; return false;
    }
}

void gl_print(const char *str, int x, int y, void *font)
{
    glPushAttrib(GL_ENABLE_BIT);
    glDisable(GL_LIGHTING);     // need to disable lighting for proper text color
    glDisable(GL_TEXTURE_2D);
    glRasterPos2i(x, y);        // place text position
    while(*str) glutBitmapCharacter(font, *str++); 
    glPopAttrib();
}

void textured_cube()
{
    glBegin(GL_QUADS);
    glColor4f(1, 1, 1, 1);

    // face v0-v1-v2-v3
    glNormal3f(0,0,1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,1);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,1);

    // face v0-v3-v4-v5
    glNormal3f(1,0,0);
    glTexCoord2f(0, 1);  glVertex3f(1,1,1);
    glTexCoord2f(0, 0);  glVertex3f(1,-1,1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,-1);

    // face v0-v5-v6-v1
    glNormal3f(0,1,0);
    glTexCoord2f(1, 0);  glVertex3f(1,1,1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,-1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 0);  glVertex3f(-1,1,1);

    // face  v1-v6-v7-v2
    glNormal3f(-1,0,0);
    glTexCoord2f(1, 1);  glVertex3f(-1,1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(-1,-1,1);

    // face v7-v4-v3-v2
    glNormal3f(0,-1,0);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(1,-1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,-1,1);

    // face v4-v7-v6-v5
    glNormal3f(0,0,-1);
    glTexCoord2f(0, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 1);  glVertex3f(1,1,-1);
    glEnd();
}

bool set_fbo_size(int width, int height)
{
    int max_size;
    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
    if(width > max_size) return false;
    if(height > max_size) return false;

    texture_width = width; texture_height = height;

    // create FBO
    if(fbo) glDeleteFramebuffersEXT(1, &fbo);
    glGenFramebuffersEXT(1, &fbo);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);    

    // create and attach a new texture as the FBO's color buffer
    if(tex) glDeleteTextures(1, &tex);
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);

    // create and attach a new depth buffer to currently bound FBO
    if(rbo) glDeleteRenderbuffersEXT(1, &rbo);
    glGenRenderbuffersEXT(1, &rbo);
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo);

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
    if( !get_fbo_status() ) exit(1);
    return true;
}


/////////////////////////////////////////////////////////////////////////////
// GLUT CALLBACKS ///////////////////////////////////////////////////////////

void CB_Idle()
{
    glutPostRedisplay();
}

void CB_Reshape(int width, int height)
{
    screen_width = width;
    screen_height = height;
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, (float)(width)/height, 1.0f, 1000.0f); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void CB_Mouse(int button, int state, int x, int y)
{
    mouse_x = x; mouse_y = y;
    if(button == GLUT_LEFT_BUTTON)
        mouse_left = (state == GLUT_DOWN);
    else if(button == GLUT_RIGHT_BUTTON)
        mouse_right = (state == GLUT_DOWN);
}

void CB_Motion(int x, int y)
{
    if(mouse_left) {
        camera_angle_y += (x - mouse_x);
        camera_angle_x += (y - mouse_y);
        mouse_x = x; mouse_y = y;
    }
    if(mouse_right) {
        camera_distance += (y - mouse_y) * 0.2f;
        mouse_y = y;
    }
}

void CB_Keyboard(unsigned char key, int x, int y)
{
    static int drawMode = 0;
    static int tex_size = 0;
    bool ret = false;

    switch(key) {
    case 27: // ESCAPE
        exit(0);
        break;
    case ' ':
        while(!ret) {
            tex_size = (tex_size+1) % 7;
            switch(tex_size) {
                case 0: ret = set_fbo_size(128,128); break;
                case 1: ret = set_fbo_size(256,256); break;
                case 2: ret = set_fbo_size(512,512); break;
                case 3: ret = set_fbo_size(1024,1024); break;
                case 4: ret = set_fbo_size(2048,2048); break;
                case 5: ret = set_fbo_size(4096,4096); break;
                case 6: ret = set_fbo_size(8192,8192); break;
                default: ; break;
            }
        }
        break;
    default:
        break;
    }
    glutPostRedisplay();
}

void CB_Init() 
{
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        cerr << "Error: " << glewGetErrorString(err) << endl; 
        exit(1);
    }

    if(!GLEW_EXT_framebuffer_object) {
        cerr << "Requires EXT_framebuffer_object" << endl; 
        exit(1);
    }

    tex = fbo = rbo = 0;

    glShadeModel(GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);

    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
    glClearColor(0, 0, 0, 0);

    GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f};  // ambient light
    GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f};  // diffuse light
    GLfloat lightKs[] = {1, 1, 1, 1};           // specular light
    glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
    glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);
    float lightPos[4] = {0, 0, 20, 1};          // positional light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    glEnable(GL_LIGHT0);

    set_fbo_size(128, 128);
}

void CB_Exit()
{
    glDeleteTextures(1, &tex);
    glDeleteFramebuffersEXT(1, &fbo);
    glDeleteRenderbuffersEXT(1, &rbo);
}

void CB_Display()
{
    static ExpAvg ft_fbo(0, 19);
    static ExpAvg ft_overall(0, 19);

    int before = glutGet(GLUT_ELAPSED_TIME);  

    // compute rotation angle
    const float ANGLE_SPEED = 90;   // degree/s
    float angle = ANGLE_SPEED * (glutGet(GLUT_ELAPSED_TIME) / 1000.0f);

    // render using fbo /////////////////////////////////////////////
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // bind fbo

    // adjust viewport and projection matrix to texture dimension
    glViewport(0, 0, texture_width, texture_height);
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    gluPerspective(60.0f, (float)(texture_width)/texture_height, 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();

    // clear buffer
    glClearColor(1, 1, 1, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTranslatef(0,0,-3);
    glPushMatrix();
    glRotatef(angle*0.5f, 1, 0, 0);
    glRotatef(angle, 0, 1, 0);
    glRotatef(angle*0.7f, 0, 0, 1);

    // set up teapot colors
    float shininess = 15.0f;
    float diffuseColor[3] = {0.929524f, 0.796542f, 0.178823f};
    float specularColor[4] = {1.00000f, 0.980392f, 0.549020f, 1.0f};
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); // range 0 ~ 128
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glColor3fv(diffuseColor);

    glBindTexture(GL_TEXTURE_2D, 0);
    glFrontFace(GL_CW);
    glutSolidTeapot(1.0); 
    glFrontFace(GL_CCW); 
    glPopMatrix();

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
    glFinish();

    ft_fbo.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );

    // normal rendering ///////////////////////////////////

    // back to normal viewport and projection matrix
    glViewport(0, 0, screen_width, screen_height);
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    gluPerspective(60.0f, (float)(screen_width)/screen_height, 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();

    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTranslatef(0,0,-4);
    glPushMatrix();
    glTranslatef(0, 0, camera_distance);
    glRotatef(camera_angle_x, 1, 0, 0);
    glRotatef(camera_angle_y, 0, 1, 0);

    // draw a cube with the dynamic texture
    glBindTexture(GL_TEXTURE_2D, tex);
    textured_cube();     
    glPopMatrix();

    { 
        gl2D two_dee;   // set 2D mode
        glDisable(GL_DEPTH_TEST);
        stringstream ss;
        glColor3f(1,1,0);
        ss << fixed << setprecision(3);
        int pos = 1;

        ss.str(""); ss << "Texture size: " << texture_width << "x" << texture_height;
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "Overall frame time: " << ft_overall.Get() << " ms";
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "    FBO frame time: " << ft_fbo.Get() << " ms";
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "Press space to change texture size; mouse moves/zooms cube";
        gl_print(ss.str().c_str(), 10, 10, GLUT_BITMAP_8_BY_13);
        glEnable(GL_DEPTH_TEST);
    }

    glutSwapBuffers();
    ft_overall.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );
}


/////////////////////////////////////////////////////////////////////////////
// MAIN /////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(screen_width, screen_height);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("FBO Test");

    glutDisplayFunc(CB_Display);
    glutIdleFunc(CB_Idle);
    glutReshapeFunc(CB_Reshape);
    glutKeyboardFunc(CB_Keyboard);
    glutMouseFunc(CB_Mouse);
    glutMotionFunc(CB_Motion);
    atexit(CB_Exit);

    CB_Init();
    glutMainLoop();
    return 0;
}

Here's a FBO "benchmark" I wrote a while ago. set_fbo_size() has a creation sequence that Works For Me(TM).

/////////////////////////////////////////////////////////////////////////////
// INCLUDES /////////////////////////////////////////////////////////////////

#include <GL/glew.h>
#include <GL/glut.h>

#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;


/////////////////////////////////////////////////////////////////////////////
// CLASSES //////////////////////////////////////////////////////////////////

// http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
class ExpAvg 
{
public:
    ExpAvg(float initial, unsigned int time_periods) : avg(initial), alpha(2.0f / ( time_periods + 1 )) {}
    void Update(float nextval) { avg = alpha*nextval + (1.0f-alpha)*avg; }
    float Get() { return avg; }
private:
    float avg;
    float alpha;
};

class gl2D
{
public:
    gl2D() {
        int viewport[4];
        glGetIntegerv(GL_VIEWPORT, viewport);
        glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
        gluOrtho2D(0, viewport[2], 0, viewport[3]);
        glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
    }
    ~gl2D() {
        glMatrixMode(GL_PROJECTION); glPopMatrix();
        glMatrixMode(GL_MODELVIEW); glPopMatrix();
    }
};


/////////////////////////////////////////////////////////////////////////////
// GLOBALS //////////////////////////////////////////////////////////////////

int screen_width = 1024;
int screen_height = 768;
int mouse_x, mouse_y;
bool mouse_left, mouse_right;
float camera_angle_x = 45;
float camera_angle_y = 45;
float camera_distance = 0;

int texture_width, texture_height;
GLuint tex, fbo, rbo;  // object IDs


/////////////////////////////////////////////////////////////////////////////
// UTILITIES ////////////////////////////////////////////////////////////////

bool get_fbo_status()
{
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE_EXT: 
        cout << "Framebuffer complete." << endl; return true;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
        cerr << "[ERROR] Attachment is NOT complete." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
        cerr << "[ERROR] No image is attached to FBO." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
        cerr << "[ERROR] Attached images have different dimensions." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
        cerr << "[ERROR] Color attached images have different internal formats." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
        cerr << "[ERROR] Draw buffer." << endl; return false;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
        cerr << "[ERROR] Read buffer." << endl; return false;
    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
        cerr << "[ERROR] Unsupported by FBO implementation." << endl; return false;
    default:
        cerr << "[ERROR] Unknow error." << endl; return false;
    }
}

void gl_print(const char *str, int x, int y, void *font)
{
    glPushAttrib(GL_ENABLE_BIT);
    glDisable(GL_LIGHTING);     // need to disable lighting for proper text color
    glDisable(GL_TEXTURE_2D);
    glRasterPos2i(x, y);        // place text position
    while(*str) glutBitmapCharacter(font, *str++); 
    glPopAttrib();
}

void textured_cube()
{
    glBegin(GL_QUADS);
    glColor4f(1, 1, 1, 1);

    // face v0-v1-v2-v3
    glNormal3f(0,0,1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,1);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,1);

    // face v0-v3-v4-v5
    glNormal3f(1,0,0);
    glTexCoord2f(0, 1);  glVertex3f(1,1,1);
    glTexCoord2f(0, 0);  glVertex3f(1,-1,1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,-1);

    // face v0-v5-v6-v1
    glNormal3f(0,1,0);
    glTexCoord2f(1, 0);  glVertex3f(1,1,1);
    glTexCoord2f(1, 1);  glVertex3f(1,1,-1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 0);  glVertex3f(-1,1,1);

    // face  v1-v6-v7-v2
    glNormal3f(-1,0,0);
    glTexCoord2f(1, 1);  glVertex3f(-1,1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(-1,-1,1);

    // face v7-v4-v3-v2
    glNormal3f(0,-1,0);
    glTexCoord2f(0, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(1,-1,1);
    glTexCoord2f(0, 1);  glVertex3f(-1,-1,1);

    // face v4-v7-v6-v5
    glNormal3f(0,0,-1);
    glTexCoord2f(0, 0);  glVertex3f(1,-1,-1);
    glTexCoord2f(1, 0);  glVertex3f(-1,-1,-1);
    glTexCoord2f(1, 1);  glVertex3f(-1,1,-1);
    glTexCoord2f(0, 1);  glVertex3f(1,1,-1);
    glEnd();
}

bool set_fbo_size(int width, int height)
{
    int max_size;
    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
    if(width > max_size) return false;
    if(height > max_size) return false;

    texture_width = width; texture_height = height;

    // create FBO
    if(fbo) glDeleteFramebuffersEXT(1, &fbo);
    glGenFramebuffersEXT(1, &fbo);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);    

    // create and attach a new texture as the FBO's color buffer
    if(tex) glDeleteTextures(1, &tex);
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);

    // create and attach a new depth buffer to currently bound FBO
    if(rbo) glDeleteRenderbuffersEXT(1, &rbo);
    glGenRenderbuffersEXT(1, &rbo);
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo);

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
    if( !get_fbo_status() ) exit(1);
    return true;
}


/////////////////////////////////////////////////////////////////////////////
// GLUT CALLBACKS ///////////////////////////////////////////////////////////

void CB_Idle()
{
    glutPostRedisplay();
}

void CB_Reshape(int width, int height)
{
    screen_width = width;
    screen_height = height;
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, (float)(width)/height, 1.0f, 1000.0f); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void CB_Mouse(int button, int state, int x, int y)
{
    mouse_x = x; mouse_y = y;
    if(button == GLUT_LEFT_BUTTON)
        mouse_left = (state == GLUT_DOWN);
    else if(button == GLUT_RIGHT_BUTTON)
        mouse_right = (state == GLUT_DOWN);
}

void CB_Motion(int x, int y)
{
    if(mouse_left) {
        camera_angle_y += (x - mouse_x);
        camera_angle_x += (y - mouse_y);
        mouse_x = x; mouse_y = y;
    }
    if(mouse_right) {
        camera_distance += (y - mouse_y) * 0.2f;
        mouse_y = y;
    }
}

void CB_Keyboard(unsigned char key, int x, int y)
{
    static int drawMode = 0;
    static int tex_size = 0;
    bool ret = false;

    switch(key) {
    case 27: // ESCAPE
        exit(0);
        break;
    case ' ':
        while(!ret) {
            tex_size = (tex_size+1) % 7;
            switch(tex_size) {
                case 0: ret = set_fbo_size(128,128); break;
                case 1: ret = set_fbo_size(256,256); break;
                case 2: ret = set_fbo_size(512,512); break;
                case 3: ret = set_fbo_size(1024,1024); break;
                case 4: ret = set_fbo_size(2048,2048); break;
                case 5: ret = set_fbo_size(4096,4096); break;
                case 6: ret = set_fbo_size(8192,8192); break;
                default: ; break;
            }
        }
        break;
    default:
        break;
    }
    glutPostRedisplay();
}

void CB_Init() 
{
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        cerr << "Error: " << glewGetErrorString(err) << endl; 
        exit(1);
    }

    if(!GLEW_EXT_framebuffer_object) {
        cerr << "Requires EXT_framebuffer_object" << endl; 
        exit(1);
    }

    tex = fbo = rbo = 0;

    glShadeModel(GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);

    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
    glClearColor(0, 0, 0, 0);

    GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f};  // ambient light
    GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f};  // diffuse light
    GLfloat lightKs[] = {1, 1, 1, 1};           // specular light
    glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
    glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);
    float lightPos[4] = {0, 0, 20, 1};          // positional light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    glEnable(GL_LIGHT0);

    set_fbo_size(128, 128);
}

void CB_Exit()
{
    glDeleteTextures(1, &tex);
    glDeleteFramebuffersEXT(1, &fbo);
    glDeleteRenderbuffersEXT(1, &rbo);
}

void CB_Display()
{
    static ExpAvg ft_fbo(0, 19);
    static ExpAvg ft_overall(0, 19);

    int before = glutGet(GLUT_ELAPSED_TIME);  

    // compute rotation angle
    const float ANGLE_SPEED = 90;   // degree/s
    float angle = ANGLE_SPEED * (glutGet(GLUT_ELAPSED_TIME) / 1000.0f);

    // render using fbo /////////////////////////////////////////////
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // bind fbo

    // adjust viewport and projection matrix to texture dimension
    glViewport(0, 0, texture_width, texture_height);
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    gluPerspective(60.0f, (float)(texture_width)/texture_height, 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();

    // clear buffer
    glClearColor(1, 1, 1, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTranslatef(0,0,-3);
    glPushMatrix();
    glRotatef(angle*0.5f, 1, 0, 0);
    glRotatef(angle, 0, 1, 0);
    glRotatef(angle*0.7f, 0, 0, 1);

    // set up teapot colors
    float shininess = 15.0f;
    float diffuseColor[3] = {0.929524f, 0.796542f, 0.178823f};
    float specularColor[4] = {1.00000f, 0.980392f, 0.549020f, 1.0f};
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); // range 0 ~ 128
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glColor3fv(diffuseColor);

    glBindTexture(GL_TEXTURE_2D, 0);
    glFrontFace(GL_CW);
    glutSolidTeapot(1.0); 
    glFrontFace(GL_CCW); 
    glPopMatrix();

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind fbo
    glFinish();

    ft_fbo.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );

    // normal rendering ///////////////////////////////////

    // back to normal viewport and projection matrix
    glViewport(0, 0, screen_width, screen_height);
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    gluPerspective(60.0f, (float)(screen_width)/screen_height, 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();

    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glTranslatef(0,0,-4);
    glPushMatrix();
    glTranslatef(0, 0, camera_distance);
    glRotatef(camera_angle_x, 1, 0, 0);
    glRotatef(camera_angle_y, 0, 1, 0);

    // draw a cube with the dynamic texture
    glBindTexture(GL_TEXTURE_2D, tex);
    textured_cube();     
    glPopMatrix();

    { 
        gl2D two_dee;   // set 2D mode
        glDisable(GL_DEPTH_TEST);
        stringstream ss;
        glColor3f(1,1,0);
        ss << fixed << setprecision(3);
        int pos = 1;

        ss.str(""); ss << "Texture size: " << texture_width << "x" << texture_height;
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "Overall frame time: " << ft_overall.Get() << " ms";
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "    FBO frame time: " << ft_fbo.Get() << " ms";
        gl_print(ss.str().c_str(), 10, screen_height - (pos++ * 20), GLUT_BITMAP_8_BY_13);
        ss.str(""); ss << "Press space to change texture size; mouse moves/zooms cube";
        gl_print(ss.str().c_str(), 10, 10, GLUT_BITMAP_8_BY_13);
        glEnable(GL_DEPTH_TEST);
    }

    glutSwapBuffers();
    ft_overall.Update( (float)(glutGet(GLUT_ELAPSED_TIME) - before) );
}


/////////////////////////////////////////////////////////////////////////////
// MAIN /////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(screen_width, screen_height);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("FBO Test");

    glutDisplayFunc(CB_Display);
    glutIdleFunc(CB_Idle);
    glutReshapeFunc(CB_Reshape);
    glutKeyboardFunc(CB_Keyboard);
    glutMouseFunc(CB_Mouse);
    glutMotionFunc(CB_Motion);
    atexit(CB_Exit);

    CB_Init();
    glutMainLoop();
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文