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函数会被调用。
这时我们再编译运行一次,发现同样可以显示画面。其实这个时候,画面是在不断地更新的,只是你感觉不出来而已。
指针并没有动,因为指针的读数和h,m,s三个参数有关,而这三个参数的值是固定的。把这三个参数改为全局变量,让其在其他函数中也可以被使用,然后在Update函数中,更新h,m,s的值为当前系统的时间就可以了。最后记得去掉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;}
- OpenGL织梦之旅【第二章】第2节.实现动画
- OpenGL织梦之旅【第四章】第2节.简单的3D动画
- OpenGL织梦之旅【第二章】第1节.绘制基本的几何图形
- OpenGL织梦之旅【第二章】第3节.指定颜色以及定义视口
- OpenGL织梦之旅【第三章】第3节.实现截图功能
- OpenGL织梦之旅【第三章】第2节.循环显示图片
- OpenGL织梦之旅【第0章】前言
- OpenGL织梦之旅【第三章】第1节.纹理贴图
- OpenGL织梦之旅【第三章】第4节.glut键盘鼠标响应
- OpenGL织梦之旅【第四章】第1节.设置视点函数gluLookAt
- OpenGL织梦之旅【第二章】编写一个的钟表程序
- 安全参透之旅第2章 Zenmap工具使用第二节
- 我的opengl之旅--第一篇 配置opengl
- 利用OpenGL实现动画效果
- OpenGL骨骼动画的实现
- 《OpenGL编程基础》第二章笔记2
- OpenGL ES1.1.12 第二章 2.9.2
- OpenGL ES1.1.12 第二章 2.10.2
- Hibernate三种状态的转换
- WinCE5.0开发环境的建立
- POJ 3628 Bookshelf 2
- CEGUI 中文按钮
- sqlite3在ARM上的移植
- OpenGL织梦之旅【第二章】第2节.实现动画
- WDK介绍与安装
- JavaSE第三十三讲:Java数组常见问题深度解析
- Hibernate4入门到精通一——————第一个Hibernate程序
- Android root 有感
- optics算法
- IPV4 与IPV6 头部结构与其区别
- 对比基于boost::function/bind和AS3 Function回调机制
- 第二十四节 java学习 包