OpenGL织梦之旅【第二章】第2节.实现动画

来源:互联网 发布:mysql数据库下载 编辑:程序博客网 时间:2024/06/07 01:57

       在上一节中,我们知道了怎么在OpenGL程序里,画一些基本的图形,并且画了一个钟表出来。然而,这个钟的时间是我们事先给它的,所以它只能显示一个固定的时间。所以,这一节我们将来学习怎么让画面动起来!

       我希望这个表能够获取系统时间,并且随着系统时间的改变,指针的读数也会改变。

       在实现动画这一块,OpenGL给我们提供了双缓冲。当A缓冲区显示时,B缓冲区正在绘制图形。当B绘制完毕时,就交换缓冲区,此时B显示,而A就进行绘画。从而实现平滑地显示每一帧地显示,观众就永远看不到没有完成的画面。计算机的在交换缓冲区的时候,速度很快,所以一般用户是觉察不到的。

       为了能让我们的程序能够使用双缓冲,我们需要改变main函数中glutInitDisplayMode()函数的参数,把GLUT_SINGLE改为GLUT_DOUBLE,表示我们现在要使用双缓冲(double)了,以前是单缓冲(single)

       glutInitDisplayMode(GLUT_RGB| GLUT_DOUBLE);

       在openGL中,并没有提供交换缓冲这个函数,因为有些硬件不支持这个特性。对于不同的操作系统,有不同的方法。我们使用的GLUT辅助库,帮我们解决了这个问题,我们只用调用glutSwapBuffers();函数就OK了。

       所以我们再把Draw函数中的glFlush()函数换成glutSwapBuffers()。就可以了。

       这个时候编译运行,会同样的出现钟表,画面并没有动起来,因为Draw函数只调用了一次,我们希望程序能不停地显示。怎么做呢?

       我们在main函数中使用glutIdleFunc(&Update)函数,可以设置一个回调函数Update。设置了以后,Update便会在循环中不断地被调用,直到有窗口消息产生。这里暂时不管窗口消息是啥,我们就知道Update会不断被调用就是了。

于是我们写一个Update函数.

void Update(){    glutPostRedisplay();}

       glutPostRedisplay函数,就和它的名字一样,它发送了一个消息给glut窗口,告诉它重新绘制一下画面,结果就是Draw函数会被调用。

这时我们再编译运行一次,发现同样可以显示画面。其实这个时候,画面是在不断地更新的,只是你感觉不出来而已。



       指针并没有动,因为指针的读数和hms三个参数有关,而这三个参数的值是固定的。把这三个参数改为全局变量,让其在其他函数中也可以被使用,然后在Update函数中,更新hms的值为当前系统的时间就可以了。最后记得去掉draw函数中的

h=10;m=25;s=25;


void Update(){    time_t rawtime;    struct tm * timeinfo;    time ( &rawtime );    timeinfo = localtime ( &rawtime );    h=timeinfo->tm_hour;    m=timeinfo->tm_min;    s=timeinfo->tm_sec;    glutPostRedisplay();}

       这个时候,在编译运行,效果就出来了!

附本节全部代码:


#include <GL/glut.h>#include <stdio.h>#include <math.h>#include <time.h>#define PI 3.1415926float h,m,s;void Draw(){    int i;    float R,TR,h_Angle,m_Angle,s_Angle,count,h_Length,m_Length,s_Length;    R=0.5;    TR=R-0.05;    glClear(GL_COLOR_BUFFER_BIT);    glLineWidth(5);    glBegin(GL_LINE_LOOP);for (i=0; i<100; i++)    {        glVertex2f(R*cos(2*PI/100*i),R*sin(2*PI/100*i));    }    glEnd();    glLineWidth(2);for (i=0; i<12; i++){    glBegin(GL_LINES);            glVertex2f(TR*sin(2*PI/12*i),TR*cos(2*PI/12*i));            glVertex2f(R*sin(2*PI/12*i),R*cos(2*PI/12*i));        glEnd();}    glLineWidth(1);h_Length=0.2;m_Length=0.3;s_Length=0.4;count=60;s_Angle=s/count;count*=60;m_Angle=(m*60+s)/count;count*=12;h_Angle=(h*60*60+m*60+s)/count;glLineWidth(1);glBegin(GL_LINES);        glVertex2f(0.0f,0.0f);        glVertex2f(s_Length*sin(2*PI*s_Angle),s_Length*cos(2*PI*s_Angle));    glEnd();    glLineWidth(5);    glBegin(GL_LINES);        glVertex2f(0.0f,0.0f);        glVertex2f(h_Length*sin(2*PI*h_Angle),h_Length*cos(2*PI*h_Angle));    glEnd();    glLineWidth(3);    glBegin(GL_LINES);        glVertex2f(0.0f,0.0f);        glVertex2f(m_Length*sin(2*PI*m_Angle),m_Length*cos(2*PI*m_Angle));    glEnd();    glLineWidth(1);    glBegin(GL_POLYGON);for (i=0; i<100; i++)    {        glVertex2f(0.03*cos(2*PI/100*i),0.03*sin(2*PI/100*i));    }    glEnd();    glutSwapBuffers();}void Update(){    time_t rawtime;    struct tm * timeinfo;    time ( &rawtime );    timeinfo = localtime ( &rawtime );    h=timeinfo->tm_hour;    m=timeinfo->tm_min;    s=timeinfo->tm_sec;    glutPostRedisplay();}int main(int argc, char *argv[]){    glutInit(&argc, argv);    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);    glutInitWindowPosition(100, 100);    glutInitWindowSize(400, 400);    glutCreateWindow("HelloOpenGL");    glutIdleFunc(&Update);    glutDisplayFunc(&Draw);    glutMainLoop();    return 0;}



原创粉丝点击