// 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 #include class Renderer : protected QOpenGLFunctions{ public: float t; int mode; private: GLuint fboID; GLuint depthID; int fboTexSize; int width; int height; public: // constructor Renderer() : t(0.0), mode(1), fboID(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 // this is not used (but some drivers require it) GLuint texID; 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 depth render texture glGenTextures (1, &depthID); glBindTexture(GL_TEXTURE_2D, depthID); 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); glTexImage2D(GL_TEXTURE_2D, level, GL_DEPTH_COMPONENT, fboTexSize, fboTexSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Attach the texture to the fbo glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthID, level); 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 > 0) { // bind the fbo glBindFramebuffer(GL_FRAMEBUFFER, fboID); changeViewport(fboTexSize,fboTexSize); }else{ changeViewport(width, height); } glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // render to attached fbo drawScene(); if(mode == 1) { // unbind frame buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); changeViewportOrtho(width, height); // using first render pass result as texture glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, depthID); //draw quad with depth texture glColor3f(1.0f,0.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f,-1.0f, 0.0f); glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f, 0.0f); glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, 1.0f, 0.0f); glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f, 0.0f); glEnd(); glDisable(GL_TEXTURE_2D); } } void dispose() { if(fboID !=0) glDeleteFramebuffers(1, &fboID); if(depthID != 0) glDeleteTextures(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, 7.0, 12.0); } void changeViewportOrtho(int w, int h) { float aspect = (float)w/(float)h; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0*aspect, 1.0*aspect, -1.0, 1.0, -1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } 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,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(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 }