zoukankan      html  css  js  c++  java
  • GLUT Tutorials 15:帧率

    博客转自:http://www.lighthouse3d.com/tutorials/glut-tutorial/frames-per-second/

    How fast is your application really going? Sometimes we make small changes and we can’t be sure of the effect they had on the performance, namely how do they affect the number of displayed frames per second. In this section we’ll see how we can use GLUT to count the number of frames per second. Note that this shouldn’t be considered a true benchmark, just a guide value.

    GLUT provides a function that allows us to query many features of the system, one of them being the number of milliseconds from the call to glutInit. The function is glutGet and the syntax is as follows:

    int glutGet(GLenum state);
    
    Parameters:
    state – specifies the value we want.

     This function can be use for a lot of purposes, for instance getting window coordinates or getting the openGL buffer’s depth. In this section we’ll use it to get the number of milliseconds since the call to glutInit, i.e. the argument state is GLUT_ELAPSED_TIME.

    int time;
    
    //todo something 
    
    time = glutGet(GLUT_ELAPSED_TIME);

    Ok, now we’re going to use this function to compute the number of frames per second of our application. The frame rate varies from frame to frame, i.e. not all frames take the same time to render because our application is not alone. The operating system takes its toll, and the camera maybe moving thereby changing what’s being rendered. Therefore we’re going to avoid computing the frame rate in each and every frame, and instead we’re going to compute it roughly once per second. This also provides a more accurate figure, since its an average.

    We’re going to declare three variables: frame, time, and timebase, where timebase and frame are both initialized to zero.

    int frame=0,time,timebase=0;

    The meaning of these variables is:

    • frame – the number of frames since we last computed the frame rate
    • time – the current number of milliseconds
    • timebase – the time when we last computed the frame rate

    The following piece of code, when placed inside the registered idle function, will do the job (see bellow for a detailed description):

    ...
    
        frame++;
        time=glutGet(GLUT_ELAPSED_TIME);
    
        if (time - timebase > 1000) {
            fps = frame*1000.0/(time-timebase));
             timebase = time;
            frame = 0;
        }
        ...

    We start by increasing the number of frames, i.e. increasing the variable frame. We then get the current time into time. Next we compare it with timebase to check if a second has elapsed, i.e. if the difference between time and timebase is greater than 1000 millisecond. If this is not the case then we skip the computation part. However when the difference is larger than one second we’ll do the computation.

    Computing the difference between time and timebase gives us the number of milliseconds elapsed since we last computed the number of frames per second. Dividing 1000 by the number of milliseconds elapsed provides the inverse of the number of seconds elapsed. All its left is to multiply this value by the number of frames rendered since the last time the frame rate was computed, and we get the number of frames per second. Finally we reset timebase to the current number of milliseconds, and frame to zero.

    Note that when the application starts timebase is zero, you’ll have to wait one second to get the first value. This first few values however are very misleading because they include the time required to initialize the window. If you run some tests you’ll see that this value is much lower than the actual frame rate.

    If you want to print the number of frames per second you can use the following piece of code

    ...
        frame++;
        time=glutGet(GLUT_ELAPSED_TIME);
        if (time - timebase > 1000) {
            sprintf(s,"FPS:%4.2f",
                frame*1000.0/(time-timebase));
            timebase = time;
            frame = 0;
        }
    
        glColor3f(0.0f,1.0f,1.0f);
    
        glPushMatrix();
        glLoadIdentity();
        setOrthographicProjection();
        renderBitmapString(30,35,(void *)font,s);
        glPopMatrix();
        restorePerspectiveProjection();
    
        ...

    全部代码如下

    #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;
    
    // XZ position of the camera
    float x=0.0f, z=5.0f;
    
    // the key states. These variables will be zero
    //when no key is being presses
    float deltaAngle = 0.0f;
    float deltaMove = 0;
    int xOrigin = -1;
    
    // Constant definitions for Menus
    #define RED 1
    #define GREEN 2
    #define BLUE 3
    #define ORANGE 4
    
    #define FILL 1
    #define LINE 2
    
    // Pop up menu identifiers
    int fillMenu, fontMenu, mainMenu, colorMenu;
    
    // color for the nose
    float red = 1.0f, blue=0.5f, green=0.5f;
    
    // scale of snowman
    float scale = 1.0f;
    
    // menu status
    int menuFlag = 0;
    
    // default font
    void *font = GLUT_STROKE_ROMAN;
    
    // width and height of the window
    int h,w;
    
    // variables to compute frames per second
    int frame;
    long time, timebase;
    char s[50];
    
    void changeSize(int ww, int hh) {
    
        h = hh;
        w = ww;
        // Prevent a divide by zero, when window is too short
        // (you cant make a window of zero width).
        if (h == 0)
            h = 1;
    
        float ratio =  w * 1.0 / h;
    
        // Use the Projection Matrix
        glMatrixMode(GL_PROJECTION);
    
        // Reset Matrix
        glLoadIdentity();
    
        // Set the viewport to be the entire window
        glViewport(0, 0, w, h);
    
        // Set the correct perspective.
        gluPerspective(45.0f, ratio, 0.1f, 100.0f);
    
        // Get Back to the Modelview
        glMatrixMode(GL_MODELVIEW);
    }
    
    void drawSnowMan() {
    
        glScalef(scale, scale, scale);
        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(red, green, blue);
        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 renderStrokeFontString(
            float x,
            float y,
            float z,
            void *font,
            char *string) {  
    
        char *c;
        glPushMatrix();
        glTranslatef(x, y,z);
        glScalef(0.002f, 0.002f, 0.002f);
        for (c=string; *c != ''; c++) {
            glutStrokeCharacter(font, *c);
        }
        glPopMatrix();
    }
    
    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;
    }
    
    void renderScene(void) {
    
        if (deltaMove)
            computePos(deltaMove);
    
        // Clear Color and Depth Buffers
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // Reset transformations
        glLoadIdentity();
        // Set the camera
        gluLookAt(    x, 1.0f, z,
                x+lx, 1.0f,  z+lz,
                0.0f, 1.0f,  0.0f);
    
    // 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
        char number[3];
        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();
                sprintf(number,"%d",(i+3)*6+(j+3));
                renderStrokeFontString(0.0f, 0.5f, 0.0f, (void *)font ,number);
                glPopMatrix();
            }
    
        // Code to compute frames per second
        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;
        }
    
            // Code to display a string (fps) with bitmap fonts
        setOrthographicProjection();
    
        glPushMatrix();
        glLoadIdentity();
        renderBitmapString(5,30,0,GLUT_BITMAP_HELVETICA_18,s);
        glPopMatrix();
    
        restorePerspectiveProjection();
    
        glutSwapBuffers();
    }
    
    // -----------------------------------
    //             KEYBOARD
    // -----------------------------------
    
    void processNormalKeys(unsigned char key, int xx, int yy) {
    
        switch (key) {
            case 27:
                glutDestroyMenu(mainMenu);
                glutDestroyMenu(fillMenu);
                glutDestroyMenu(colorMenu);
                glutDestroyMenu(fontMenu);
                exit(0);
                break;
        }
    }
    
    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;
        }
    }
    
    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);
        }
    }
    
    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;
                xOrigin = -1;
            }
            else  {// state = GLUT_DOWN
                xOrigin = x;
            }
        }
    }
    
    // -----------------------------------
    //             MENUS
    // -----------------------------------
    
    void processMenuStatus(int status, int x, int y) {
    
        if (status == GLUT_MENU_IN_USE)
            menuFlag = 1;
        else
            menuFlag = 0;
    }
    
    void processMainMenu(int option) {
    
        // nothing to do in here
        // all actions are for submenus
    }
    
    void processFillMenu(int option) {
    
        switch (option) {
    
            case FILL: glPolygonMode(GL_FRONT, GL_FILL); break;
            case LINE: glPolygonMode(GL_FRONT, GL_LINE); break;
        }
    }
    
    void processFontMenu(int option) {
    
        switch (option) {
            case 1: font = GLUT_STROKE_ROMAN;
                break;
            case 2: font = GLUT_STROKE_MONO_ROMAN;
                break;
        }
    }
    
    void processColorMenu(int option) {
    
        switch (option) {
            case RED :
                red = 1.0f;
                green = 0.0f;
                blue = 0.0f; break;
            case GREEN :
                red = 0.0f;
                green = 1.0f;
                blue = 0.0f; break;
            case BLUE :
                red = 0.0f;
                green = 0.0f;
                blue = 1.0f; break;
            case ORANGE :
                red = 1.0f;
                green = 0.5f;
                blue = 0.5f; break;
        }
    }
    
    void createPopupMenus() {
    
        fontMenu = glutCreateMenu(processFontMenu);
    
            glutAddMenuEntry("STROKE_ROMAN",1 );
            glutAddMenuEntry("STROKE_MONO_ROMAN",2 );
        fillMenu = glutCreateMenu(processFillMenu);
    
        glutAddMenuEntry("Fill",FILL);
        glutAddMenuEntry("Line",LINE);
    
        colorMenu = glutCreateMenu(processColorMenu);
        glutAddMenuEntry("Red",RED);
        glutAddMenuEntry("Blue",BLUE);
        glutAddMenuEntry("Green",GREEN);
        glutAddMenuEntry("Orange",ORANGE);
    
        mainMenu = glutCreateMenu(processMainMenu);
    
        glutAddSubMenu("Polygon Mode", fillMenu);
        glutAddSubMenu("Color", colorMenu);
        glutAddSubMenu("Font",fontMenu);
        // attach the menu to the right button
        glutAttachMenu(GLUT_RIGHT_BUTTON);
    
        // this will allow us to know if the menu is active
        glutMenuStatusFunc(processMenuStatus);
    }
    
    // -----------------------------------
    //             MAIN
    // -----------------------------------
    
    int main(int argc, char **argv) {
    
        // init GLUT and create window
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowPosition(100,100);
        glutInitWindowSize(320,320);
        glutCreateWindow("Lighthouse3D - GLUT Tutorial");
    
        // register callbacks
        glutDisplayFunc(renderScene);
        glutReshapeFunc(changeSize);
        glutIdleFunc(renderScene);
    
        glutIgnoreKeyRepeat(1);
        glutKeyboardFunc(processNormalKeys);
        glutSpecialFunc(pressKey);
        glutSpecialUpFunc(releaseKey);
    
        // here are the two new functions
        glutMouseFunc(mouseButton);
        glutMotionFunc(mouseMove);
    
        // OpenGL init
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
    
        // init Menus
        createPopupMenus();
    
        // enter GLUT event processing cycle
        glutMainLoop();
        
        return 1;
    }

    显示效果如下

  • 相关阅读:
    Leetcode 449. Serialize and Deserialize BST
    机器学习入门(1)------python基础
    Leetcode 23. Merge k Sorted Lists
    mysql explain执行计划详解
    ubuntu下安装chrome浏览器证书
    ubantu下配置android开发环境(Ubuntu 12.04.4 LTS x64 dell 3420)
    system v信号量的深入剖析
    AI文件格式解析
    STC12LE5A60S2第二串口出现的奇葩问题
    ZIGBEE官方协议栈 SampleApp工程DemoEB项目 运行机制详解
  • 原文地址:https://www.cnblogs.com/flyinggod/p/12941708.html
Copyright © 2011-2022 走看看