openGL构造教室.docx
《openGL构造教室.docx》由会员分享,可在线阅读,更多相关《openGL构造教室.docx(60页珍藏版)》请在冰豆网上搜索。
openGL构造教室
基于openGL的虚拟教室
——虚拟现实与数据可视化课程作业
董元22011207
指导老师:
孙立博老师
仪器科学与工程学院
2013年12月16日
一、作业要求
用openGL制作一个虚拟教室。
要求视角可变化,教室里的物品不少于五件。
二、完成情况
我的openGL虚拟教室完成情况如下:
1、绘制出的教室里的基本物体:
黑板、讲台、投影仪、空调、门窗、音响、九张桌子、九张凳子等。
虚拟教室整体看上去接近真实生活中的教室。
2、添加了灯光和纹理效果:
门窗以及空调均是用纹理贴出来的。
使教室看起来更加生动形象。
3、为教室加上了可用键盘控制的动态效果:
可控制灯光亮灭、投影仪收起放下、六块黑板的上下滑动以及音响的开关。
4、引用FMOD音乐引擎,为教室加上可控背景音效(即3中的音响开关)。
5、在输出窗口添加操作提示信息,使界面更加人性化。
三、成果演示
1、整体效果图
2、改变视角效果
3、开灯关灯对比效果图
未开灯时:
开灯时:
4、投影仪放下效果图:
5、黑板移动效果图
6、局部细节效果图
四、内容介绍
下面我将从代码的角度简单介绍一下我的整个教室程序。
代码部分包括一个头文件(MyHeader.h)和一个cpp文件(main.cpp)。
为了增加程序的可读性,我将相关的变量定义、函数声明等集中放置在头文件下面。
在我的全部代码中,除了主函数外,共定义了19个子函数。
如下图所示:
主程序部分和一般的openGL程序一样,完成初始化、窗口的绘制、显示回调函数和键盘以及一些特殊事件的响应。
主函数如下:
初始化部分由函数init()完成,而init中又调用了进行灯光初始化的函数initlight()以及进行纹理图像载入的LoadTexture1()、LoadTexture2()、LoadTexture3()。
这主要是因为灯光初始化和载入纹理相关代码较多,这么做是为了使代码看上去更加层次分明
绘制教室的工作由回调函数display()完成。
而所有子函数中与绘制教室相关的子函数还有DrawRoom()、DrawDesk()、DrawBlackboard()以及Drawotherthings();分别完成教室墙面、黑板、桌椅及其他物体的绘制。
其中,整个教室空间有六个大矩形拼接而成;桌椅由梯形不一的长方体拼接而成。
可以这样说,整个教室基本上都是由不同的立方体和矩形构成的。
所以从这一点上来说,绘制教室并没有使用任何复杂的openGL内置函数。
响应按键主要是由OnKeyboard()和OnSpecial()完成的。
OnSpecia()函数其实只是响应退出窗口的ECS键,为了从逻辑上区分这一事件与普通按键响应的不同,我把响应这一事件的代码放在了OnSpecia()函数下。
而其他响应普通事件的代码则在OnKeyboard()下。
而普通事件的响应程序,又调用到了函数InitFMOD(),(响应播放音乐),函数projector_dispaly1()、projector_dispaly2(),(响应投影仪的放下与收起,实质是在对窗口的重新绘制时改变投影仪的相关参数)。
五、收获感想
1、对于任何一种编程语言或者是API,当我们在使用它们编程时,都首先要对其基本原理有一个最基本的认识。
贸然地调用函数或是凭感觉去编程,往往会造成不可预知的错误。
而且一旦错误发生,往往很难解决。
在程序的编写过程中,最开始时对openGL了解甚少,在参考示例程序时移植他人的代码往往很难产生自己希望的效果,就是这个道理。
而且,在编写整个程序的过程中,出现过一个我一直无法解决的问题:
通过编译后程序运行一段时间自己会卡死。
在请教了老师以后才知道,该问题出现的原因是我把载入纹理的代码放在了显示回调函数中,这样一来每一次重新绘制窗口,程序都会开辟新的内存用以储存相关信息。
因此程序运行一段时间之后内存不足,便会报错。
这个问题是我自己很难考虑到的,这也是让我认识到自己对程序的基本理解的不足,这方面需要进一步加强。
2、我觉得这次作业给我带来最大的收获就是它起到了一个抛砖引玉的效果。
虚拟教室的创立不仅让我对openGL这个图像程序接口产生了很大的兴趣,也让我对虚拟现实技术产生了更多的期待。
而且,在编写程序的过程中我又接触到一个有趣的音乐引擎FMOD。
这些都让我觉得这门课程的学习妙趣横生。
虽然我在这个作业上花费了很多时间,但是收获了很多乐趣。
3、在编写程序的过程中,我进一步意识到网络这个公开平台资源的强大。
在自学的过程中,别人的经验给了我许多启发。
网络上许多达人开放式的共享资源的态度值得我们学习。
互联网的发展为打开了巨大的学习空间,而在未来的学习生活中,我想我也会秉承这样一种开源共享的态度,学习知识,并且传播知识。
六、附录
(一)参考书目
[1]MasonWooJakieNeiderTomDavisDaveShreiner/著吴斌段海波薛凤舞/译《openGL编程权威指南》中国电力出版社
[2]网络资源:
Nehe的中文openGL教程
(二)代码
1、main.cpp
#include
#include
#include
#include
#include
#include"MyHeader.h"//相关变量和函数定义放入头文件中,增加程序可读性
#include"fmod.h"//音频库的头文件
#pragmacomment(lib,"fmodvc.lib")//把音频库加入到链接器中
#pragmacomment(lib,"GLAux.lib")
#pragmawarning(disable:
4996)//强制忽略VS2012对于老版本一些函数不安全的警告
usingnamespacestd;
FSOUND_SAMPLE*handle1;
intmain(intargc,char**argv)
{
Eye.x=0.0f;//f代表这个数据是GLfloat类型的常量
Eye.y=0.0f;
Eye.z=18.0f;
glutInit(&argc,argv);//对glut进行初始化
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);//指定
glutInitWindowSize(700,600);//窗口大小,以像素为单位窗
glutInitWindowPosition(650,100);//口左上角的屏幕位置
glutCreateWindow(argv[0]);
init();//初始化
glutDisplayFunc(display);//显示回调函数
glutReshapeFunc(reshape);
glutKeyboardFunc(OnKeyboard);
constGLubyte*test=glGetString(GL_EXTENSIONS);
glutSpecialFunc(OnSpecial);
glutIdleFunc(OnIdle);
PrintInformation();
glutMainLoop();//调用来启动程序
return0;
}
/***************函数名称:
LoadBitmap***********************************************************
****************函数作用:
检查文件能否被正常打开,不能则返回一个空指针***************************/
AUX_RGBImageRec*LoadBitmap(char*Filename)
{
//声明一个文件句柄用于打开文件
FILE*File=NULL;
//文件名不能空
if(!
Filename)
{
returnNULL;
}
//以只读方式打开文件测试文件是否能够打开
File=fopen(Filename,"r");
//文件是否存在
if(File)
{
//存在,则关闭文件
fclose(File);
//装入测试过已存在的文件
returnauxDIBImageLoad(Filename);
}
//文件装入失败,返回NULL
returnNULL;
}
/***************函数名称:
LoadTexture1*********************************************************
****************函数作用:
装入位图文件并作为纹理贴图********************************************/
intLoadTexture1()
{
intStatus=FALSE;
AUX_RGBImageRec*TextureImage=0;
glGenTextures(1,&texture[0]);
if(TextureImage=LoadBitmap("Images\\6.bmp"))
{
Status=TRUE;
glBindTexture(GL_TEXTURE_2D,texture[0]);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage->sizeX,TextureImage->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
if(TextureImage)//释放资源
{
if(TextureImage->data)
{
free(TextureImage->data);
}
free(TextureImage);
}
}
returnStatus;
}
/***************函数名称:
LoadTexture2*********************************************************
****************函数作用:
装入位图文件并作为纹理贴图********************************************/
intLoadTexture2()
{
intStatus=FALSE;
AUX_RGBImageRec*TextureImage=0;
glGenTextures(2,&texture[1]);
if(TextureImage=LoadBitmap("Images\\0.bmp"))
{
Status=TRUE;
glBindTexture(GL_TEXTURE_2D,texture[1]);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage->sizeX,TextureImage->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
if(TextureImage)//释放资源
{
if(TextureImage->data)
{
free(TextureImage->data);
}
free(TextureImage);
}
}
returnStatus;
}
/***************函数名称:
LoadTexture3*********************************************************
****************函数作用:
装入位图文件并作为纹理贴图********************************************/
intLoadTexture3()
{
intStatus=FALSE;
AUX_RGBImageRec*TextureImage=0;
glGenTextures(1,&texture[2]);
if(TextureImage=LoadBitmap("Images\\1.bmp"))
{
Status=TRUE;
glBindTexture(GL_TEXTURE_2D,texture[2]);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage->sizeX,TextureImage->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
if(TextureImage)//释放资源
{
if(TextureImage->data)
{
free(TextureImage->data);
}
free(TextureImage);
}
}
returnStatus;
}
/***************函数名称:
LoadTexture4*********************************************************
****************函数作用:
装入位图文件并作为纹理贴图********************************************/
intLoadTexture4()
{
intStatus=FALSE;
AUX_RGBImageRec*TextureImage=0;
glGenTextures(1,&texture[3]);
if(TextureImage=LoadBitmap("Images\\2.bmp"))
{
Status=TRUE;
glBindTexture(GL_TEXTURE_2D,texture[3]);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TextureImage->sizeX,TextureImage->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
if(TextureImage)//释放资源
{
if(TextureImage->data)
{
free(TextureImage->data);
}
free(TextureImage);
}
}
returnStatus;
}
/***************函数名称:
intlight************************************************************
****************函数作用:
初始化灯光设置*******************************************************/
voidinitlight(void)
{
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,model_ambient);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT0,GL_POSITION,light_position0);
glLightfv(GL_LIGHT0,GL_AMBIENT,mat_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,white_light);
glLightfv(GL_LIGHT0,GL_SPECULAR,white_light);
glLightfv(GL_LIGHT6,GL_POSITION,light_position6);
glLightfv(GL_LIGHT6,GL_AMBIENT,mat_ambient);
glLightfv(GL_LIGHT6,GL_DIFFUSE,white_light);
glLightfv(GL_LIGHT6,GL_SPECULAR,white_light);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
}
/***************函数名称:
init****************************************************************
****************函数作用:
初始化设置**********************************************************/
voidinit(void)
{
glClearColor(0,0,0,0);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
LoadTexture1();
initlight();
glShadeModel(GL_SMOOTH);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);//指定材料着色的面
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);//指定材料对镜面光的反射
glEnable(GL_DEPTH_TEST);//
LoadTexture1();//载入纹理1
LoadTexture2();//载入纹理2
LoadTexture3();//载入纹理3
LoadTexture4();//载入纹理4
}
/***************函数名称:
DrawRoom************************************************************
****************函数作用:
绘制教室墙面以及两侧石柱*********************************************/
voidDrawRoom()
{
glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse1);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
//----------------开始绘制房间---------------------------------------------------------
glColor3f(0.8f,1.0f,0.8f);
glBegin(GL_QUADS);//glNormal3f用于定义点的法向量
glNormal3f(0.0f,1.0f,0.0f);//绘制地板
glVertex3f(-50.0f,-30.0f,-80.0f);
glVertex3f(-50.0f,-30.0f,20.0f);
glVertex3f(50.0f,-30.0f,20.0f);
glVertex3f(50.0f,-30.0f,-80.0f);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3,0.3,0.3);
glNormal3f(0.0f,-1.0f,0.0f);//绘制天花板
glVertex3f(-50.0f,30.0f,20.0f);
glVertex3f(-50.0f,30.0f,-80.0f);
glVertex3f(50.0f,30.0f,-80.0f);
glVertex3f(50.0f,30.0f,20.0f);
glEnd();
glColor3f(0.8f,0.8f,0.8f);
glBegin(GL_QUADS