[OpenGL] 斯坦福兔子與顯示列表


          


       

1.調整桌子的大小。

 

        在OpenGL繪制長方體,能夠通過函數:

         glutSolidCube(Size)

         繪制得到的是一個正方體,再利用縮放矩陣使其變成長方體。使得桌子的大小剛好能夠放下16僅僅兔子。

 

2.兔子的增多降低

 

        使用一個全局變量rabbitNum來記錄兔子的數量。

        在鍵盤回調函數中,在按下I,K后令rabbitNum添加或降低,並維護兔子的數量在1~16,等於16或1不再進行對應操作。

        繪制兔子時。通過循環控制,每畫完一僅僅兔子,平移一段距離,畫到第4i+1僅僅兔子時。平移到下一行。

        在普通繪制模式下,直接調用繪制桌子、兔子函數。

        在顯示列表繪制模式下。調用事先准備好的桌子顯示列表和兔子顯示列表來繪制。

 

3.FPS

 

        fps的含義是每秒傳輸幀數,它的大小反映了繪制的流暢性。在這里我們須要計算普通以及顯示列表模式下fps大小的差別。

        計算fps。我們能夠調用該函數:

        glutGet( GLUT_ELAPSED_TIME );

        該函數返回兩次調用glutGet(GLUT_ELAPSED_TIME)的時間間隔,單位為毫秒。

        通過得到兩次調用的間隔時間,我們能夠計算繪制圖像的刷新幀率。

        我們用frame變量存儲幀數,兩次間隔調用時間差大於1000ms時我們更新fps的值。依照定義fps = 幀數/時間。

 

        調用例如以下函數:

        glutBitmapCharacter( GLUT_BITMAP_HELVETICA_18 , *c);

        能夠把字符變成位圖顯示在窗體中。

 

4.顯示列表

 

         通過調用:

          glGenLists(int num)

        我們得到了num個連續的顯示列表,返回第一個顯示列表。

        glNewList(name, mode ); 

        ……

        glEndList();

        在這兩者之間,寫要增加顯示列表的詳細語句。

類似於數組。下一個顯示列表僅僅需移動偏移值1就能夠了得到名稱了。

        glCallList(name);

       調用顯示列表。


實驗數據記錄和處理 

 

        

           

         通過實驗,我們發如今使用了顯示列表的情況下,每秒刷新的幀率更高。它是一種快速的緩存,當我們須要重復地繪制同一物體時,能夠將其存入顯示列表,並在繪制時調用顯示列表,這樣就避免了由於重復調用而導致的重復計算。

        缺點是不能動態繪制,也就是說我們后來在外面改動了一些變量的值,是不會影響到顯示列表的。詳細到此次實驗來說,我們不能把繪制多次兔子的循環放入顯示列表,由於循環的次數會隨着兔子次數的變化而變化,而一旦載入入了顯示列表,這樣的動態是無法體現出來的,顯示列表僅僅會存儲最初始增加時的狀態。所以我們僅僅能把繪制兔子的函數放入顯示列表,而在普通的函數中進行循環控制。

// glutEx1.cpp : 定義控制台應用程序的入口點。
//
//注意FPS函數的應用

#include <stdlib.h>
#include "glut.h"
#include <stdio.h>
#include <string.h>

#include "stanford_bunny.h"

float eye[] = {0, 4, 6};  //眼睛位置
float center[] = {0, 0, 0};  //視點位置
float fDistance = 0.2f;    //距離因子
float fRotate = 0;  //旋轉因子
bool bAnim = false;  //是否旋轉

bool bDrawList = false;  //是否使用顯示列表
GLint tableList=0;   //桌子列表
GLint rabbitList = 0;    //兔子列表
int rabbitNum = 1;     //兔子數量

