忆龙2009:OPENGL处理帧刷新

来源:互联网 发布:视频网站 数据库 编辑:程序博客网 时间:2024/05/05 03:25

转自:http://book.csdn.net/bookfiles/60/100601696.shtml

 

     在图形计算机上,可以完成的最激动人心的事情之一就是绘制能够移动的图片。无论你是一位试图看到自己所设计的机械零件所有侧面的工程师,还是一位使用模拟飞行器学习驾驶飞机的飞行员,或者仅仅是一位计算机游戏的狂热爱好者,都会觉得动画(animation)是计算机图形的一个重要组成部分。

     在电影院里,屏幕上的运动画面是通过拍摄大量的图片,然后以每秒24帧的频率把它们投影到屏幕上来实现的。每一帧移动到镜头后的一个位置,接着快门打开,然后这一帧便被显示。 在影片切换到下一帧的一瞬间,快门关闭,接下来又打开显示下一帧,以此类推。尽管所看到的是每秒24帧不同的画面,但大脑会把它们混合成一段平滑的动画。(老式的卓别林电影每秒播放16帧,因此有比较明显的跳动现象。)在一般情况下,计算机图形屏幕每秒大约刷新(重绘画 面)60~76次,有些甚至每秒刷新120次。显然,60帧每秒比30帧每秒的效果更为平滑,而120 帧每秒的效果又强于60帧每秒。但是,如果刷新率超过120帧每秒,就有可能到达衰减点,具体取决于人眼感知的极限。

      运动图片投影方法之所以可行的关键原因是每个帧在显示的时候已经完成绘制。假如试图用一个如下的程序来实现计算机动画,播放数以百万帧计的影片:

 

 

      如果加上系统清除屏幕以及绘制一个典型的帧所需要的时间,这个程序将会产生越来越差的效果,具体取决于清除和绘图所占用的时间与1/24秒的接近程度。假如绘图时间差不多需要1/24 秒。那么第一个被绘制的物体在这1/24秒的时间内是可见的,并在屏幕上显示一幅实体图像。但是,这一帧中临近最后被绘制的物体将被立即清除,因为程序紧接着要显示下一帧。这就导致了 一个非常可怕的场景:在这1/24秒的绝大部分时间里,所看到的并不是最后被画好的物体,而是 被清除的背景。问题在于这个程序并不是显示已经完整画好的帧,所看到的是帧的绘制过程。 绝大多数OpenGL实现提供了双缓冲(硬件或软件),提供两个完整的颜色缓冲区。当一个 缓冲区被显示时,另一个正在进行绘图。当一个帧绘制完成后,两个缓冲区就进行交换。这样, 刚刚用来显示的那个缓冲区现在就用于绘图,反之亦然。这类似于循环播放两个帧的电影放映 机。当其中一帧被投影到屏幕上时,画家迅速擦掉并重绘那个当前未显示的帧。只要画家的动 作足够快,观众并不会注意到这种方式和事先画好所有的帧然后再投影的区别。电影放映机只 是简单地一幅又一幅地显示它们而已。使用双缓冲,每一帧只在绘图完成后才被显示,观众永远不会看到不完整的帧。

 

 

     在有些OpenGL实现中,除了简单地交换显示和绘图缓冲区之外,还使用swap_the_buffer() 函数进行等待,直到当前的屏幕刷新周期结束,这样前一个缓冲区的内容就能够完整地显示。 这个函数还允许从头开始完整地显示新缓冲区。假定系统每秒刷新60次,意味着可以实现的最 快帧率是60帧每秒(fps)。如果所有的帧都可以在不到1/60秒的时间内完成清除和绘制,动画将在这个帧率下非常平滑地显示。

 

     如果帧的内容过于复杂,无法在1/60秒的时间内完成绘制,那会发生什么情况呢?此时每帧 被显示的次数将不止一次。例如,如果每帧需要1/45秒的时间才能完成绘制,而帧率是30fps, 这样每帧就有1/30秒-1/45秒=1/90秒(或者说三分之一)的空闲时间。

此外,视频刷新频率是固定的,这就有可能导致一些意想不到的性能问题。例如,在一台 刷新率为1/60秒并要求帧率固定的显示器上,可以在60fps、30fps、20fps、15fps、12fps(60/1、60/2、60/3、60/4、60/5、...)等帧率下运行。这意味着如果正在编写一个应用程序,并且逐渐 增加功能(假如应用程序是一个飞行模拟器,并且正在添加地面场景),最初所添加的每个特性 对总体性能不会有影响,仍然可以获得60fps的帧率。突然之间,当又增加了一个新特性之后, 系统无法在1/60秒的时间画完一帧中的所有物体,于是动画从60fps下降到30fps,因为系统错过 了第一次缓冲区交换的时间。当每帧的绘图时间超过1/30秒时,也会发生类似的事情,动画的帧 率将从30fps下降到20fps。

      如果场景的复杂度接近于任一魔幻时间(指本例中的1/60秒、2/60秒、3/60秒等临界时间), 由于随机变化,有些帧会稍微多于这个时间,有些帧则稍微小于这个时间。这样,帧率便会变 得无规律,可能会导致视觉上的混乱。在这种情况下,如果无法对场景进行简化,使所有的帧 都足够快,最好有意增加一小段延迟,使它们都错过这个魔幻时间,统一到下一个更慢的固定 帧率。如果各个帧的复杂性具有极大的差异,可能需要采取一种更为复杂的方法。

      实时动画程序的结构与这里所描述的相差并不大。通常,对于每个帧而言,较之判断缓冲区的哪部分需要重绘,重新绘制整个缓冲区要更容易一些。对于诸如三维飞行模拟器这样的应用程序,情况更是如此。在这种应用程序中,飞机方向的略微改变就可能导致窗外所有物体的位置都发生改变。

      在绝大多数动画中,场景中的物体简单地根据不同的转换进行重绘,例如根据观察者移动的视点、根据路上前行的汽车或根据一个略微旋转的物体。如果非绘图操作所涉及的重新计算量非常大,动画的帧率可能会降低。但是,记住swap_the_buffer()函数之后的空闲时间总是可以用来进行这类计算。