今天讲一下如何做动画,动画本质上就是一张一张的图片在很短的时间内放过去,以至于人们认为这是动起来的不是由一张一张图片放过去。
(一)双缓冲技术
其实在Java做游戏的时候已经遇到过这个问题了,提到这个概念讲一下什么叫单缓冲,单缓冲就是在显示物体的时候,是在屏幕上开始绘画的。
双缓冲:先把画,花在缓冲区然后在把缓冲放到屏幕上。
为什么要这么做:
因为在绘画简单的图的时候并不是很需要双缓冲,单缓冲来得及,但是绘画过于复杂那么就会来不及画出来,屏幕上显示的就是不完整的图画。这样的效果很不好。所以要使用双缓冲技术。
这个是怎么使用双缓冲方法:
在main函数里面写:
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
其中GLUT_SINGLE表示单缓冲,如果改成GLUT_DOUBLE就是双缓冲了。
当然还有需要更改的地方——每次绘制完成时,我们需要交换两个缓冲区,把绘制好的信息用于屏幕显示(否则无论怎么绘制,还是什么都看不到)。如果使用GLUT工具包,也可以很轻松的完成这一工作,只要在绘制完成时简单的调用glutSwapBuffers函数就可以了。
而且我们在绘制图画的时候应该是在cpu空闲的时候,不能因为我们要画图就让歌不放了,视频不看了,这个明显是不合理的。
所以使用glut中的glutIdleFunc()函数来在cpu空的时候绘画。使用方法我下面代码写了。
#include <GL/glut.h> #include <stdio.h> #include<stdlib.h> static float n = -1.0; void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW);//使用模型矩阵 glLoadIdentity();//消除之前矩阵的影响 glTranslatef(0.0f, n, 0.0f); glutSolidSphere(1, 80, 16); glutSwapBuffers(); } void ne()//图像变化的函数 { n += 0.1; if (n >= 0.0f) { n = -1.0; } display(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowPosition(150, 150); glutInitWindowSize(400, 400); glutCreateWindow("透视投影变换"); //init(); glutDisplayFunc(display); glutIdleFunc(ne); glutMainLoop(); return 0; }
这个程序就是很简单的把一个圆移动特定的位置。
还有一点就是gflush函数和glutSwapBuffers两个函数的问题,因为glutSwapBuffers函数会自动刷新一次缓存区,如果在使用一次glflush那么效率就会很低。
->
这个就是效果的变化。
(二)垂直同步
这个是一种可以控制帧数的方法。
引用一下别人的话(自己说起来解释不清):
大家知道显示器的刷新率是比较有限的,一般为60~120Hz,也就是一秒钟刷新60~120次。但如果叫计算机绘制一个简单的画面,例如只有一个三角形,则一秒钟可以绘制成千上万次。因此,如果最大限度的利用计算机的处理能力,绘制很多幅画面,但显示器的刷新速度却跟不上,这不仅造成性能的浪费,还可能带来一些负面影响(例如,显示器只刷新到一半时,需要绘制的内容却变化了,由于显示器是逐行刷新的,于是显示器上半部分和下半部分实际上是来自两幅画面)。采用垂直同步技术可以解决这一问题。即,只有在显示器刷新时,才把绘制好的图象传输出去供显示。这样一来,计算机就不必去绘制大量的根本就用不到的图象了。如果显示器的刷新率为85Hz,则计算机一秒钟只需要绘制85幅图象就足够,如果场景足够简单,就会造成比较多的CPU空闲。
几乎所有的显卡都支持“垂直同步”这一功能。
垂直同步也有它的问题。如果刷新频率为60Hz,则在绘制比较简单的场景时,绘制一幅图画需要的时间很段,帧速可以恒定在60FPS(即60帧/秒)。如果场景变得复杂,绘制一幅图画的时间超过了1/60秒,则帧速将急剧下降。
如果绘制一幅图画的时间为1/50,则在第一个1/60秒时,显示器需要刷新了,但由于新的图画没有画好,所以只能显示原来的图画,等到下一个1/60秒时才显示新的图画。于是显示一幅图画实际上用了1/30秒,帧速为30FPS。(如果不采用垂直同步,则帧速应该是50FPS)
如果绘制一幅图画的时间更长,则下降的趋势就是阶梯状的:60FPS,30FPS,20FPS,……(60/1,60/2,60/3,……)
如果每一幅图画的复杂程度是不一致的,且绘制它们需要的时间都在1/60上下。则在1/60时间内画完时,帧速为60FPS,在1/60时间未完成时,帧速为30FPS,这就造成了帧速的跳动。这是很麻烦的事情,需要避免它——要么想办法简化每一画面的绘制时间,要么都延迟一小段时间,以作到统一。
但是一般的英伟达的显卡这个功能是自带启动的,其他的不一定。
(三)
这个是我没事干看到的。+第一次我在学opengl的时候我看到main函数里面有个显示时才进行绘画的函数,我在想为什么要用这个直接调用绘画的函数不就好了,但是有一个问题,就是你的窗口被覆盖或者被移动了那么什么时候进行重新画呢?你的main函数里面不可能定义这么多的信息。所以只能通过glut那些函数来交给系统,让系统决定什么时候进行重画。