//繪制桌子
void DrawTable()
{
	glPushMatrix();
	glTranslatef(0, 3.5, 0);
	glScalef(5, 1, 4);

	glPushMatrix();
	glScalef(1.3, 0.4, 1.3);
	glutSolidCube(1.0);  
	glPopMatrix();

	glPopMatrix();

	glPushMatrix();
	glTranslatef(2.0, 0.5, 1.5);
	glScalef(0.6, 5, 0.6);
	glutSolidCube(1.0);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(-2.0, 0.5, 1.5);
	glScalef(0.6, 5, 0.6);
	glutSolidCube(1.0);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(2.0, 0.5, -1.5);
	glScalef(0.6, 5, 0.6);
	glutSolidCube(1.0);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(-2.0, 0.5, -1.5);
	glScalef(0.6, 5, 0.6);
	glutSolidCube(1.0);
	glPopMatrix();
}

GLint GenTableList()
{
	GLint lid=glGenLists(2); //生成兩個空的顯示列表
	glNewList(lid, GL_COMPILE);  // 用於創建和替換一個顯示列表函數原型
	                             // 指定顯示列表的名稱,編譯模式:僅僅編譯

	//第一個顯示列表:畫桌子
	DrawTable();
	glEndList();

	//第二個顯示列表:畫兔子
	glNewList(lid + 1, GL_COMPILE);
	DrawBunny();
	glEndList();

	return lid; //返回顯示列表編號
}

void Draw_Table_List()
{	
	glPushMatrix();
	glTranslatef(2.2, 4.5, 1.5); //平移與縮放
	glScalef(2, 2, 2);

	for (int i = 1; i <= rabbitNum; i++) {
		glCallList(rabbitList);     //調用顯示列表畫兔子
		if (i == 4 || i == 8 || i == 12) {
			glTranslatef(2.1f, 0, -0.5f);  //兔子換行
		}
		else glTranslatef(-0.7f, 0.0f, 0.0f); //兔子平移
	}
	glPopMatrix();

	glCallList(tableList);  //調用顯示列表畫桌子
}

void DrawScene()
{
	glPushMatrix();
	glTranslatef(2.2, 4.5, 1.5);
	glScalef(2, 2, 2);

	for (int i = 1; i <= rabbitNum; i++) {
		DrawBunny();   //直接繪制兔子
		if (i==4||i==8||i==12) {
			glTranslatef(2.1f, 0, -0.5f);    //兔子換行
		}
		else glTranslatef(-0.7f, 0.0f, 0.0f);    //兔子平移
	}
	glPopMatrix();

	DrawTable();   //直接繪制桌子
}

void reshape(int width, int height)
{
	if (height == 0)
	{
		height = 1;  //高度為0時,讓高度為1  
	}

	glViewport(0, 0, width, height);    //設置視窗大小  

	glMatrixMode(GL_PROJECTION);    //設置矩陣模式為投影  
	glLoadIdentity();           //初始化矩陣為單位矩陣  

	float whRatio = (GLfloat)width / (GLfloat)height;
	gluPerspective(45, whRatio, 1, 1000);	//設置投影方位  

	glMatrixMode(GL_MODELVIEW);   //設置矩陣模式為模型  
}

void idle()
{
	glutPostRedisplay();  //調用當前繪制函數  
}

void key(unsigned char k, int x, int y)
{
	switch(k)
	{
	case 27:
	case 'q': {exit(0); break; }

	case 'a':  //物體左移
		{
			eye[0] += fDistance; 
			center[0] += fDistance;
			break;
		}
	case 'd':   //物體右移
		{
			eye[0] -= fDistance;
			center[0] -= fDistance;
			break;
		 }
	case 'w':   //物體上移
		{
			eye[1] -= fDistance;
			center[1] -= fDistance; 
			break;
		}
	case 's':   //物體下移
		{
			eye[1] += fDistance;
			center[1] += fDistance;
			break;
		}
	case 'z':    //靠近
		{
			eye[2] *= 0.95;
			break; 
		}
	case 'c':    //遠離
		{
			eye[2] *= 1.05;
			break;
		 }
	case 'l':    // 切換顯示列表和非顯示列表繪制方式
		{
			bDrawList = !bDrawList;	
			break;
		}
	case ' ':     //旋轉
		{
			bAnim = !bAnim; 
			break;
		}
	case 'i':     //兔子增多
		{
			if(rabbitNum<=15)rabbitNum++;
			break;
		} 
	case 'k':     //兔子降低
		{
			if (rabbitNum>=2)rabbitNum--;
			break;
		}
	default: break;
	}
}

