logo资料库

关于opengl的桌子 杯子 酒瓶的场景.doc

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
1. 程序说明 1.1 图形项目说明: 即将毕业,以“夏日狂欢”与同学们告别。“夏日狂欢”绘制了一个三维场景,主要包括 四个部分,一张简易的桌子,一瓶红葡萄酒,五个杯子,一个电风扇,十分简陋,一是因为我 所掌握的技术不够,二是因为,这就是我们的生活,它模拟的,是前年宿舍五人共渡中秋佳节 的情景,只是当时凉快,而现在已经是炎炎夏日了,天气热时就用右键菜单打开我们的小电风 扇吧;看不见背面的场景,就用上下左右键旋转视图吧。 1.2 术语定义 旋转矩阵:指 glRotatef()产生的矩阵 纹理映射:指应用内存中的图像覆盖模型表面 1.3 参考资料 《OpenGL 三维图形系统开发与实用技术(基础编程篇)》 清华大学出版社 《Computer Graphics with OpenGL,Third Edition》 D. Hearn, M.P Baker 电子工业出版社 2 应用软件的总体设计 2.1 需求规定 : 输入:键盘的“←”、“↑”、“→”和“↓”;鼠标。 输出:显示屏。 基本图形建模: 工具库:立方体,球。 实用库:二次曲面、NURBS 曲面。 使用旋转、平移、放大缩小等方法变换坐标矩阵,组成相应物体。使用纹理和光照模型, 完善场景外观。 其它处理: 工具库:创建子窗口,使用定时器,创建右键菜单,键盘响应函数。 核心库:光栅位图。 Windows 相关:读 BMP 位图作为纹理数据。 2.2 运行环境 具体说明自己程序的开发和运行环境(软,硬件). 开发环境:Visual C++ 6.0 Console 运行环境: 硬件: 项目 CPU 时钟频率 内存 硬盘 软件: OpenGL Pentinum 或 Pentinum Pro 90MHz 16/32/64MB 512MB 本人运行环境 PM 1.5GHz 512MB 40GB Windows 2000 或 Windows XP 头文件:gl.h, glu.h, glut.h, math.h, windows.h, stdib.h, stdio.h 动态链接库:glu.dll, glu32.dll, glut32.dll 和 opengl32.dll 静态链接库:glu32.lib, glut32.lib, opengl32.lib 1
2.3 基本设计概念和流程图(要求较为详细)  软件系统创意的简要说明:本软件系统的基本设计方案 数据定义 纹理数据 文字位图 酒瓶列表 桌子列表 电扇列表 杯子列表 子窗口 主窗口 右键菜单 定时器 键盘响应 绘图循环 消息循环 初 始 化 绘 图  系统的初始化(如,背景色的设定,单/双缓存的说明) 1 使用双缓冲、RGB 模式、深度缓冲 2 主窗口设置 window=glutCreateWindow ("夏日狂欢"); glutReshapeFunc(main_reshape); glutDisplayFunc(main_display); glutSpecialFunc(screen_special); glutCreateMenu(menu); 主窗口的背景色设置为蓝色,在其 display 函数中定义。 3 子窗口设置 screen = glutCreateSubWindow(window, 50, 50, 600, 600); init ( ); glutDisplayFunc (screen_display); glutSpecialFunc(screen_special); glutReshapeFunc(screen_reshape); glutTimerFunc(3, timf, 0); // 设置定时器 glutCreateMenu(menu); 其中主窗口和子窗口的键盘响应函数和右键菜单设置均相同,这是防止当鼠标不 在子窗口范围内时出现不响应的情况;初始化函数 init( )载入纹理、显示列表等。 主窗口和子窗口的 Reshape 函数均设置为视口不随窗口变化而变化。 主窗口投影矩阵设置为 gluOrtho2D;子窗口投影矩阵设置为直角投影,在子窗口 的 display 函数中。 4 子窗口初始化 2
子窗口为主要的绘图窗口,初始化背景为黑色,开启光照、二维纹理设置、深度 测试及归一化处理。 glClearColor (0.0, 0.0, 0.0, 0.0); glFrontFace(GL_CCW); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); 子窗口初始化函数中载入纹理、光照模型、显示列表,定义像素存储属性,定义 二次曲面及 NURSE 曲面属性。 loadlight(); qobj = gluNewQuadric(); theNurb = gluNewNurbsRenderer(); gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0); gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); loadtexture(); loadlist(); 光照为: void loadlight() { GLfloat ambient[] = {0.5, 0.5, 0.5, 1.0}; GLfloat diffuse[] = {1, 1, 1.0, 1.0}; GLfloat specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat position[] = {40.0, 40.0, 40.0, 0.0}; GLfloat lmodel_ambient[] = {0.2, 0.2, 0.2, 1.0}; GLfloat local_view[] = {0.0}; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_POSITION, position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); } loadtexture( )和 loadlist( )在稍后详解。  对象模型的建立 1 桌子 桌子的绘制较为简单,分别用 glScalef 将 glutSolidCube 绘出的正方体变形为扁扁 的桌面和长长的桌脚,然后用 glTranslate 平移至相应的位置,最后贴上纹理。贴纹理 时先自动计算纹理坐标满贴整个桌子,此时效果并不理想,尤其是桌面,所以将两面 桌面重新贴上手动计算的纹理。 void table() { tablelist=glGenLists(1); 3
glNewList(tablelist,GL_COMPILE); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_2D); 自动计算二维纹理 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, texName); 使用桌子的木制纹理 glScalef(1.6,0.05,1); glutSolidCube(50); glPopMatrix(); glPushMatrix(); glTranslatef(35,-15,20); glScalef(0.1,1,0.1); glutSolidCube(30); ……… 坐标变换使下面要重置矩阵 桌面 重置模型矩阵 桌脚 其余三个桌脚 glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); 关闭自动计算二维纹理 glPopMatrix(); glPushMatrix(); glBegin(GL_QUADS); 手动指定纹理坐标贴桌面 glTexCoord2f(0.0, 0.0); glVertex3f(-40, 1.5, -25); glTexCoord2f(1.0, 0.0); glVertex3f(-40,1.5,25); glTexCoord2f(1.0, 1); glVertex3f(40,1.5,25); glTexCoord2f(0.0, 1); glVertex3f(40,1.5,-25); glTexCoord2f(0.0, 0.0); glVertex3f(-40, -1.5, -25); glTexCoord2f(1.0, 0.0); glVertex3f(-40,-1.5,25); glTexCoord2f(1.0, 1); glVertex3f(40,-1.5,25); glTexCoord2f(0.0, 1); glVertex3f(40,-1.5,-25); glEnd(); glDisable(GL_TEXTURE_2D); glEndList(); } 2 酒瓶 酒瓶是本场景中最难画的一个物体,它由四部份组成,一是瓶身下半部份,二是 酒瓶中的酒,以上两部分用二次曲面的 gluCylinder 完成;第三是瓶身的上半部分,用 两个相同的 NURSE 曲面模拟;以上三部份均需开启融合,即 GL_BLEND。最后一部 分是酒瓶上的标签,由 NURSE 曲面构建并贴图,疑惑的是,此部分的贴图始终没有 贴好,也没有找到原因,可能是坐标计算不当。 void bottle() { 4
bottlelist=glGenLists(1); glNewList(bottlelist,GL_COMPILE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 以半透明方式与背景融合 开启融合 设置 Alpha 为 0.5 绘制酒瓶下半部份 绘制红葡萄酒 glEnable(GL_BLEND); material(0.7,0.1,0.1,0.5,0.7,0.1,0.1,0.5,0.0,0.0,0.0); glPopMatrix(); glPushMatrix(); glTranslatef(0,17,0); glRotatef(90,1,0,0); gluCylinder(qobj,3.8,3.8,17,50,20); glPopMatrix(); glPushMatrix(); material(1,0.9,0.9,0.5,0.9,0.9,0.9,0.5,0.0,0.0,0.0); glTranslatef(0,20,0); glRotatef(90,1,0,0); gluCylinder(qobj,4.5,4.5,20,50,20); glPopMatrix(); glPushMatrix(); glTranslatef(0,20,0); glScalef (2,2,2.5); glRotatef(-90.0, 1.0,0.0,0.0); gluBeginSurface(theNurb); gluNurbsSurface(theNurb, 绘制酒瓶上半部分的一半 8, knots, 8, knots, 4 * 3, 3, &ctlpoints[0][0][0], 4, 4, GL_MAP2_VERTEX_3); gluEndSurface(theNurb); glRotatef(180.0, 0.0,0.0,1.0); gluBeginSurface(theNurb); gluNurbsSurface(theNurb, 将上半部分旋转 180 度绘制另一半 8, knots, 8, knots, 4 * 3, 3, &ctlpoints[0][0][0], 4, 4, GL_MAP2_VERTEX_3); gluEndSurface(theNurb); glDisable(GL_BLEND); //----------------------------------------- glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D); 关闭融合 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, texName+1); glPopMatrix(); glPushMatrix(); glTranslatef(0,3,0); 贴标签 5
glScalef (2.1,2.1,2.7); glRotatef(-90.0, 1.0,0.0,0.0); gluBeginSurface(theNurb); gluNurbsSurface(theNurb, 8, knots, 8, knots, 4 * 3, 3, &ctlpoints2[0][0][0], 4, 4, GL_MAP2_TEXTURE_COORD_2); 纹理坐标 gluNurbsSurface(theNurb, 8, knots, 8, knots, 4 * 3, 3, &ctlpoints2[0][0][0], 4, 4, GL_MAP2_VERTEX_3); 对应点坐标 gluEndSurface(theNurb); glDisable(GL_TEXTURE_2D); glEndList(); } NURSE 曲面的控制点为: GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; GLfloat ctlpoints[4][4][3]={ {{-0.55,0,10},{-0.55*XP,0.55*XP,10.0},{0.55*XP,0.55*XP,10.0},{0.55,0,10.0}}, {{-0.55,0,6},{-0.55*XP,0.55*XP,6.0},{0.55*XP,0.55*XP,6.0},{0.55,0,6.0}}, {{-1.0,0,4},{-1.0*XP,1.0*XP,4.0},{1.0*XP,1.0*XP,4.0},{1.0,0,4.0}}, {{-2.25,0,0},{-2.25*XP,2.25*XP,0.0},{2.25*XP,2.25*XP,0.0},{2.25,0,0.0}}}; GLfloat ctlpoints2[4][4][3]={ {{-2.25,0,6},{-2.25*XP,2.25*XP,6.0},{2.25*XP,2.25*XP,6.0},{2.25,0,6.0}}, {{-2.25,0,3},{-2.25*XP,2.25*XP,3.0},{2.25*XP,2.25*XP,3.0},{2.25,0,3.0}}, {{-2.25,0,2},{-2.25*XP,2.25*XP,2.0},{2.25*XP,2.25*XP,2.0},{2.25,0,2.0}}, {{-2.25,0,1},{-2.25*XP,2.25*XP,1.0},{2.25*XP,2.25*XP,1.0},{2.25,0,1.0}}}; 3 酒杯 酒杯由三部分构成,一是杯身,由二次曲面构建;二是杯底,是由一个球体压扁 后平移至相应的位置;三是杯中的酒,也是由二次曲面构建。上述三个部分均为透明。 void cap() { caplist=glGenLists(1); glNewList(caplist,GL_COMPILE); 开启融合模式 杯中酒 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glPopMatrix(); glPushMatrix(); material(0.7,0.1,0.1,0.5,0.7,0.1,0.1,0.5,0.0,0.0,0.0); glTranslatef(0,5,0); glRotatef(90,1,0,0); gluCylinder(qobj,2,1.8,3,20,20); material(0.7,0.7,0.5,0.7,0.7,0.7,0.5,0.7,0.0,0.0,0.0); glPopMatrix(); 杯底 6
glPushMatrix(); glTranslatef(0,2,0); glScalef(1,0.2,1); gluSphere(qobj,2,10,10); glPopMatrix(); glPushMatrix(); glTranslatef(0,10,0); glRotatef(90,1,0,0); gluCylinder(qobj,2.5,1.8,10,50,20); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); 杯身 关闭融合模式 glEndList(); } 由于场景中由多个酒杯,其调用模式如下: glPopMatrix(); glPushMatrix(); glTranslatef(X,Y,Z); 表示酒杯的位置 glPushMatrix(); glCallList(caplist); glPopMatrix(); 4 电扇 电扇模拟的是小微风扇,由两个部分组成,一是其中心的圆,由球压扁而成;二 是三片叶子,为使其看起来有一点厚度,由三个圆台的曲面压扁并旋转平移到相应位 置。电扇的难点在于对旋转矩阵的控制。经分析矩阵相乘的属性和多次尝试,采用 Translate/Scale/Rotate 的顺序。 void fan() { fanlist=glGenLists(1); glNewList(fanlist,GL_COMPILE); material(0.7,0.1,0.1,0.5,0.7,0.1,0.1,0.5,0.0,0.0,0.0); glPopMatrix(); glPushMatrix(); glTranslatef(0,40,0); glScalef(1,0.3,1); gluSphere(qobj,2,20,20); material(0.7,0.7,0.7,1.0,0.7,0.7,0.7,1.0,0.0,0.0,0.0); glPopMatrix(); glPushMatrix(); glTranslatef(0,40,0); glScalef(1,0.05,1); glRotatef(120,0,1,0); gluCylinder(qobj,1,3,10,20,20); glPopMatrix(); glPushMatrix(); 7 中心小红圆 周围的三片白叶子 旋转 120 度的叶子 不旋转的叶子
glTranslatef(0,40,0); glScalef(1,0.05,1); gluCylinder(qobj,1,3,10,20,20); glPopMatrix(); glPushMatrix(); glTranslatef(0,40,0); glScalef(1,0.05,1); glRotatef(240,0,1,0); gluCylinder(qobj,1,3,10,20,20); glEndList(); } 由于电扇要旋转,调用模式为: glPopMatrix(); glPushMatrix(); glTranslatef(20,-5,20); if(TurnOn==GL_TRUE) { fantheta+=10; if(fantheta==360) fantheta=0; } glRotatef(fantheta,0,1,0); glPushMatrix(); glCallList(fanlist); glPopMatrix(); TurnOn 由右键菜单控制,并由定时函数控制旋转速度。 旋转 240 度叶子 控制电扇位置 每次旋转 10 度 旋转矩阵 表项为“关电扇” 重绘子窗口 表项为“天热了,开电扇吧” void menu(int choice) { switch (choice) { case 2: TurnOn=GL_FALSE; redisplay_all(); break; case 1: TurnOn=GL_TRUE; redisplay_all(); break; } } void timf(int value) { redisplay_all(); glutTimerFunc(3, timf, 0); } 8
分享到:
收藏