今天要讲的是动画制作——可能是各位都很喜欢的。除了讲授知识外,我们还会让昨天那个“太阳、地球和月亮”天体图画动起来。缓和一下枯燥的气氛。
本次课程,我们将进入激动人心的计算机动画世界。想必大家都知道电影和动画的工作原理吧?是的,快速的把看似连续的画面一幅幅的呈现在人们面前。一旦每秒钟呈现的画面超过24幅,人们就会错以为它是连续的。我们通常观看的电视,每秒播放25或30幅画面。但对于计算机来说,它可以播放更多的画面,以达到更平滑的效果。如果速度过慢,画面不够平滑。如果速度过快,则人眼未必就能反应得过来。对于一个正常人来说,每秒60~120幅图画是比较合适的。具体的数值因人而异。假设某动画一共有n幅画面,则它的工作步骤就是:显示第1幅画面,然后等待一小段时间,直到下一个1/24秒显示第2幅画面,然后等待一小段时间,直到下一个1/24秒……显示第n幅画面,然后等待一小段时间,直到下一个1/24秒结束如果用C语言伪代码来描述这一过程,就是:1 for(i=0; i
1 for(i=0; i
1 #include2 3 // 太阳、地球和月亮 4 // 假设每个月都是30天 5 // 一年12个月,共是360天 6 static int day = 200; // day的变化:从0到359 7 void myDisplay(void) 8 { 9 /****************************************************10 这里的内容照搬上一课的,只因为使用了双缓冲,补上最后这句11 *****************************************************/12 glutSwapBuffers();13 }14 15 void myIdle(void)16 {17 /* 新的函数,在空闲时调用,作用是把日期往后移动一天并重新绘制,达到动画效果 */18 ++day;19 if( day >= 360 )20 day = 0;21 myDisplay();22 }23 24 int main(int argc, char *argv[])25 {26 glutInit(&argc, argv);27 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); // 修改了参数为GLUT_DOUBLE28 glutInitWindowPosition(100, 100);29 glutInitWindowSize(400, 400);30 glutCreateWindow("太阳,地球和月亮"); // 改了窗口标题31 glutDisplayFunc(&myDisplay);32 glutIdleFunc(&myIdle); // 新加入了这句33 glutMainLoop();34 return 0;35 }
Code:
1 #include2 double CalFrequency() 3 { 4 static int count; 5 static double save; 6 static clock_t last, current; 7 double timegap; 8 9 ++count;10 if( count <= 50 )11 return save;12 count = 0;13 last = current;14 current = clock();15 timegap = (current-last)/(double)CLK_TCK;16 save = 50.0/timegap;17 return save;18 }
最后,要把计算的帧速显示出来,但我们并没有学习如何使用OpenGL把文字显示到屏幕上。——但不要忘了,在我们的图形窗口背后,还有一个命令行窗口~使用printf函数就可以轻易的输出文字了。
1 #include2 3 double FPS = CalFrequency();4 printf("FPS = %f\n", FPS);
最后的一步,也被我们解决了——虽然做法不太雅观,没关系,以后我们还会改善它的。时间过得太久,每次给的程序都只是一小段,一些朋友难免会出问题。现在,我给出一个比较完整的程序,供大家参考。
Code:
1 #include2 #include 3 #include 4 5 // 太阳、地球和月亮 6 // 假设每个月都是12天 7 // 一年12个月,共是360天 8 static int day = 200; // day的变化:从0到359 9 10 double CalFrequency()11 {12 static int count;13 static double save;14 static clock_t last, current;15 double timegap;16 17 ++count;18 if( count <= 50 )19 return save;20 count = 0;21 last = current;22 current = clock();23 timegap = (current-last)/(double)CLK_TCK;24 save = 50.0/timegap;25 return save;26 }27 28 void myDisplay(void)29 {30 double FPS = CalFrequency();31 printf("FPS = %f\n", FPS);32 33 glEnable(GL_DEPTH_TEST);34 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);35 36 glMatrixMode(GL_PROJECTION);37 glLoadIdentity();38 gluPerspective(75, 1, 1, 400000000);39 glMatrixMode(GL_MODELVIEW);40 glLoadIdentity();41 gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1);42 43 // 绘制红色的“太阳”44 glColor3f(1.0f, 0.0f, 0.0f);45 glutSolidSphere(69600000, 20, 20);46 // 绘制蓝色的“地球”47 glColor3f(0.0f, 0.0f, 1.0f);48 glRotatef(day/360.0*360.0, 0.0f, 0.0f, -1.0f);49 glTranslatef(150000000, 0.0f, 0.0f);50 glutSolidSphere(15945000, 20, 20);51 // 绘制黄色的“月亮”52 glColor3f(1.0f, 1.0f, 0.0f);53 glRotatef(day/30.0*360.0 - day/360.0*360.0, 0.0f, 0.0f, -1.0f);54 glTranslatef(38000000, 0.0f, 0.0f);55 glutSolidSphere(4345000, 20, 20);56 57 glFlush();58 glutSwapBuffers();59 }60 61 void myIdle(void)62 {63 ++day;64 if( day >= 360 )65 day = 0;66 myDisplay();67 }68 69 int main(int argc, char *argv[])70 {71 glutInit(&argc, argv);72 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);73 glutInitWindowPosition(100, 100);74 glutInitWindowSize(400, 400);75 glutCreateWindow("太阳,地球和月亮");76 glutDisplayFunc(&myDisplay);77 glutIdleFunc(&myIdle);78 glutMainLoop();79 return 0;80 }
小结:OpenGL动画和传统意义上的动画相似,都是把画面一幅一幅的呈现在观众面前。一旦画面变换的速度快了,观众就会认为画面是连续的。双缓冲技术是一种在计算机图形中普遍采用的技术,绝大多数OpenGL实现都支持双缓冲技术。通常都是利用CPU空闲的时候绘制动画,但也可以有其它的选择。介绍了垂直同步的相关知识。介绍了一种简单的计算帧速(FPS)的方法。最后,我们列出了一份完整的天体动画程序清单。===================== 第六课 完 ==========================================TO BE CONTINUED=====================