【问题标题】:OpenGL framebuffer: can clear it, but can't draw to itOpenGL帧缓冲区:可以清除它,但不能绘制到它
【发布时间】:2011-11-11 13:24:29
【问题描述】:

在 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; 

【问题讨论】:

  • 你在哪里创建fbTexID?你在哪里使用tex
  • fbTexID 和 tex 都只是前面定义的 GLuint。 (在我的实际代码中,它们是更大结构的成员;为了简单明了,我在帖子中替换了更简单的名称。谢谢。
  • 仅供未来的读者阅读,因为我只是偶然发现了它:多重采样和 FBO 也可能会产生问题。

标签: opengl framebuffer


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    但事实并非如此:

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

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

    【讨论】:

      【解决方案3】:

      这是我前段时间写的一个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();
          }
      }
      

      也许这个参考有帮助

      【讨论】:

        【解决方案4】:

        这是我写了while ago 的 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;
        }
        

        【讨论】:

          猜你喜欢
          • 2011-11-24
          • 1970-01-01
          • 1970-01-01
          • 2018-02-18
          • 1970-01-01
          • 2014-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多