• GLUT Tutorials 19:glutPostRedisplay vs. Idle Func


    博客转自:http://www.lighthouse3d.com/tutorials/glut-tutorial/glutpostredisplay-vs-idle-func/.

    GLUT将会调用显示函数知道没有事件函数去处理,也就是说,只要没有事件函数处理,主程序尽可能调用显示函数。我们将建立一个很简单的交互程序,当我们按下键盘,触发键盘事件之后,显示函数将会被调用,屏幕将会被重新绘制。我们需要做的就是注册显示函数和空闲处理函数为同一函数。

    如果只有我们的OpenGL程序运行,或者仅仅是想要测试,这样设置是OK的。但是当OpenGL程序仅仅是我们想要运行的程序其中之一时,计算机资源此时将显得匮乏。导致这个问题的当然是GLUT程序,因为他一直持续调用显示函数,即使在没有任何需要更新的时候。Try checking the task manager tab for the processes and you can see that even if the render does not change from frame to frame, our GLUT app is eating CPU resources. GPU resources are also being used, of course.

    当我们需要CPU或者GPU去处理其他事情的时候,我们肯定想节约计算机资源,同时保证GLUT程序不受影响;为了达到此目的,我们必须让GLUT有选择的去调用显示函数。这正是函数 glutPostRedisplay 的用武之地。

    glutPostRedisplay marks the current window to be redisplayed, i.e. it causes the main loop to call the display func asap. Note that it is only the current window, not all windows. Since our last example has sub windows we must take some extra measures to guarantee that everything works OK.

    First we are going to change the display func for the main window so that it calls all render functions defined for the sub windows. Then we can just call glutPost Redisplay for the main window and everything will be rendered again.

    In the main function we had:

    int main(int argc, char **argv) {
    
        // init GLUT and create main window
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowPosition(100,100);
        glutInitWindowSize(800,800);
        mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial");
    
        // callbacks for main window
        glutDisplayFunc(renderScene);
        glutReshapeFunc(changeSize);
            glutIdleFunc(renderSceneAll);
            ...

    We are going to change the display func for the main window to renderSceneAll, the previous idle func, and we’re removing the callback registration for the idle func. So our new main is as shown below:

    int main(int argc, char **argv) {
    
        // init GLUT and create main window
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowPosition(100,100);
        glutInitWindowSize(800,800);
        mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial");
    
        // callbacks for main window
        glutDisplayFunc(renderSceneAll);
        glutReshapeFunc(changeSize);
    
        // Removing the idle function to save CPU and GPU
        //glutIdleFunc(renderSceneAll);
            

    Now lets see where we must put our calls to glutPostRedisplay. We only want to have our display func called when there will be a change in the rendered image. Since all the scene is static, the only time the rendering differs is when we move the camera.

    The camera is moved with the mouse and keyboard so we must add a call to glutPostRedisplay when these events are processed.

    Lets start with the mouse. The camera moves when the mouse moves. So we are going to modify our mouse move function from:

    void mouseMove(int x, int y) {
    
        // this will only be true when the left button is down
        if (xOrigin >= 0) {
    
            // update deltaAngle
            deltaAngle = (x - xOrigin) * 0.001f;
    
            // update camera's direction
            lx = sin(angle + deltaAngle);
            lz = -cos(angle + deltaAngle);
        }
    }

    to:

    void mouseMove(int x, int y) {
    
        // this will only be true when the left button is down
        if (xOrigin >= 0) {
    
            // update deltaAngle
            deltaAngle = (x - xOrigin) * 0.001f;
    
            // update camera's direction
            lx = sin(angle + deltaAngle);
            lz = -cos(angle + deltaAngle);
    
                    // setting the main window as active
                    //and marking it for redraw
            glutSetWindow(mainWindow);
            glutPostRedisplay();
        }
    }

    Now for the keyboard. The function that processes events when a key is pressed is pressKey. So we are going to modify pressKey from:

    void pressKey(int key, int xx, int yy) {
    
        switch (key) {
            case GLUT_KEY_UP : deltaMove = 0.5f; break;
            case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
        }
    }

    to:

    void pressKey(int key, int xx, int yy) {
    
        switch (key) {
            case GLUT_KEY_UP : deltaMove = 0.5f; break;
            case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
        }
    
            // setting the main window as active
            //and marking it for redraw
        glutSetWindow(mainWindow);
        glutPostRedisplay();
    
    }

    Unfortunately we disabled the keyboard callbacks for key repetition, hence the above code change is not enough. The pressKey function will only be called once regardless of the amount of time you keep the key pressed.

    Fortunately there is a way around this. When we press a key we did set a variable to a nonzero value. Latter we checked the variable to see if the camera position needed to be updated. This check took place in the renderSceneAll function, so we know that this test will take place whenever a user initially presses a key.

    Here is the renderSceneAll function from the previous example:

    // Global render func
    void renderSceneAll() {
    
        // check for keyboard movement
        if (deltaMove) {
            computePos(deltaMove);
        }
    
        renderScene();
        renderScenesw1();
        renderScenesw2();
        renderScenesw3();
    }

    The variable deltaMode will be non-zero when a key is initially pressed. Therefore we can call glutPostRedisplay inside the if statement as shown below.

    // Global render func
    void renderSceneAll() {
    
        // check for keyboard movement
        if (deltaMove) {
            computePos(deltaMove);
    
                    // set the main window as active and
                    // ask for a redraw
            glutSetWindow(mainWindow);
            glutPostRedisplay();
        }
    
        renderScene();
        renderScenesw1();
        renderScenesw2();
        renderScenesw3();
    }

    Doing this will cause our display function to be called repeatedly until deltaMove is set zero. This only occurs when the user releases the key, as coded in the releaseKey function:

    void releaseKey(int key, int x, int y) {
    
        switch (key) {
            case GLUT_KEY_UP :
            case GLUT_KEY_DOWN : deltaMove = 0;break;
        }
    }

    全部代码如下

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #ifdef __APPLE__
    #include <GLUT/glut.h>
    #else
    #include <GL/glut.h>
    #endif
    
    // angle of rotation for the camera direction
    float angle = 0.0f;
    
    // actual vector representing the camera's direction
    float lx=0.0f,lz=-1.0f, ly = 0.0f;
    
    // XZ position of the camera
    float x=0.0f, z=5.0f, y = 1.75f;
    
    // the key states. These variables will be zero
    //when no key is being presses
    float deltaAngle = 0.0f;
    float deltaMove = 0;
    int xOrigin = -1;
    
    // width and height of the window
    int h,w;
    
    // variables to compute frames per second
    int frame;
    long time, timebase;
    char s[50];
    
    // variables to hold window identifiers
    int mainWindow, subWindow1,subWindow2,subWindow3;
    //border between subwindows
    int border = 6;
    
    void setProjection(int w1, int h1)
    {
        float ratio;
        // Prevent a divide by zero, when window is too short
        // (you cant make a window of zero width).
        ratio = 1.0f * w1 / h1;
        // Reset the coordinate system before modifying
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    
        // Set the viewport to be the entire window
            glViewport(0, 0, w1, h1);
    
        // Set the clipping volume
        gluPerspective(45,ratio,0.1,1000);
        glMatrixMode(GL_MODELVIEW);
    }
    
    void changeSize(int w1,int h1) {
    
        if(h1 == 0)
            h1 = 1;
    
        // we're keeping these values cause we'll need them latter
        w = w1;
        h = h1;
    
        // set subwindow 1 as the active window
        glutSetWindow(subWindow1);
        // resize and reposition the sub window
        glutPositionWindow(border,border);
        glutReshapeWindow(w-2*border, h/2 - border*3/2);
        setProjection(w-2*border, h/2 - border*3/2);
    
        // set subwindow 2 as the active window
        glutSetWindow(subWindow2);
        // resize and reposition the sub window
        glutPositionWindow(border,(h+border)/2);
        glutReshapeWindow(w/2-border*3/2, h/2 - border*3/2);
        setProjection(w/2-border*3/2,h/2 - border*3/2);
    
        // set subwindow 3 as the active window
        glutSetWindow(subWindow3);
        // resize and reposition the sub window
        glutPositionWindow((w+border)/2,(h+border)/2);
        glutReshapeWindow(w/2-border*3/2,h/2 - border*3/2);
        setProjection(w/2-border*3/2,h/2 - border*3/2);
    }
    
    void drawSnowMan() {
    
        glColor3f(1.0f, 1.0f, 1.0f);
    
    // Draw Body
        glTranslatef(0.0f ,0.75f, 0.0f);
        glutSolidSphere(0.75f,20,20);
    
    // Draw Head
        glTranslatef(0.0f, 1.0f, 0.0f);
        glutSolidSphere(0.25f,20,20);
    
    // Draw Eyes
        glPushMatrix();
        glColor3f(0.0f,0.0f,0.0f);
        glTranslatef(0.05f, 0.10f, 0.18f);
        glutSolidSphere(0.05f,10,10);
        glTranslatef(-0.1f, 0.0f, 0.0f);
        glutSolidSphere(0.05f,10,10);
        glPopMatrix();
    
    // Draw Nose
        glColor3f(1.0f, 0.5f, 0.5f);
        glRotatef(0.0f,1.0f, 0.0f, 0.0f);
        glutSolidCone(0.08f,0.5f,10,2);
    
        glColor3f(1.0f, 1.0f, 1.0f);
    
    }
    
    void renderBitmapString(
            float x,
            float y,
            float z,
            void *font,
            char *string) {
    
        char *c;
        glRasterPos3f(x, y,z);
        for (c=string; *c != ''; c++) {
            glutBitmapCharacter(font, *c);
        }
    }
    
    void restorePerspectiveProjection() {
    
        glMatrixMode(GL_PROJECTION);
        // restore previous projection matrix
        glPopMatrix();
    
        // get back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }
    
    void setOrthographicProjection() {
    
        // switch to projection mode
        glMatrixMode(GL_PROJECTION);
    
        // save previous matrix which contains the
        //settings for the perspective projection
        glPushMatrix();
    
        // reset matrix
        glLoadIdentity();
    
        // set a 2D orthographic projection
        gluOrtho2D(0, w, h, 0);
    
        // switch back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }
    
    void computePos(float deltaMove) {
    
        x += deltaMove * lx * 0.1f;
        z += deltaMove * lz * 0.1f;
    }
    
    // Common Render Items for all subwindows
    void renderScene2() {
    
    // Draw ground
    
        glColor3f(0.9f, 0.9f, 0.9f);
        glBegin(GL_QUADS);
            glVertex3f(-100.0f, 0.0f, -100.0f);
            glVertex3f(-100.0f, 0.0f,  100.0f);
            glVertex3f( 100.0f, 0.0f,  100.0f);
            glVertex3f( 100.0f, 0.0f, -100.0f);
        glEnd();
    
    // Draw 36 SnowMen
        for(int i = -3; i < 3; i++)
            for(int j=-3; j < 3; j++)
            {
                glPushMatrix();
                glTranslatef(i*10.0f, 0.0f, j * 10.0f);
                drawSnowMan();
                glPopMatrix();
            }
    }
    
    // Display func for main window
    void renderScene() {
        glutSetWindow(mainWindow);
        glClear(GL_COLOR_BUFFER_BIT);
        glutSwapBuffers();
    }
    
    // Display func for sub window 1
    void renderScenesw1() {
    
        glutSetWindow(subWindow1);
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glLoadIdentity();
        gluLookAt(x, y, z,
              x + lx,y + ly,z + lz,
              0.0f,1.0f,0.0f);
    
        renderScene2();
    
        // display fps in the top window
         frame++;
    
        time=glutGet(GLUT_ELAPSED_TIME);
        if (time - timebase > 1000) {
            sprintf(s,"Lighthouse3D - FPS:%4.2f",
                frame*1000.0/(time-timebase));
            timebase = time;
            frame = 0;
        }
    
        setOrthographicProjection();
    
        glPushMatrix();
        glLoadIdentity();
        renderBitmapString(5,30,0,GLUT_BITMAP_HELVETICA_12,s);
        glPopMatrix();
    
        restorePerspectiveProjection();
    
        glutSwapBuffers();
    }
    
    // Display func for sub window 2
    void renderScenesw2() {
    
        glutSetWindow(subWindow2);
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glLoadIdentity();
        gluLookAt(x, y+15, z,
              x ,y - 1,z,
              lx,0,lz);
    
        // Draw red cone at the location of the main camera
        glPushMatrix();
        glColor3f(1.0,0.0,0.0);
        glTranslatef(x,y,z);
        glRotatef(180-(angle+deltaAngle)*180.0/3.14,0.0,1.0,0.0);
        glutSolidCone(0.2,0.8f,4,4);
        glPopMatrix();
    
        renderScene2();
    
        glutSwapBuffers();
    }
    
    // Display func for sub window 3
    void renderScenesw3() {
    
        glutSetWindow(subWindow3);
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glLoadIdentity();
        gluLookAt(x-lz*10 , y, z+lx*10,
              x ,y ,z ,
              0.0f,1.0f,0.0f);
    
        // Draw red cone at the location of the main camera
        glPushMatrix();
        glColor3f(1.0,0.0,0.0);
        glTranslatef(x,y,z);
        glRotatef(180-(angle+deltaAngle)*180.0/3.14,0.0,1.0,0.0);
        glutSolidCone(0.2,0.8f,4,4);
        glPopMatrix();
    
        renderScene2();
    
        glutSwapBuffers();
    }
    
    // Global render func
    void renderSceneAll() {
    
        // check for keyboard movement
        if (deltaMove) {
            computePos(deltaMove);
            glutSetWindow(mainWindow);
            glutPostRedisplay();
        }
    
        renderScene();
        renderScenesw1();
        renderScenesw2();
        renderScenesw3();
    }
    
    // -----------------------------------
    //             KEYBOARD
    // -----------------------------------
    
    void processNormalKeys(unsigned char key, int xx, int yy) {
    
        if (key == 27) {
            glutDestroyWindow(mainWindow);
            exit(0);
        }
    }
    
    void pressKey(int key, int xx, int yy) {
    
        switch (key) {
            case GLUT_KEY_UP : deltaMove = 0.5f; break;
            case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
        }
        glutSetWindow(mainWindow);
        glutPostRedisplay();
    
    }
    
    void releaseKey(int key, int x, int y) {
    
        switch (key) {
            case GLUT_KEY_UP :
            case GLUT_KEY_DOWN : deltaMove = 0;break;
        }
    }
    
    // -----------------------------------
    //             MOUSE
    // -----------------------------------
    
    void mouseMove(int x, int y) {
    
        // this will only be true when the left button is down
        if (xOrigin >= 0) {
    
            // update deltaAngle
            deltaAngle = (x - xOrigin) * 0.001f;
    
            // update camera's direction
            lx = sin(angle + deltaAngle);
            lz = -cos(angle + deltaAngle);
    
            glutSetWindow(mainWindow);
            glutPostRedisplay();
        }
    }
    
    void mouseButton(int button, int state, int x, int y) {
    
        // only start motion if the left button is pressed
        if (button == GLUT_LEFT_BUTTON) {
    
            // when the button is released
            if (state == GLUT_UP) {
                angle += deltaAngle;
                deltaAngle = 0.0f;
                xOrigin = -1;
            }
            else  {// state = GLUT_DOWN
                xOrigin = x;
    
            }
        }
    }
    
    // -----------------------------------
    //             MAIN and INIT
    // -----------------------------------
    
    void init() {
    
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
    
        // register callbacks
        glutIgnoreKeyRepeat(1);
        glutKeyboardFunc(processNormalKeys);
        glutSpecialFunc(pressKey);
        glutSpecialUpFunc(releaseKey);
        glutMouseFunc(mouseButton);
        glutMotionFunc(mouseMove);
    }
    
    int main(int argc, char **argv) {
    
        // init GLUT and create main window
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowPosition(100,100);
        glutInitWindowSize(800,800);
        mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial");
    
        // callbacks for main window
        glutDisplayFunc(renderSceneAll);
        glutReshapeFunc(changeSize);
    
        // Removing the idle function to save CPU and GPU
        //glutIdleFunc(renderSceneAll);
        init();
    
        // sub windows
        subWindow1 = glutCreateSubWindow(mainWindow, border,border,w-2*border, h/2 - border*3/2);
        glutDisplayFunc(renderScenesw1);
        init();
    
        subWindow2 = glutCreateSubWindow(mainWindow, border,(h+border)/2,w/2-border*3/2, h/2 - border*3/2);
        glutDisplayFunc(renderScenesw2);
        init();
    
        subWindow3 = glutCreateSubWindow(mainWindow, (w+border)/2,(h+border)/2,w/2-border*3/2,h/2 - border*3/2);
        glutDisplayFunc(renderScenesw3);
        init();
    
        // enter GLUT event processing cycle
        glutMainLoop();
        
        return 1;
    }

    显示效果如下

    操作时候帧率上升,不操作时候帧率下降解决计算机资源。

  • 相关阅读:
    Apache ActiveMQ消息中间件的基本使用
    struts2结合生成验证码
    Python中docstring文档的写法
    Nginx+uWSGI+Django原理
    Python垃圾回收机制详解
    Python数据库连接池实例——PooledDB
    构建高可用服务端
    Python使用multiprocessing实现一个最简单的分布式作业调度系统
    python3 分布式进程(跨机器)BaseManager(multiprocessing.managers)
    python BaseManager分布式学习
  • 原文地址:https://www.cnblogs.com/flyinggod/p/12943663.html
Copyright © 2020-2023  润新知