// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. #include #include #include #include #include #include #include #include #include class Renderer : protected QOpenGLFunctions { public: float t; int mode; private: GLuint fboID; GLuint texID; GLuint depthID; int fboTexSize; int width; int height; public: // constructor Renderer() : t(0.0), mode(1), fboID(0), texID(0), depthID(0), fboTexSize(512), width(0), height(0) {} public: void init() { initializeOpenGLFunctions(); glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH); // create a frame buffer object glGenFramebuffers(1, &fboID); // bind the frame buffer glBindFramebuffer(GL_FRAMEBUFFER, fboID); // Generate render texture glGenTextures (1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); int level = 0; glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, fboTexSize, fboTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Attach the texture to the fbo glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, level); if(!checkFramebufferStatus()) exit(1); // generate a renderbuffer for the depth buffer glGenRenderbuffers(1, &depthID); glBindRenderbuffer(GL_RENDERBUFFER, depthID); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fboTexSize, fboTexSize); // Attach the depth buffer to the fbo glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthID); if(!checkFramebufferStatus()) exit(1); // unbind texture glBindTexture(GL_TEXTURE_2D, 0); //unbind fbo glBindFramebuffer(GL_FRAMEBUFFER, 0); } void resize(int w, int h) { width = w; height = h; changeViewport(w, h); } void display() { if(mode == 1) { // bind the fbo glBindFramebuffer(GL_FRAMEBUFFER, fboID); changeViewport(fboTexSize,fboTexSize); } glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // render to attached fbo drawScene(); if(mode == 1) { // unbind frame buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); changeViewport(width, height); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // using first render pass result as texture glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texID); // second render pass drawScene(); glDisable(GL_TEXTURE_2D); } } void dispose() { if(texID !=0) glDeleteTextures( 1, &texID); if(fboID !=0) glDeleteFramebuffers(1, &fboID); if(depthID != 0) glDeleteRenderbuffers(1, &depthID); } private: void changeViewport(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30.0, (float)w/(float)h, 0.1, 50.0); } void drawScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // set camera gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); // draw scene glRotatef(t, 0.0f, 0.0f, 1.0f); drawTexturedCube(); } bool checkFramebufferStatus() { GLenum status; status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER); switch(status) { case GL_FRAMEBUFFER_COMPLETE: return true; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: printf("Framebuffer incomplete, incomplete attachment\n"); return false; case GL_FRAMEBUFFER_UNSUPPORTED: printf("Unsupported framebuffer format\n"); return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: printf("Framebuffer incomplete, missing attachment\n"); return false; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: printf("Framebuffer incomplete, missing draw buffer\n"); return false; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: printf("Framebuffer incomplete, missing read buffer\n"); return false; } return false; } void drawTexturedCube() { glColor3f(1.0f,0.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f, 1.0f); glEnd(); glColor3f(1.0f,1.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); glColor3f(0.0f,0.0f,1.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f,-1.0f); glEnd(); glColor3f(1.0f,1.0f,1.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f,-1.0f); glEnd(); glColor3f(0.0f,1.0f,1.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f, -1.0f,-1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, -1.0f,-1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, -1.0f, 1.0f); glEnd(); glColor3f(0.0f,1.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(1.00f,1.00f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f,-1.0f); glEnd(); } }; class MyWidget : public QOpenGLWidget { private: Renderer *renderer; QTimer *timer; public: MyWidget(QWidget *parent = NULL) : QOpenGLWidget(parent) { this->setWindowTitle("Press 1 to toggle between first/second render pass"); this->resize(320, 320); renderer = new Renderer(); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(30); } ~MyWidget() { renderer->dispose(); delete renderer; delete timer; } protected: void initializeGL() { renderer->init(); } void resizeGL(int w, int h){ renderer->resize(w, h); } void paintGL() { float offset = 1.0f; renderer->t += offset; renderer->display(); } void keyPressEvent(QKeyEvent* event){ bool redraw = false; QString modeStr = ""; switch(event->key()) { case '1': if(renderer->mode == 1) { renderer->mode = 0; modeStr = "first render pass result"; } else { renderer->mode = 1; modeStr = "second render pass result"; } redraw = true; break; } if(redraw) { this->setWindowTitle(modeStr); this->update(); } } }; int main (int argc, char* argv[]) { // create a QApplication object that handles initialization, // finalization, and the main event loop QApplication appl(argc, argv); MyWidget widget; // create a widget widget.show(); //show the widget and its children return appl.exec(); // execute the application }