• [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 != ''; 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;
    }
    
    
    






  • 相关阅读:
    numpy库:常用基本
    高考的结束,新的开始
    Hello World!
    第一篇随笔
    Linux命令之文件与用户权限
    看山不是山,看水不是水
    Python基础篇【第1篇】: Python基础
    css居中
    JS正则表达式(一)
    小问题总结
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7355856.html
Copyright © 2020-2023  润新知