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;
}