void getFPS()
{
	static int frame = 0, time, timebase = 0;
	static char buffer[256]; //字符串緩沖區

	char mode[64]; //模式
	if (bDrawList)   //是否用顯示列表繪制
		strcpy(mode, "display list");
	else
		strcpy(mode, "naive");

	frame++;  
	time=glutGet(GLUT_ELAPSED_TIME);
	//返回兩次調用glutGet(GLUT_ELAPSED_TIME)的時間間隔,單位為毫秒
	if (time - timebase > 1000) { //時間間隔差大於1000ms時
		sprintf(buffer,"FPS:%4.2f %s",
			frame*1000.0/(time-timebase), mode); //寫入buffer中
		timebase = time; //上一次的時間間隔
		frame = 0;
	}

	char *c;
	glDisable(GL_DEPTH_TEST);     // 禁止深度測試
	glMatrixMode(GL_PROJECTION);  // 選擇投影矩陣
	glPushMatrix();               // 保存原矩陣
	glLoadIdentity();             // 裝入單位矩陣
	glOrtho(0,480,0,480,-1,1);    // 位置正投影
	glMatrixMode(GL_MODELVIEW);   // 選擇Modelview矩陣
	glPushMatrix();               // 保存原矩陣
	glLoadIdentity();             // 裝入單位矩陣
	glRasterPos2f(10,10);
	for (c=buffer; *c != '\0'; c++) {		
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c); //繪制字符
	}
	glMatrixMode(GL_PROJECTION);  // 選擇投影矩陣
	glPopMatrix();                // 重置為原保存矩陣
	glMatrixMode(GL_MODELVIEW);   // 選擇Modelview矩陣
	glPopMatrix();                // 重置為原保存矩陣
	glEnable(GL_DEPTH_TEST);	  // 開啟深度測試
}

/*畫圖函數*/
void redraw() 
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//清除顏色和深度緩存
	glClearColor(0, 0.5, 0, 1); //設置清除顏色
	glLoadIdentity(); //初始化矩陣為單位矩陣

	gluLookAt(eye[0], eye[1], eye[2],
		center[0], center[1], center[2],
		0, 1, 0);				
	// 場景(0,0,0)的視點中心 (0, 5, 50)。Y軸向上
	// 視點位置。望向位置,頭頂方向

	glEnable(GL_DEPTH_TEST);  //開啟深度測試
	glEnable(GL_LIGHTING);    //開啟光照
	GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 };    //設置灰色
	GLfloat light_pos[] = {10, 10, 10, 1};      //設置光源位置
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,gray);   //指定整個場景的環境光強度
	glLightfv(GL_LIGHT0, GL_POSITION, light_pos);  //設置第0號光源的光照位置
	glLightfv(GL_LIGHT0, GL_AMBIENT, gray); //設置第0號光源多次反射后的光照顏色(環境光顏色)
	glEnable(GL_LIGHT0);  //開啟第0號光源

	if (bAnim) 
		fRotate += 0.5f; //改變旋轉因子
	glRotatef(fRotate, 0, 1.0f, 0);			//繞y軸旋轉

	glScalef(0.4, 0.4, 0.4);   //縮放
	if(!bDrawList)
		DrawScene();						// 普通繪制
	else 
		Draw_Table_List();                  // 顯示列表繪制

	getFPS();  //得到每秒傳輸幀數(Frames Per Second)
	glutSwapBuffers(); //交換緩沖區
}

int main (int argc,  char *argv[])
{
	glutInit(&argc, argv);//初始化glut
	glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
	//初始化顯示模式:RGB顏色模型,雙緩沖,深度測試
	glutInitWindowSize(480,480);//設置窗體大小
	int windowHandle = glutCreateWindow("Exercise 4");
	//取得新建窗體的句柄
	glutDisplayFunc(redraw);//注冊顯示函數
	glutReshapeFunc(reshape);	//注冊重繪函數
	glutKeyboardFunc(key); //注冊鍵盤回調事件
	glutIdleFunc(idle); //注冊空暇回調事件

	tableList = GenTableList();  //初始化顯示列表
	rabbitList = tableList + 1;

	glutMainLoop(); //開啟時間循環
	return 0;
}









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM