zoukankan      html  css  js  c++  java
  • OpenGL学习笔记(6)第一个动画

    首先再说明几个回调函数
    1. glutMouseFunc用于捕获鼠标事件
    2. glutKeyboardFunc用于捕获键盘事件
    3. glutMotionFunc用于鼠标按下又移动鼠标的事件(MouseMove)
    4. glutIdleFunc事件,当循环队列处于空闲时则触发该事件
    5. glutTimerFunc单位时间内内触发事件

    第一个动画

    #include <GL/glut.h>
    #include <stdlib.h>
    
    static GLfloat spin = 0.0;
    
    void display(void)
    {
       glClear(GL_COLOR_BUFFER_BIT);
       glPushMatrix();
       glRotatef(spin, 0.0, 0.0, 1.0);
       glColor3f(1.0, 1.0, 1.0);
       glRectf(-25.0, -25.0, 25.0, 25.0);
       glPopMatrix();
    
       glutSwapBuffers();
    }
    
    void spinDisplay(void)
    {
       spin = spin + 2.0;
       if (spin > 360.0)
          spin = spin - 360.0;
       glutPostRedisplay();
    }
    
    void init(void) 
    {
       glClearColor (0.0, 0.0, 0.0, 0.0);
       glShadeModel (GL_FLAT);
    }
    
    void reshape(int w, int h)
    {
       glViewport (0, 0, (GLsizei) w, (GLsizei) h);
       glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
       glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0);
       glMatrixMode(GL_MODELVIEW);
       glLoadIdentity();
    }
    
    void mouse(int button, int state, int x, int y) 
    {
       switch (button) {
          case GLUT_LEFT_BUTTON:
             if (state == GLUT_DOWN)
                glutIdleFunc(spinDisplay);
             break;
          case GLUT_MIDDLE_BUTTON:
          case GLUT_RIGHT_BUTTON:
             if (state == GLUT_DOWN)
                glutIdleFunc(NULL);
             break;
          default:
             break;
       }
    }
       
    /* 
     *  Request double buffer display mode.
     *  Register mouse input callback functions
     */
    int main(int argc, char** argv)
    {
       glutInit(&argc, argv);
       glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
       glutInitWindowSize (250, 250); 
       glutInitWindowPosition (100, 100);
       glutCreateWindow (argv[0]);
       init ();
       glutDisplayFunc(display); 
       glutReshapeFunc(reshape); 
       glutMouseFunc(mouse);
       glutMainLoop();
       return 0;   /* ANSI C requires main to return int. */
    }

    效果如下,犹如是动画,所以看不出来
    image

    当鼠标左键按下时则开始不断执行spinDisplay方法,这动画将使得矩形不断的旋转
    下面我们来看相关代码

    static GLfloat spin = 0.0;
    
    void display(void)
    {
       glClear(GL_COLOR_BUFFER_BIT);
       glPushMatrix();
       glRotatef(spin, 0.0, 0.0, 1.0);
       glColor3f(1.0, 1.0, 1.0);
       glRectf(-25.0, -25.0, 25.0, 25.0);
       glPopMatrix();
    
       glutSwapBuffers();
    }
    
    void spinDisplay(void)
    {
       spin = spin + 2.0;
       if (spin > 360.0)
          spin = spin - 360.0;
       glutPostRedisplay();
    }

    矩阵堆栈

    每次都将spin加2,这样的话spin其实是矩形旋转度数的总和,但如何维护矩形初始化(未旋转前)的矩阵呢?

    即将为旋转前的当前矩阵压入(glPushMatrix)矩阵堆栈中,然后当旋转结束后又弹出(glPopMatrix)堆栈恢复,当spin增加时,又以原始矩阵来合并,这样就不会出现什么问题了.

    还有一种做法则是去掉矩阵堆栈的压入与弹出,使得spin每次都是等于2,但度数就可能会超过360,造成数字过大转换,如

    void display(void)
    {
       glClear(GL_COLOR_BUFFER_BIT);
       //glPushMatrix();
       glRotatef(spin, 0.0, 0.0, 1.0);
       glColor3f(1.0, 1.0, 1.0);
       glRectf(-25.0, -25.0, 25.0, 25.0);
       //glPopMatrix();
    
       glutSwapBuffers();
    }
    
    void spinDisplay(void)
    {
       spin = 2.0;
       if (spin > 360.0)
          spin = spin - 360.0;
       glutPostRedisplay();
    }

    glutPostRedisplay方法将调用display方法进行强制刷新

    使用glutTimerFunc

    glutTimerFunc回调事件只执行一次,如果想一直执行的话就需要在内部再次调该方法,下面用glutTimerFunc来替代glutIdleFunc实现同样的效果

    void spinDisplay(int value)
    {
       spin = spin + 2.0;
       if (spin > 360.0)
          spin = spin - 360.0;
       glutPostRedisplay();
       glutTimerFunc(10, spinDisplay, 1);
    }

    当然首先要外部先调用一次spinDisplay方法才可以

    双缓冲技术

    下面这段话是转载

    总体意思为两个区域一个显示,一个则负责画图,然后连续切换
    在计算机上的动画与实际的动画有些不同:实际的动画都是先画好了,播放的时候直接拿出来显示就行。计算机动画则是画一张,就拿出来一张,再画下一张,再拿出来。如果所需要绘制的图形很简单,那么这样也没什么问题。但一旦图形比较复杂,绘制需要的时间较长,问题就会变得突出。
    让我们把计算机想象成一个画图比较快的人,假如他直接在屏幕上画图,而图形比较复杂,则有可能在他只画了某幅图的一半的时候就被观众看到。而后面虽然他把画补全了,但观众的眼睛却又没有反应过来,还停留在原来那个残缺的画面上。也就是说,有时候观众看到完整的图象,有时却又只看到残缺的图象,这样就造成了屏幕的闪烁。
    如何解决这一问题呢?我们设想有两块画板,画图的人在旁边画,画好以后把他手里的画板与挂在屏幕上的画板相交换。这样以来,观众就不会看到残缺的画了。这一技术被应用到计算机图形中,称为双缓冲技术。即:在存储器(很有可能是显存)中开辟两块区域,一块作为发送到显示器的数据,一块作为绘画的区域,在适当的时候交换它们。由于交换两块内存区域实际上只需要交换两个指针,这一方法效率非常高,所以被广泛的采用。
    注意:虽然绝大多数平台都支持双缓冲技术,但这一技术并不是OpenGL标准中的内容。OpenGL为了保证更好的可移植性,允许在实现时不使用双缓冲技术。当然,我们常用的PC都是支持双缓冲技术的。
    要启动双缓冲功能,最简单的办法就是使用GLUT工具包。我们以前在main函数里面写:
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    其中GLUT_SINGLE表示单缓冲,如果改成GLUT_DOUBLE就是双缓冲了。
    当然还有需要更改的地方——每次绘制完成时,我们需要交换两个缓冲区,把绘制好的信息用于屏幕显示(否则无论怎么绘制,还是什么都看不到)。如果使用GLUT工具包,也可以很轻松的完成这一工作,只要在绘制完成时简单的调用glutSwapBuffers函数就可以了。

  • 相关阅读:
    Java学习笔记——动态代理
    Java学习随笔——RMI
    数据结构与算法——排序算法
    设计模式——装饰者模式
    Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法
    vs中debug的一个小技巧 -- debug时忽略某段代码
    SilverlightMVVM模式中的数据校验
    技能图谱
    MQ队列管理器损坏的处理方法
    informix数据库锁表处理方法
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1853671.html
Copyright © 2011-2022 走看看