OpenGL-动画
動(dòng)畫:就是連續(xù)播放一系列圖片的過程,如果每秒播放超過24張圖片則會(huì)認(rèn)為是連續(xù)的,每秒播放的越多,則越平滑。
1.雙緩沖技術(shù)
計(jì)算機(jī)上的動(dòng)畫和實(shí)際動(dòng)畫的不同之處:實(shí)際的動(dòng)畫都是提前畫好了,播放的時(shí)候直接拿出來顯示就可以。計(jì)算機(jī)動(dòng)畫則是,畫一張,拿一張,并不是提前畫好的。這樣會(huì)出現(xiàn)一個(gè)問題,就是對于簡單動(dòng)畫,計(jì)算機(jī)畫的速度可以跟上播放的速度,那么對于復(fù)雜的動(dòng)畫,則繪制時(shí)間較長,可能還沒繪制完畢,就得顯示,那么對于這種問題,提出了一種解決方案,稱之為 雙緩沖技術(shù)。所謂的雙緩沖技術(shù)就是:就是設(shè)置兩塊畫面繪制區(qū)域,一塊作為發(fā)送到顯示器的數(shù)據(jù),一塊作為繪畫的區(qū)域,在適當(dāng)?shù)臅r(shí)候交換它們,由于交換兩塊內(nèi)存區(qū)域?qū)嶋H上只需交換兩個(gè)指針即可,這一方法效率非常高,所以被廣泛采用。 // 啟用雙緩沖功能, 使用GLUT 工具包 main函數(shù)里面這樣寫 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); // GLUT_SINGLE 表示單緩沖,改成GLUT_DOUBLE 就表示雙緩沖2. 實(shí)現(xiàn)連續(xù)動(dòng)畫
在實(shí)現(xiàn)連續(xù)動(dòng)畫的時(shí)候,一般方法是:如果你需要繪制窗口了,那就請調(diào)用 myDispaly函數(shù)。單由于我們的程序無法知道究竟在什么時(shí)候該繪制,因?yàn)?一般的窗口操作系統(tǒng),都是支持多窗口同時(shí)顯示。恰好你的程序窗口被別的 窗口遮住,然后用戶又把原來的窗口移開,這樣就需要對窗口進(jìn)行重新繪制。 然而這一切,我們無法預(yù)料,只能委托操作系統(tǒng)代為辦理。這里我們使用glutIdleFunc 來實(shí)現(xiàn)在 cpu 空閑時(shí)間來調(diào)用繪制窗口函數(shù), 重新繪制窗口,實(shí)現(xiàn)動(dòng)畫效果。 // 太陽 月亮 地球案例 #include <GL/glut.h> static int day = 200; void myDispay(void) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 400000000);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1);// 繪制紅色的“太陽”glColor3f(1.0f, 0.0f, 0.0f);glutSolidSphere(69600000, 20, 20);// 繪制藍(lán)色的“地球”glColor3f(0.0f, 0.0f, 1.0f);glRotatef(day/360.0*360.0, 0.0f, 0.0f, -1.0f);glTranslatef(150000000, 0.0f, 0.0f);glutSolidSphere(15945000, 20, 20);// 繪制黃色的“月亮”glColor3f(1.0f, 1.0f, 0.0f);glRotatef(day/30.0*360.0 - day/360.0*360.0, 0.0f, 0.0f, -1.0f);glTranslatef(38000000, 0.0f, 0.0f);glutSolidSphere(4345000, 20, 20);glFlush();// 這里繪制完畢后,需要交換緩沖區(qū)glutSwapBuffers(); } void myIdle(void) {/*作用是把日期往后移動(dòng)一天,并重新繪制 達(dá)到動(dòng)畫效果*/if(++day >= 360){day = 0;}myDisplay(); // 重新繪制窗口 } int main(int argc,char *argv[]) {glutInit(&argc,argv);// 使用雙緩沖區(qū)glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);glutInitWindowPostion(100,100);glutInitWindowSize(400,400);glutCreateWindow("太陽,地球和月亮");glutDisplayFunc(&myDisplay);// 該句 改變day 重新繪制窗口、 實(shí)現(xiàn)動(dòng)畫效果// glutIdleFunc 可以使得CPU 在空閑時(shí)間 調(diào)用某一函數(shù)干某些事情glutIdleFunc(&myIdle);glutMainLoop();return 0; }3. 垂直同步
由于顯示器的刷新頻率有限,如果讓計(jì)算機(jī)繪制一個(gè)簡單圖形,則有可能一秒鐘 繪制上萬次,因此,如果最大限度的利用計(jì)算機(jī)處理能力,繪制出很多副畫面, 但是顯示器的刷新速度卻跟不上,這樣不僅造成性能的浪費(fèi),還有可能帶來一些負(fù) 面影響(比如 當(dāng)顯示器只刷新到一半時(shí)候,需要繪制的內(nèi)容變化了,由于顯示器 是逐行刷新,所以會(huì)導(dǎo)致顯示器上半部分和下班部分是來自兩幅不同的畫面。)采用垂直同步技術(shù)可以解決這一問題。當(dāng)只有在顯示器刷新時(shí)候,才把繪制好的圖 像傳輸顯示。這樣,計(jì)算機(jī)就不必去繪制大量的根本用不到的圖像了。單也存在問題:若刷新頻率為60Hz,在簡單場景,繪制一幅畫需要的時(shí)間很短, 幀速可以恒定60FPS(60幀/s),若場景復(fù)雜,繪制一幅畫的時(shí)間超過了1/60秒,則 幀速將急劇下降,如果繪制一幅畫時(shí)間為 1/50,則在第一個(gè)1/ 60 秒時(shí),顯示器 需要刷新了,但由于新的圖沒有繪制好,所以只能顯示原來的圖畫,等到下一個(gè) 1/60 秒時(shí)才顯示新圖畫,于是顯示一幅畫實(shí)際上用了1 /30 秒,幀數(shù)為30FPS。試想如果一幅圖的復(fù)雜程度不一致,且繪制它們的時(shí)間都在1/60,則在1/60時(shí)間內(nèi) 畫完,則幀數(shù)為60FPS,,在1/60時(shí)間未完成,幀速為30FPS,這樣就造成幀速跳動(dòng)。4. 計(jì)算幀速
定義: 幀速就是一秒鐘內(nèi)播放的畫面數(shù)目(FPS) #include <time.h> double CalFrequency() {/*幀速計(jì)算*/static int cout;static double save;static clock_t last,current;double timegap;++count;if(cout <= 50){return save;}count = 0;last = current;current = clock();timegap = (current - last) / (double)CLK_TCK;save = 50.0 / timegap; // 按照 50FPS 計(jì)算 瞬時(shí)幀速return save; }天體運(yùn)動(dòng)完整代碼
#include <GL/glut.h> #include <stdio.h> #include <time.h>static int day = 200; double CalFrequency() {/* 計(jì)算幀速*/static int count;static double save;static clock_t last, current;double timegap;++count;if( count <= 50 ){return save;}count = 0;last = current;current = clock();timegap = (current-last)/(double)CLK_TCK;save = 50.0/timegap;return save; } void myDisplay(void) {double FPS = CalFrequency();printf("FPS = %lf\n", FPS);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 400000000);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1);// 繪制紅色的“太陽”glColor3f(1.0f, 0.0f, 0.0f);glutSolidSphere(69600000, 20, 20);// 繪制藍(lán)色的“地球”glColor3f(0.0f, 0.0f, 1.0f);glRotatef(day/360.0*360.0, 0.0f, 0.0f, -1.0f);glTranslatef(150000000, 0.0f, 0.0f);glutSolidSphere(15945000, 20, 20);// 繪制黃色的“月亮”glColor3f(1.0f, 1.0f, 0.0f);glRotatef(day/30.0*360.0 - day/360.0*360.0, 0.0f, 0.0f, -1.0f);glTranslatef(38000000, 0.0f, 0.0f);glutSolidSphere(4345000, 20, 20);glFlush();glutSwapBuffers(); } void myIdle(void) {++day;if( day >= 360 ){day = 0;}myDisplay(); } int main(int argc,char* argv[]) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("太陽,地球和月亮");glutDisplayFunc(&myDisplay);glutIdleFunc(&myIdle);glutMainLoop();return 0; }總結(jié)
- 上一篇: 三星手机安装linux系统下载,技术|在
- 下一篇: O2O模式和B2C模式的区别是什么?