基于Opengl的屏幕对象拾取 毕业论文

更新时间:2024-04-26 16:50:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

论文题目: 基于OpenGL的屏幕对象拾取 系 别: 计算机系 专业年级:

学 号: 姓 名: 指导教师、职称:

年 05 月 10 日

I

目录

摘要 ................................................................................ 1 ABSTRACT ............................................................................ 2 1 绪论 .............................................................................. 3 1.1 课题的目的和意义 ................................................................ 3 11..22 拾拾取取技技术术国国内内外外研研究究 .............................................................. 3 1.3 本论文研究主要内容 .............................................................. 3 2 基于OPENGL+MFC的建模基础 ........................................................ 5 2.1 OpenGL概括 ...................................................................... 5 2.2 OpenGL渲染管线过程 .............................................................. 5 2.2.1顶点变换 ..................................................................... 6 2.2.2图元组装 ..................................................................... 6 2.2.3图元处理 ..................................................................... 6 2.2.4片元处理 ..................................................................... 6 2.2.5光栅化操作 ................................................................... 6 2.3 MFC概述 ......................................................................... 6 2.4 MFC特点 ......................................................................... 7 2.4.1封装 ......................................................................... 7 2.4.2继承 ......................................................................... 8 2.4.3虚拟函数和动态约束 ........................................................... 8 2.5 应用程序的构成 .................................................................. 8 2.6 基于OpenGL+MFC的三维模拟的编程环境配置 ......................................... 9 3 拾取技术 ......................................................................... 12 3.1 基于射线求交拾取技术 ........................................................... 12 3.1.1判断线段和包围盒的相对位置 .................................................. 12 3.2 基于GPU的重绘式拾取技术 ....................................................... 14 3.3 各种拾取技术比较 ............................................................... 16 4 系统的设计及实现 ................................................................. 18 4.1 系统的选择机制 ................................................................. 18 4.1.1进入选择模式之前 ............................................................ 18 4.1.2获取当前选择模式 ............................................................ 18 4.1.3退出选择模式 ................................................................ 20 4.1.4拾取 ........................................................................ 20 4.2 拾取结果截图 ................................................................... 21 5 结论与展望 ...................................................................... 25 5.1 结论 ........................................................................... 25 5.2 展望 ........................................................................... 25 参考文献 ........................................................................... 26 致谢 ............................................................................... 28

II

摘要

屏幕对象的拾取是计算机图形处理系统中一个重要的功能,在许多情况下,计算机图形处理系统不仅要绘制图形,而且要允许操作者能够通过输入设备(通常是鼠标)操纵屏幕上的物体(标识、移动和修改)。有时还需要获取物体上点的空间坐标或测量物体的几何特性如距离、角度、半径等,这些操作都需要以拾取作为实现的基础。OpenGL为了解决拾取问题,提供了一种基于名字堆栈和命中记录的选择机制。在OpenGL中,拾取物体是利用拾取矩阵和投影变换,将拾取的范围限制在鼠标热点的有效区中,一旦触发鼠标事件就进入选择模式并将有效区初始化,最后利用拾取矩阵拾取有效区内的物体。有效区的定义由glPick2Matix()函数来完成。一旦拾取成功,就以记录的形式返回与拾取物体相关的信息,并生成一个记录表示一个物体被命中。这种物体拾取方法非常简单,不需要写很多代码。

在使用OpenGL工具包开发图形处理系统时,物体的拾取有多种方法,其中包括OpenGL提供的选择机制、射线拾取法、重绘式拾取法等。本文采用OpenGL本身提供的选择机制来拾取对象,突出OpenGL工具包在屏幕对象的拾取方面的优势。 关 键 词:OpenGL;计算机应用;拾取算法

1

Abstract

In most cases, one important feature of graphics processing system is picking, which allow users to select objects by mouse, and to modify the their attributes, such as gemetry mesh or angle and so on. In order to solve the problem, pick OpenGL provides a name on the stack and hit record choice mechanism. In the OpenGL and pickobject is using the loot matrix and projection transformation, and will gather in the limits of the mouse, effective once entered the mouse event trigger mode choice and will be effective area, finally using initialization gleaned matrix pick objects in the area of effective. The definition of effective glPick2Matix () function to finish. Once pick success, to return to pick the record object relevant

information, and to create a record, says an object to be hit. This object pick method is very simple, need not write many code.

In the use of graphics processing system development OpenGL toolkit objects, pick a variety of methods, including OpenGL provide choice mechanism, ray pick, redrawn type gather method, etc. Based on the mechanism of OpenGL itself to provide choice pickup, outstanding OpenGL toolkit objects in the screen in the object.

Key words: OpenGL; computer application;picking

2

1 绪论

目前许多优秀的图形工具能为我们绘制惟妙惟肖的虚拟现实场景,在面对这些场景时候我们除了欣赏之外更多的是希望能与之互动,做为编程人员可以使用代码轻松的重新构造场景,但对于终端用户而言,他们也希望自己也能对造场景进行一些操作,如添加,删除等等。对于这些操作而言,首先我们要做的是能让用户使用鼠标来选择他所希望操作的对象,这就是本文要讨论的一个重点:拾取,这是一种在许多交互性程序中有基础地位的操作,是对屏幕中对象进行定位,并确定所选择的是哪个物体。然而该操作给我们提出了一些难题,首先,需要对对象进行届定。其次,必须对“拾取目标”进行定义。这就需要终端用户确定单击的位置是构成对象的图元上,还是对象附近的位置以及考虑如果选取点落在两个以上物体交集部分如何处理等等问题,本文利用了OpenGL中的选择模式进行有效的对象判别和拾取。 1.1 课题的目的和意义

图形对象的拾取是计算机图形处理系统中一个重要的功能,很多图形系统需要用户通过输入设备与系统交互,如移动、旋转某个物体,或查询某个物体的状态信息,需要通过拾取来确定景中的操作对象。快速可靠的拾取被广泛地运用于各种系统中,如实时图形系统、虚拟现实、游戏和CAD系统等方面,拾取操作己成为这些系统的重要部分,它在计算机建模软件尤其重要,能够通过拾取操作对模型进行局部修改和编辑,提高建模系统的灵活性和适用性。随着计算机软硬件的快速发展,人们对实时系统的交互的实时性要求也越发苛刻,而且三维场景复杂度也日益提高,这就要求系统提供快速的拾取操作。因此,高效的拾取算法能够决定拾取操作快与慢的关键所在,从而开发高效的拾取算法已成为当今一个的课题研究。 1.2 拾取技术国内外研究

随着网络科技越来越发达,拾取操作也越来越方便了,有的只要鼠标点点就可以。而拾取操作的关键是拾取算法。到目前为止,拾取算法大致上可以分三种。第一种是基于射线求交的拾取技术,1992年,Mark Segul,Carl Korobkin,Rolf van Widenfelt等人首次采用了基于射线求交的拾取

[1]

技术原理实现了对衣服的拾取;1998年Michael Deering,Step hanie Winner and Bic Schediwy

[2]

等也才采用了同样的技术成功做到了人物的拾取;2005年,龚堰珏,颜敏等人采用了基于射线求

[3]

交的拾取技术实现对几个简单物体的拾取;同年,韦宇炜也是用此技术实现对游戏中各类的拾取,

[4]

如对技能的释放,对地上物品的捡起来,对别的玩家人物属性的查看等等;2006年,姚继权,李

[5]

晓豁等人也采用了这种拾取技术成功地做到了对3D网游游戏中的各种各样的拾取,等等。第二种是基于GPU的重绘式拾取技术,这种方法对硬件的依赖性大,不过拾取速度快。1997年,Masaaki.Oka,Kyoya Tsutsui,Akio Ohba等人第一次采用了基于GPU的重绘式拾取技术在房子中拾取到了房子主

[6]

人与小孩子;2006年,刘力强,周明全等多人采用基于GPU的重绘式拾取技术,在大规模室外地

[7]

形中拾取到了地面某个区域。第三种是OpenGL自带的拾取机制,1992年7月,SGI公司发布了OpenGL的1.0版本,随后又与微软公司共同开发了Windows NT版本的OpenGL,从而使一些原来必须在高档图形工作站上运行的大型3D图形处理软件也可以在微机上运用。1995年OpenGL的1.1版本面市,该版本较1.0性能提高许多,并加入了一些新的功能,如本身自带的拾取机制,这项功能

[8]

使OpenGL在各个领域都得到了应用。随后出现的各个版本,使自带的拾取机制越来越完善,操作越来越方便,应用范围越来越广泛。 1.3 本文研究的主要内容

(一):综述本课题研究的意义以及国内外研究现状;

(二):介绍了OpenGL与OpenGL渲染管道,分析MFC编程框架和基于OpenGL+MFC的三维模拟的编程环境配置;

(三):各种拾取技术的实现原理,优缺点;

(四):采用了OpenGL本身自带的拾取机制设计并实现简单的拾取操作;

3

(五):总结本文并进一步给出了展望。

4

2 基于OpenGL+MFC的建模基础

2.1 OpenGL概括

OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言、跨平台的编程软件接口的规格,该接口包括了大约250个不同的函数(其中核心OpenGL大约包括200个函数,另外还有50个左右位于OpenGL工具函数库),可以用这些函数指定物体和操作,创建交互性三维应用程序。它是个专业的图形程序接口,是一个功能强大,调用方便的底层图形库,Opengl用于三维图象(二维的亦可)。

OpenGL的设计目标就是作为一种流线型的、独立于硬件的接口,可以在许多不同的硬件平台上实现。为了实现这个目标,OpenGL并未包含用于执行窗口任务或者获取用户输入之类的函数。反之,必须通过窗口系统控制所使用的特定硬件。类似地,OpenGL并没有提供用于描述三维物体模型的高层函数。这类函数可能允许你指定相对较为复杂的形状,例如汽车、身体的某 个部位、飞机或分子等。在OpenGL中,必须根据少数几个基本几何图元(geometric primitive)(如点、直线和多边形)来创建你所需要的模型。当然,我们可以在OpenGL上创建能够提供这些特性的高级函数库。OpenGL 实用函数库(GLU)提供了许多建模特性,例如二次曲面以及NURBS曲线和表面。GLU是所有OpenGL实现的一个标准组成部分。

1992年7月,SGI公司发布了OpenGL的1.0版本,随后又与微软公司共同开发了Windows NT版本的OpenGL,从而使一些原来必须在高档图形工作站上运行的大型3D图形处理软件也可以在微机上运用。

1995年OpenGL的1.1版本面市,该版本较1.0性能提高许多,并加入了一些新的功能。 1997年,Windows 95下3D游戏的大量涌现,游戏开发公司迫切需要一个功能强大、兼容性好的3D图形接口,而当时微软公司自己的3D图形接口DirectX 3.0功能却是很糟糕。因而以制作《雷神之锤》等经典3D射击游戏而著名的id公司同其它一些游戏开发公司一同强烈要求微软在Windows95中加入对OpenGL的支持。微软公司最终在Windows95的OSR2版和后来的Windows版本中加入了对OpenGL的支持。这样,不但许多支持OpenGL的电脑3D游戏得到广泛应用,而且许多在3D图形设计软件也可以运用支持OpenGL标准的3D加速卡,大大提高其3D图形的处理速度。

2003年的7月28日,SGI和ARB公布了OpenGL 1.5。OpenGL 1.5中包括OpenGL ARB的正式扩展规格绘制语言“OpenGL Shading Language”。

2004年8月,OpenGL2.0版本发布OpenGL 2.0标准的主要制订者并非原来的SGI,而是逐渐在ARB中占据主动地位的3Dlabs。

2008年8月初Khronos工作组在Siggraph 2008大会上宣布了OpenGL 3.0图形接口规范,GLSL1.30 shader语言和其他新增功能将再次未来开放3D接口发展指明方向。

2009年3月又公布了升级版新规范OpenGL 3.1,也是这套跨平台免费API有史以来的第九次更新。

2009年8月Khronos小组发布了OpenGL 3.2,这是一年以来OpenGL进行的第三次重要升级。 Khronos旗下的OpenGL ARB(Architecture Review Board)工作组推出了GLSL 1.5OpenGLShading Language(OpenGL着色语言)的升级版,以及在OpenGL3.2框架下推出了两个新功能,可以让开发者在开发新程序时能够在使用流水线内核特性或兼容性特性之间做出选择,其中兼容性特性会提供与旧版OpenGL之间的兼容性。 2.2 OpenGL渲染管线过程

管线这个术语用于描述一种过程,它涉及两个或更多个独特的阶段或步骤。当应用程序进行OpenGL API 调用时,这些命令被放置在一个命令缓冲区中。这个缓冲区最终填满了命令、顶点数据、纹理数据等。当缓冲区被刷新时,命令和数据就被传递给管线的下一个阶段。通常,顶点数据首先进行转换和光照。在转换阶段,描述物体几何形状的点被重新计算,以确定这个物体的位置和方向。

5

同时所进行的光照计算将确定每个顶点应该具有的颜色亮度。当这个阶段完成之后,数据就被输入到管线的光栅化部分。光栅阶段根据几何图形、颜色和纹理数据实际创建彩色图像。然后,图像被放入帧缓冲区中。帧缓冲区就是图形显示设备的内存,这意味着这幅图像将会在屏幕上显示。图1显示了OpenGL工作流程图顺序,虽然并没有严格规定OpenGL必须采用这样的实现,但它却提供了一个可靠的指南方向,可以预测OpenGL将以什么样的顺序来执行这些操作。

图 1 Opengl工作渲染流程图

OpenGL渲染管线的操作过程主要包括以下几部分: 1)顶点变换 2)图元组装 3)图元处理 4)片元处理 5)光栅化操作 2.2.1顶点变换

这个阶段主要是对输入的顶点进行逐个处理,这些顶点都包括很多属性(如位置、颜色、法线和纹理坐标等),经过处理后,输出是经过变换后的顶点属性及关联信息。 主要过程:顶点变换(几何变换和投影变换)、光照计算、纹理坐标变换和生成。 2.2.2图元组装

这个阶段主要是按照输入的变换后的顶点属性和关联信息,组装形成图元。 2.2.3图元处理

这个阶段主要是对输入的图元进行处理,输出片元(帧缓存中更新象素属性的数据)信息,该片元信息是对顶点变换阶段得出的属性进行插值处理得到的。 主要过程:视景裁剪、背面剔除。 2.2.4片元处理

这个阶段的输入为经过插值计算后的最终片元信息,经过处理后,输出信息为片元的深度和颜色值。

主要过程:纹理、雾化、颜色汇总(包括纹理颜色,光照颜色,主颜色等)。 2.2.5光栅化操作

这个阶段的输入为像素位置和片元的深度、颜色值等信息,经过一系列的测试(剪切测试、Alpha测试、模板测试和深度测试)后形成像素的颜色。

主要过程:剪切测试、Alpha测试、模板测试和深度测试、写入帧缓存。 2.3 MFC概述

MFC(Microsoft Foundation Class Library)中的各种类结合起来构成了一个应用程序框架,它

6

的目的就是让程序员在此基础上来建立Windows下的应用程序,这是一种相对SDK来说更为简单的方法。因为总体上,MFC框架定义了应用程序的轮廓,并提供了用户接口的标准实现方法,程序员所要做的就是通过预定义的接口把具体应用程序特有的东西填入这个轮廓。Microsoft Visual C++提供了相应的工具来完成这个工作:AppWizard可以用来生成初步的框架文件(代码和资源等);资源编辑器用于帮助直观地设计用户接口;ClassWizard用来协助添加代码到框架文件;最后,编译,则通过类库实现了应用程序特定的逻辑。

MFC是在1992年随微软的Microsoft C/C++ 7.0编译器发布的,用于面向16位Windows的软件开发。起初,MFC是作为一个应用程序框架开发的,所以定名为Application FrameworkX (AFX)。 Borland几乎同时发布了面向Turbo C编译器的OWL,并且在一开始比MFC更具有市场占有率,但是在Borland发布了一个不向下兼容的应用程序框架之后,它丧失了很多市场份额;在Borland从微软获得发布MFC的授权之后它的市场份额进一步减少。Borland最终用Visual Component Library来作为OWL的后继者。

随着Visual Basic和Visual Studio .NET的发布,曾经一度被微软重点推荐的MFC被Visual Basic、C#、Windows Forms抢走了不少市场份额,但是MFC继续在非托管软件开发中占据重要地位。在托管开发方面,MFC中也包括对Windows Forms和托管/非托管互操作的封装。微软在Windows Vista和Windows 7发布之后在MFC中增加了对新的Windows API支持。

很多商用类库在MFC的基础上进一步实现了皮肤、渐变风格、多顶层窗口程序、属性列表等较受欢迎的功能;同时,在C++在线社区中,很大一部分开放的源代码也是基于MFC的。 VC++产品版本与MFC版本如下:

表格 1 VC++产品版本与MFC版本

2.4 MFC 特点 2.4.1封装

构成MFC框架的是MFC类库。MFC类库是C++类库。这些类或者封装了Win32应用程序编程接口,或者封装了应用程序的概念,或者封装了OLE特性,或者封装了ODBC和DAO数据访问的功能,等等,

7

分述如下:

(1)对Win32应用程序编程接口的封装; (2)对应用程序概念的封装; (3)对COM/OLE特性的封装; (4)对ODBC功能的封装。 2.4.2继承

首先,MFC抽象出众多类的共同特性,设计出一些基类作为实现其他类的基础。这些类中,最重要的类是CObject和CCmdTarget。CObject是MFC的根类,绝大多数MFC类是其派生的,包括CCmdTarget。CObject 实现了一些重要的特性,包括动态类信息、动态创建、对象序列化、对程序调试的支持,等等。所有从CObject派生的类都将具备或者可以具备CObject所拥有的特性。CCmdTarget通过封装一些属性和方法,提供了消息处理的架构。MFC中,任何可以处理消息的类都从CCmdTarget派生。

针对每种不同的对象,MFC都设计了一组类对这些对象进行封装,每一组类都有一个基类,从基类派生出众多更具体的类。这些对象包括以下种类:窗口对象,基类是CWnd;应用程序对象,基类是CwinThread;文档对象,基类是Cdocument,等等。 2.4.3虚拟函数和动态约束

MFC以“C++”为基础,自然支持虚拟函数和动态约束。但是作为一个编程框架,有一个问题必须解决:如果仅仅通过虚拟函数来支持动态约束,必然导致虚拟函数表过于臃肿,消耗内存,效率低下。例如,CWnd封装 Windows窗口对象时,每一条Windows消息对应一个成员函数,这些成员函数为派生类所继承。如果这些函数都设计成虚拟函数,由于数量太多,实现起来不现实。于是,MFC建立了消息映射机制,以一种富有效率、便于使用的手段解决消息处理函数的动态约束问题。 2.5 应用程序的构成

图2解释了该应用程序的结构与对象,箭头表示信息流向。

图 2 应用程序的结构

从CWinApp、CDocument、CView、CMDIFrameWnd、CMDIChildWnd类对应地派生出CTApp、CTDoc、CTView、CMainFrame、CChildFrame五个类,这五个类的实例分别是应用程序对象、文档对象、视对象、主框架窗口对象和文档边框窗口对象。主框架窗口包含了视窗口、工具条和状态栏。对这些

8

类或者对象解释如下:

(1)应用程序(CWinApp)

应用程序类派生于CWinApp。基于框架的应用程序必须有且只有一个应用程序对象,它负责应用程序的初始化、运行和结束。 (2)边框窗口(CMDIFrameWnd)

如果是SDI应用程序,从CFrameWnd类派生边框窗口类,边框窗口的客户子窗口(MDIClient)直接包含视窗口;如果是MDI应用程序,从CMDIFrameWnd类派生边框窗口类,边框窗口的客户子窗口(MDIClient)直接包含文档边框窗口。如果要支持工具条、状态栏,则派生的边框窗口类还要添加CToolBar和CStatusBar类型的成员变量,以及在一个OnCreate消息处理函数中初始化这两个控制窗口。

边框窗口用来管理文档边框窗口、视窗口、工具条、菜单、加速键等,协调半模式状态(如上下文的帮助(SHIFT+F1模式)和打印预览)。 (3)文档边框窗口(CMDIChildWnd)

文档边框窗口类从CMDIChildWnd类派生,MDI应用程序使用文档边框窗口来包含视窗口。 (4)文档(CDocument)

文档类从CDocument类派生,用来管理数据,数据的变化、存取都是通过文档实现的。视窗口通过文档对象来访问和更新数据。 (5)视(CView)

视类从CView或它的派生类派生。视和文档联系在一起,在文档和用户之间起中介作用,即视在屏幕上显示文档的内容,并把用户输入转换成对文档的操作。

用图的形式可直观地表示所涉及的MFC类的继承或者派生关系,如下:

图 3 MFC的层次

2.6 基于OpenGL+MFC的三维模拟的编程环境配置

用MFC调用OpenGL函数来进行三维模拟的编程环境配置: (一)创建MFC项目

(1) 创建项目文件:选择File/New 菜单选项,建立一个名为MyTest 的单文档 (SDI) 应用程序; (二)配置OpenGL开发环境

(1)将91.h,glu.h,glaux.h和glut.h拷贝到???(即盘符+路径)\Microsoft Visual Studio\VC98\Include\GL目录中; (2)将opengl32.1ib,glu32.1ib,glaux.1ib和glut32.1ib拷贝到???(即盘符+路径)\Microsoft

9

Visual Studio\Vc98\Lib目录中;

(3)将opengl32.dll,glu.dll,glu32.dll,glut.dll,glut32.dll文件拷贝到操作系统安装目录C:\WINDOWS\system32目录下;

(4)选择Project/Setting 菜单选项。在Link栏的Lib输入域中添加openg132.lib、glu32.lib,若需使用OpenGL的辅助库函数,则还需添加glaux.lib。 到此,基于OpenGL+MFC的开发环境就建立好。 (三)初始化OpenGL 具体编程步骤:

第一步:修改窗口风格设置。 需要在函数CGLView::PreCreateWindow中增加对Windows窗口风格的设置,以防止在窗口重叠时把图形绘制到子窗口和兄弟窗口。实现代码如下:cs.style l=WS_CLIPCHILDREN WS CLIPSIBLINGS; 第二步:设置像素格式。

首先需要在视图类CGLView中添加一个成员函数,函数原型如下:BOOL CGLView::SetupPixelFormat(CDC*pDC);设置像素格式并向视图类CGLView中添加两个成员变量:

CDC* m_pDC;OpenGL设备场境HGLRC m_hRC;OpenGL渲染场境在Windows中,使用结构PIXELFO腿ATDEscRIPTOR来设置像素格式,并提供ChoosePixelFormat()函数来选择最为匹配的像素格式以及SetPixelFormat()函数来为设备场境设置像素格式。 设置像素格式的步骤如下:

a.填写结构PIXELFORMATDESCRIPTOR,像素格式是用这个结构来描述的。

b.调用函数ChoosePixelFormat(),将填写好的像素格式结构传递给该函数,函数ChoosePixelFormat()返回一个整型的序号。这个序号标识一个当前设备场境中所能提供的,且与所要求的像素格式最为匹配的像素格式。

c.将这个返回的像素格式序号传递给函数SetPixelFormat(),使之设置成为当前设备场境的像素格式。

第三步:创建渲染场境。

用wglreatecontext()函数来创建OpenGL的一个渲染场境;用wglMakeCurrent()函数使给定的渲染场境设置成为当前调用线程的渲染场境,而线程中随后调用的OpenGL命令都将通过与该渲染场境相关联的设备场境来实现窗口的场景绘制。具体实现代码如下: HDC m hDC;

HGLRC nl hglRC:

m_hglRC=wglCreateContext(m_hDC);创建一个渲染场境

wglMakecurrent(m_hDC,m hglRC);使成为当前调用线程的渲染场境 第四步:添加消息处理函数。

利用MFC ClassWizard为CGLView类添加消息:帐_CREATE、wM_DESTROY、m,t_SIZE和删_TIMER的响应函数,消息处理函数名依次为:OnCreate()、onDestroy()、OnSize()和OnTimer()。 A.CGLView::OnCreate()函数

该函数完成的功能是:在视图窗口创建完成后,进行OpenGLWindows的初始化工作。 (四)清理工作 CGLView::OnDestroy()函数

该函数完成的功能是:在视图窗口被释放时,用于清除当前的渲染场境,并释放设备场境。具体实现代码如下:

wglMakeCurrent(NULL,NULL);

wglDeleteContext(m__hglRC);清除渲染场境: ReleaseDC(m_hWnd,m_hDC);释放设备场境

10

C.CGLView::OnSize()函数 D.CGLView::OnTimer()函数

该函数完成的功能是:通过定时器每隔一定时间的消息驱动,来实现动态的场景更新。

11

3 拾取技术

拾取算法的研究可大致分为两类:一类是基于三维空间的射线拾取算法,代表算法就是基于CPU的射线求交拾取技术;另一类是基于图像空间的拾取算法,例如:基于GPU的重绘式拾取技术。 3.1 基于射线求交拾取技术

其基本原理是:获取屏幕坐标并转换成图形系统的视口坐标,根据不同图形API(应用程序编程接口)的实现给该点加上适当的深度值(如OpenGL标准的深度值介于0-1),反算出该拾取点的世界空间坐标,将相机焦点坐标转换为屏幕坐标,过相机位置点向鼠标选中点作一条射线在三维空间中对射线和物体进行求交,离相机位置点最近的实体就是被选中的实体。 算法的具体实现步骤如下:

(1)初始化,获取鼠标点的屏幕坐标(x,y),并将相机焦点坐标转换为屏幕坐标;

(2)相机焦点深度值(z值)作为鼠标点的深度值(z值),并将鼠标点坐标转化为世界坐标(XW ,YW ,ZW);

(3)过相机位置点向点(XW,YW,ZW)作一射线m,并分别求射线m 和投影空间近截面和远截面的交点A,B,得到线段AB。如果射线m垂直于视线,则射线m和投影空间不相交; (4)依次取出场景实体列表中的每个实体,获取该实体的转换矩阵,并利用该矩阵将A、B点的坐标转换为局部坐标;

(5)计算实体的包围盒,并判断AB和包围盒的相对位置。如果AB和包围盒相交,则求该实体和AB交点的参数值,并将该实体标记为选中对象。如不相交,则进行下一个实体的处理。

在上述算法中,判断线段AB和实体包围盒的相对位置及线段AB和实体的求交是算法实现的关键。为了提高拾取速度,对传统的包围盒算法和求交算法进行了改进。 3.1.1判断线段和包围盒的相对位置

实体的最大包围盒是一个各表面平行于坐标平面的六面体,其左下顶点的x、y、z坐标值为实体所有顶点相应坐标值的最小值,其右上顶点的坐标值为实体所有顶点相应坐标值的最大值。

采用向量法来判断线段和包围盒相对位置,该算法的基本思想为:将线段看成一个由起点指向终点的向量,求向量各分量和离起点最近的三个包围盒侧面所在平面的交点,如果各分量与平面的交点都在包围盒侧面上或者在包围盒内且在各分量上,则该线段和包围盒相交(本文中我们把线段与包围盒相交和线段在包围盒内这两种情况统称为相交)。 判断线段与包围盒相对位置的具体步骤如下:

(1)判断起点A是否在包围盒内,如果在盒内,则线段AB和包围盒相交,判断结束;如果不在盒内,则记下该包围盒离起点A最近的三个侧面,这三个侧面必定共点且相互垂直;

(2)过起点A向各侧面做垂线,得到三个垂足,连接点A和各垂足,得到三个向量a1、a2、a3(如图4所示),并求a1、a2、a3和向量AB各相应分量的比值ti=ai/AB(i=1,2,3)。如果AB的某个分量为零,则比值取-1。取t1、t2、t3中的最大值为tmax,如果tmax<0或tmax>1,则AB和包围盒不相交,判断结束;

(3)根据tmax值求出交点坐标,判断交点是否在包围盒上。(此处最好给出交点坐标的计算式,以及交点是否在包围盒上的判断算式。)如果交点在盒上,则AB和包围盒相交,否则,AB和包围盒相离。

图 4 线段AB 和包围盒的位置关系图

12

判断线段与包围盒相对位置的算法流程如图5所示。

图 5 向量法判断线段和包围盒相对位置算法流程图

根据拾取对象的不同,线段和相关对象求交的方法和过程存在差别。设要和拾取对象求交的线段为AB,针对不同的情况,下面对两种求交过程分别加以描述。 (1)拾取对象为点

当拾取对象为点时,求交的实质就是以AB为轴线,以一个很小的浮点数tolerance(tolerance一般小于0.001)为半径做一个圆柱,在这个圆柱内离视点最近的点就是所求的交点。具体做法是将实体的每一个顶点向AB投影,并求出投影点在线段AB上的参数坐标。在0到1的范围内,参数坐标的值越小,说明该点离视点越近。如果我们发现了某个实体顶点比当前的最近点离视点更近且该点到AB所在直线的距离小于tolerance,则把该点记录为当前的最近点。当所有的点处理完毕,当前的最近点就是该实体和线段AB的交点。 (2)拾取对象为直线或复合线

13

复合线一般指由多个直线段相连接所构成的单元体,在本文所述的三维图形浏览器系统中,曲线如NURBS曲线、圆弧等都存储为复合线的形式。对于线状图元,比较常用的方法是通过计算点线距离来进行拾取,这种方法简单易懂,易于实现。但当拾取曲线、复杂折线等图元时,计算量会非常大。为此提出一种新的改进算法,其具体操作步骤如下: ①以拾取点为中心、两倍拾取精度(在本文中拾取精度一般为象素宽度的2~5倍)为边长,绘制一个以背景色为填充色的正方形作为“测试窗口”。 如图6所示

图 6 测试窗口

②重绘图形对象。如果图元进入拾取范围,则必然在“测试区”中留下轨迹,重绘图形对象的目的是为了恢复可能被“测试窗口”遮蔽的图形对象。

③循环读取“测试窗口”中象素点颜色。当发现象素点颜色有别于背景色时,终止读点,标识拾取成功。若未发现有别于背景色的象素点时,则继续进行下一个图元的检测。如图7所示

图 7 测试区中的轨迹

3.2 基于GPU的重绘式拾取技术 基本思路:

重绘式拾取法是在OpenGL绘图模式下,通过2次绘图来拾取并显示物体。第1次绘图为虚拟绘 图,通过在OpenGL帧缓存中绘制一些辅助图形来帮助选取物体。这些辅助图形对于系统使用者是不 可见的,因此在确定所选物体之后要将辅助图形从帧缓存中清除掉才能进行第2次绘图。第2次绘 图为实际绘图,所绘图形为系统使用者看到的真实图形。

在GPU上实现三维图元拾取的方法有两种,第一种方法与场景几何无关,第二种方法是场景几 何依赖。下面介绍第一种方法:

场景几何无关方法的应用一直受到限制:它需要GPU的可编程能力,需要ShaderModel2.0和浮点型纹理支持;其次是因为每次出发拾取程序的时候都要在后台绘制一张表面,等同于重复绘制了两次场景,不适合频繁连续的拾取动作。

该方法的核心是把图元的几何信息、指针等相关信息作为它的颜色渲染到后台的一张Render Target型表面上对应帧缓冲做一次特殊的“渲染”。在渲染后只要读取表面上相应像素坐标的颜色值就可以得知它相对应图元的信息。整个算法分为在CPU上和在GPU上的两部分。在CPU上C++程序的任务是建立一个后台的表面,然后调用GPU上的程序对物体进行特殊的RTT(Rallderto Texture,渲染到纹理),再根据渲染结果读取表面某坐标的颜色并还原信息。具体实现时考虑到纹理有pow of two和non—pow of two之别,屏幕分辨率一般不为pow of two,因此可以考虑采用渲染到表面(RRS),用Direct3D9中的CreateRenderTarget()创建一个Render Target型表面,CPU上的主要流程如下:

鼠标点击拾取事件触发下面流程: (1)建立一张新的临时纹理;

14

(2)将当前设备屏幕的内容存入缓冲中,将设备的渲染对象设为该临时纹理; (3)做好渲染前的准备,包括从fx文件中读入effect; (4)对于每个几何对象在GPU通过Shader进行特殊渲染; (5)还原设备信息,设备的渲染对象指向帧缓冲; (6)获取临时纹理上拾取区域的像素; (7)将获得的像素按定义的格式解码。 图8说明了上述整个流程。

图 8 GPU拾取流程

下面定义Vertex Shader的输出内容,定义了一个包括坐标和颜色的结构(struct)。其中,pos用于顶点转换,color用于顶点信息存储。 Struct VSResult {

Float4 pos:POSITION; Float4 color:TEXCOORDO };

在Vertex Shader中,输入某点的局部坐标,把坐标的值编码成一个颜色的RGB值后作为输出颜色的RGB值,同时将输入坐标向量左乘世界矩阵、观察矩阵、投影矩阵后得到最终输出的坐标值。在Pixel Shader中,将物体指针信息作为颜色的Alpha值,加上Vertex Shader输出的颜色,输出为最终的渲染颜色。

在单个几何图元中,不同顶点有不同的坐标,在Vertex Shader中,根据坐标信息进行顶点转换,同时将坐标信息作为颜色值存入VSResult中。主要如下: VSResult Vs_main{ float3 pos:POSITION } {

VSResult ret;

ret.color=float4(pos,1.of);

float4 worldpos=mul(float4(pos,1),worldmatrix);

15

ret.pos=mul(worldpos,ViewProjection); return ret; }

对于ret.color,前3个RGB值表示输入的位置坐标;而第4个Alpha值用作存储其他信息,暂时填入1.Of,后文将填充图元的指针。 3.3 各种拾取技术比较 各种拾取技术比较表如下:

表 2 各种拾取技术比较

OpenGL的选择机制 原理 先把场景画进帧缓冲,然后进入选择模式并重新绘制这个场景。当退出选择模式时,OpenGL返回一个图元(premitives)清单,图元可能被视见体(viewing volume)分割。每个被视见体图元引出一资选择命中(hit)。确切的说,图元清单是作为一个取整数值的名字(integer-valued names)数组和相关的数据-命中记录(hit record)-对应名字栈(name stack)的当前内容。当在选择模式下发布图元绘制命令时向名字栈中加入名字就可建立起名字栈。当名字清单被返回后,可以用它来确定屏幕上的哪个图元可能被用户选中了。 获取屏幕坐标并转换成图形系统的视口坐标,根据不同图形API(应用程序编程接口)的实现给该点加上适当的深度值(如OpenGL标准的深度值介于0-1),反算出该拾取点的世界空间坐标,并由视点向此点引一条射线,在三维空间中对射线和物体进行求交。 优点 此算法简单 局限性 名字堆栈容量有限,不能处理大规模场景中的拾取。 射线拾取方法 对拾取对象为点或简单的选择体较为方便,速度快。 (1)因它假设所有的图形变换矩阵必须可逆,经过一系列的逆运算可得到图像空间某点的三维坐标,但实际上这些矩阵并非总是可逆; (2)对于复杂的选择体,判断物体是否在选择体内部的算法极其复杂。从而使整个处理过程耗时巨大,且如此复杂的算法也会给整个系统的实现带来一定难度。

在OpenGL绘图模式下,通过2(1)没有采用OpenGL选择机制。整个拾取过程都在OpenGL的绘图模式下16

重绘式拾取法 次绘图来拾取并显示物体。第1次绘图为虚拟绘图,通过在OpenGL帧缓存中绘制一些辅助图形来帮助选取物体。这些辅助图形对于系统使用者是不可见的,因此在确定所选物体之后要将辅助图形从帧缓存中清除掉才能进行第2次绘图。第2次绘图为实际绘图,所绘图形为系统使用者看到的真实图形。 完成,因此不必要为每个物体命名。同时,避免了在绘图模式与选择模式之间的切换;(2)灵活的拾取范围,可以定义各种形态的框选,如圆形,方形;(3)算法简单,容易实现,且容易迁移到GPU上,利用硬件加速拾取算法。 依赖于硬件,与GPU的性能息息相关 17

4 系统的设计及实现

有些图形应用程序只绘制两维和三维物体构成的静态图形,另一些允许用户识别屏幕上的物体并移动、修改、删除或用其它方法操纵这些物体。OpenGL正是设计用于支持这些交互式应用程序的。因为绘制在屏幕上的物体通常经过多次旋转、移动和透视变换,所以确定用户选中了三维场景中的哪个物体会很困难。为了解决这个问题,OpenGL提供了一个选择机制可惟自动告诉你哪个物体被绘制在窗口的提定区域里。

本文的拾取考虑到简单地拾取三个不同的物体,分别是一个一个拾取,而不是同时拾取的过程且拾取物体是简单的选择体,这些正好都不是OpenGL的选择机制的各种缺点且OpenGL的选择机制是OpenGL本身自带的因素,所以采用了OpenGL的选择机制的拾取方法,来实现对三个不同的物体拾取。拾取过程如下:

使用OpenGL的选择机制时,首先把场景画进帧缓冲,然后进入选择模式并重新绘制这个场景。然而,一旦进入了选择模式,帧缓冲的内容将保存不变,直到退出选择模式。当退出选择时,OpenGL返回一个图元(premitives)清单,图元可能被视见体(viewing volume)分割。每个被视见体图元引出一资选择命中(hit)。确切的说,图元清单是作为一个取整数值的名字(integer-valued names)数组和相关的数据-命中记录(hit record)-对应名字栈(name stack)的当前内容。当在选择模式下发布图元绘制命令时向名字栈中加入名字就可建立起名字栈。这样,当名字清单被返回后,就可以用它来确定屏幕上的哪个图元可能被用户选中了。

除了这个选择机制之外,OpenGL提供了一个工具例程,以便在某些情况下通过限定在视口(viewport)一个小区域内绘制来简化选择。可以用这个例程决定哪个物体被画在光标附近了,这样就能识别用户拾取了哪个物体,也可以通过指定附加的裁剪面来界定一个选择区域。 4.1系统的选择机制

选择机制分以下几个部分来进行: (1)进入选择模式之前; (2)获取当前选择模式; (3)退出当前选择模式; (4)拾取。

4.1.1进入选择模式之前

用glSelectBuffer()指定用于返回命中记录的数组; 下面描述glSelectBuffer()和glRenderMode()。

void glSelectBuffer(GLsizei size,GLuint *buffer);指定用于返回选择数据的数组。

参数buffer是指向无符号整数(unsigned integer)数组的指针,数据就存在这个数组中,size参数说明数组中最多能够保存的值的个数。要在进入选择模式之前调用glSelectBuffer() 4.1.2获取当前选择模式

以GL_SELECT为参数调用glRenderMode()进入选择模式;

GLint glRenderMode(GLenum mode);控制应用程序是否进入绚染(rendering)、选择或反馈模式。mode参数可以是GL_RENDER(默认)、GL_SELECT或GL_FEEDBACK之一。应用程序将保持处于给定模式,直到再次以不同的参数调用glRenderMode()。在进入选择模式之前必须调用glSelectBuffer()指定选择数组。类似的,进入反馈模式之前要调用glFeedbackBuffer()指定反馈数组。如果当前模式是GL_SELECT或GL_FEEDBACK之一,那么glRenderMode()的返回值有意义。返回值是当前退出当前模式时,选择命中数或放在反馈数组中的值的个数。负值意味着选择或反馈数组溢出(overflowed)。用GL_RENDER_MODE调用glGetIntegerv()获取当前模式。 定义用于选择的视见体

通常它与原来用于绘制场景的视见体不同,也可以用glPushMatrix()和glPopMatrix()来保存

18

和恢复当前的变换矩阵;在选择模式下,被视见体裁剪的每个图元引起一个选择命中。当前一个名字栈控制命令被执行或glRenderMode()被调用后,OpenGL将一个命中记录写进选择数组,如果从上一次名字栈操纵或glRenderMode()调用以来有了一个命中记录的话。这个过程中,共用同样名字的物体-例如:由多个图元组成的物体-不生成多个命中记录。当然,命中记录不保证会被写进数组中直到glRenderMode()被调用。

除图元之外,glRasterPos()产生的有效坐标也可以引起选择命中。在多边形的情况下,如果它已经被消隐掉的话不会有命中记录出现。 每个命中记录由四项组成,依次是: (1)当命中出现时名字栈中的名字数;

(2)至上次记录的命中以来,被视见体裁剪后的图元的所有顶点的窗口Z坐标的最大; (3)被视见体裁剪后的图元的所有顶点的窗口Z坐标最小值; (4)本次命中时名字栈的内容,最底元素最前。

进入选择模式时,OpenGL初始化一个指针指向选择数组的起点。每写入一个命中记录,指针相应更新。如果写入一个命中记录会使数组中值的个数超过glSelectBuffer()的size参数时,OpenGL会写入尽可能多的记录并设置一个溢出标志。当用glRenderMode()退出选择模式时,这条命令返回被写入的记录的个数(包括一条部分记录如果有的话),清除名字栈,复位溢出标识,重置栈指针。如设定溢了出标识则返回值是-1。

用glInitName()和glPushName()初始化名字栈

名字栈是返回给你的选择信息的基础,要建立名字栈,首先用glInitNames()初始化它,这将简单地清空栈。然后当发布相应的绘制命令时向其中加入整数名字。栈控制命令允许你压入名字(glPushName()),弹出名字(glPopName()),替换栈顶的名字(glLoadName())。 举个例子:

Example 12-1: Creating a Name Stack glInitNames(); glPushName(-1);

glPushMatrix(); /*保存当前的转型的状态*/ glLoadName(1); drawSomeObject(); glLoadName(2);

drawAnotherObject(); glLoadName(3);

drawYetAnotherObject(); drawJustOneMoreObject();

glPopMatrix (); /*恢复以前的转型的状态*/

在这个例子中,前两个被绘制的物体有自己的名字,第三和第四个共用一个名字。这样,如果第三或第四个物体中的一个或全部引起一个选择命中,只有一个命中记录返回给你。如果处理命中记录时不想区分各个物体的话,可以让多个物体共享一个名字。 void glInitNames(void); 清空名字栈。

void glPushName(GLuint name); 将name压入名字栈

压入名字超过栈容量时将生成一个GL_STACK_OVERFLOW错误。名字栈深度因OpenGL实现(implementations)不同而不同,但最少要能容纳64个名字。可以用参数GL_NAME_STACK_DEPTH调用glGetIntegerv()以获取名字栈深度。

void glPopName(void);弹出名字栈栈顶的那一个名字

19

从空栈中弹出名字引发GL_STACK_UNDERFLOW错误。

void glLoadName(GLuint name);用name取代名字栈栈顶的那个名字。如果栈是空的,刚调用过glInitName()后就是这样,glLoadName()生成一个GL_INVALID_OPRATION错。为避免这种情况,如果栈初始时是空的,那么在调用glLoadName()之前至少调用一次glPushName()以在名字栈中放上点东西。

交替发布图元绘制命令和名字栈控制命令,这样每个感兴趣的图元都会被指定适当的名字; 4.1.3退出选择模式

退出选择模式并处理返回的选择数据(命中记录)。 4.1.4拾取

用选择模式确定物体是否被拾取了,要做到这一点,用一个与投影矩阵相关联的拾取矩阵将绘制限制在视口的一个很小的区域里,通常是在光标附近。然后允许某种形式的输入,如点击鼠标的一个键,引发选择模式的初始化。建立起选择模式并使用特定的拾取矩阵,绘制在光标附近的物体引发选择命中。即,通常在拾取的时候确定哪个物体被画在光标附近了。

拾取的建立几乎与正规的选择模式完全一样,只有以下的主要区别:拾取通常由某个输入设备触发。

在下面的例子中,按鼠标左键运行实现拾取的函数。

用例程gluPickMatrix()将一个特殊的投影矩阵乘到当前矩阵上。它要在把投影矩阵乘到栈上之前调用。

void gluPickMatrix(GLdouble x,Gldouble y,GLdouble width,GLdouble height,GLint viewport[4]);

建立一个投影矩阵用于将绘制限制在视口的一个小区域里,并将这个矩阵乘到当前矩阵栈上。拾取区域的中心是窗口坐标(x,y)处,通常是光标位置。width和height定义选取区域大小,用屏幕坐标。Viewport{}表明当前视口边界,这可以用调用glGetIntegerv(GL_VIEWPORT,GLint *viewport);获得。

gluPickMatrix()建立的矩阵的净结果(net result)是将裁剪区域变换到单位立方体-1&1e;(x,y,z)&1e;1(或-w&1e;(wx,wy,wz)&1e;w)。拾取矩阵实际上提供了一个正交变换将这个单位立方体的一个子区域映射到单位立方体。因为变换是任意的,所以可以让拾取为不同类型的领域工作-如,用于旋转窗口的矩形区域。在某些情况下,会发觉用附加的裁剪平面定义拾取区域要容易些。

20

图 9 拾取流程图

4.2 拾取结果截图

本系统中,未启用拾取状态的物体渲染如图10与图11所示,系统中使用物体空间的旋转矩阵变换各个物体,因此每个物体在其局部坐标系中旋转。

21

图 10 对象拾取前状态

图 11 对象拾取前状态

用户可通过鼠标对物体进行拾取,鼠标左键点击待拾取的物体,物体被拾取时的效果如下:

22

图 12 第一只对象被拾取效果

图 13 第二只对象被拾取效果

23

图 14 第三只对象被拾取效

24

5 结论与展望

5.1 结论

本文分析了基于CPU的射线求交拾取技术、基于GPU的重绘式拾取技术、OpenGL的选择机制技术三种拾取的实现原理和优缺点,本文考虑到只是简单地拾取三个不同的物体,分别是一个一个拾取,而不是同时拾取的过程且拾取物体是简单的选择体的原因,采用了OpenGL本身自带的选择机制拾取实现了简单的三个不同物体拾取,实验表明本文的方法是有效的。 5.2 展望

现今越来越多的3D网游游戏出炉,对电脑的配置要求也越来越高,对最基本的对象拾取也越来越严格,而拾取的关键是用什么拾取算法。前面分析了各种算法,可以得出基于GPU的重绘式拾取技术具有明显的优势,是一种不错的拾取技术。今后也将继续考虑如何可以使重绘式拾取技术脱离GPU也可以实现拾取,甚至实现更快、更简单地拾取,让程序员操作起来更快,更方便,让游戏玩家玩游戏起来更流畅,拾取各种物品或人物更快。

25

参考文献

[1]Mark Segul,Carl Korobkin,Rolf van Widenfelt等.Fast Shadows and Liighting Effects using Texture Mapping.Computer Graphics.1992,July,249-252. [2]Michael Deering,Step hanie Winner and Bic Schediwy等.The Triangle Processor and Normal Vectore Shader.Computer Graphics.1998,8,21-30.

[3]龚堰珏,颜敏. 面向对象的交互显示和拾取模型研究[J]. 系统仿真学报,2005. [4]韦宇炜.基于OpenGL技术的三维游戏引擎开发. 广东工业大学,2005.

[5]姚继权, 李晓豁.计算机图形学人机交互中三维拾取方法的研究 工程设计学报 2006.3-20 [6]Masaaki.Oka,Kyoya Tsutsui,Akio Ohba等.Real-Thne Manipulation of Texture-Mapped Surfaces.Computer Graphicsa 1997,7.

[7]刘力强,周明全. 一种平行透视下的三维拾取方法[J]. 西南大学学报,2002. [8]OpenGL Specification. http://www.open91.ore.

[9]Donald Hearn等.计算机图形学(第三版)[M]. 北京:电子工业H版社,2005. [10] Angel E.OpenGL编程基础[M]. 北京:清华大学出版社,2008. [12]3D Game Development On JSR-1 84. http://www.forum.nokia.com. [13]Eric Freeman,Head First Design Pattern[M]. O’REILLY,2005.

[14]openGL Programming Guide网络版. Addison--Wesley Publishing Company.

[15]Microsoft Visual C++6.0技术内幕,David J.Kruglinski,Scot Wingo,GeorgeShepherd著. 北京希望电子出版社1999年5月第1版. [16]Mason.Woo,Jcakie Neider,Tom Davis等著.吴斌,段海波,薛凤武译. OpenGL编程权威指南.北京:中国电力出版社,310-312. [17]Richard s.Wright,Jr.Michael Sweet著.潇湘工作室译.OpenGL超级宝典. 北京:人民邮电出版社,2001.251-257.

[18]Catmull E.A.Subdivision Algorithm for Computer Display of Curved Surfaces.PhD thesis.University of Utah.1974

[19]乔林,费广正. OpenGL程序设计. 北京:清华大学出版社,2000.

[20]白燕斌,史惠康. OpenGL三维图形编程指南. 北京:机械工业出版社,1998.

[21]彭群生,鲍虎军,金小刚. 计算机真实感图形的算法基础[M]. 北京:科学出版社,1999. [22]Dave Shreiner著. (OpenGL参考手册》. 机械工业出版社.2001.

[23]孙家广等.计算机图形学(第三版). 北京:清华大学出版社,1998,286.357. [24]F.S.Hill,JR著.<计算机图形学一一用OpenGL实现(第二二版)》.罗霄等译. 清华大学出版社.2006.

[25]潇湘工作室. OpenGL超级宝典[M]. 北京:人民邮电出版社,2001

[26]和平鸽工作室. OpenGL 高级编程与可视化系统开发[M]. 北京:中国水利水电出版社, 2003. [27]孙家广,胡事民.计算机图形学基础教程[M]. 北京:清华大学出版社,2005. [28]王汝传. 计算机图形技术原理及应用[M]. 北京:人民邮电出版社,1998.

[29]费广正,芦丽丹,陈立新. 可视化OpenGL程序设计[M]. 北京:清华大学出版社,2001. [30]孙家广,杨长贵. 计算机图形学(第三版)[M]. 北京:清华大学出版社。1998. [31]Heran D,Baker M P. 计算机图形学. 北京:清华大学出版社,1998. [32]蔡士杰,等译.Computer Graphics with OpenGL(ThirdEdition)[M]. 北京:电子工业出版社,2005.

[33]吴斌.OpenGL编程权威指南[M]. 北京:中国电力出版社,2001.

[34]彭群生,等.计算机真实感图形的算法基础[M]. 北京:北京科学出版社,2003.

26

[35]江早.OpenGL 图形编程[M]. 科学出版社,2001.

[36]乔林,费广正等.程序设计0peoGL[Ⅵ]. 清华大学出版杜,2000.

[37]曾建超,俞志和.虚拟现实的技术及其应用Ⅶ. 北京:清华大学出版社,2003. [38]圈石教英.虚拟现实基础及实用算法嗍. 北京:科学出版社,2002. [39]倪明田.计算机图形学[M]. 北京:北京大学出版社,1999. [40]李自力.虚拟现实中基于图形与图像的混合建模技术. 中国图象图形学报.2001.1.96-100. [41]Wright R S,Sweet J M. OpenGL超级宝典. 北京:人民邮电 出版社,2000. [42]乔林,费广正等.OpenGL程序设计. 北京:清华大学出版社,2000.1-121.. [43]彭群生,鲍虎军,金小刚.计算机真实感图形的算法基础. 北京:科学出版社,1999,6.227-229.

27

致谢

半年的设计时间虽然短暂,我却从中学到了很多的东西。我由衷地感谢关怀、教诲、帮助、支持和鼓励我完成设计的老师和同学。

特别感谢我的导师,半年来他在学习、科研上一直对我悉心指导,严格要求、热情鼓励,为我创造了很多锻炼提高的机会。老师洞察全局、高屋建瓴,为我的论文的顺利完成指出了很好的方向,郑老师渊博的知识、宽广无私的胸怀、夜以继日的工作态度、对事业的执著追求、诲人不倦的教师风范和对问题的敏锐观察力,都将使我毕生受益。

在此我谨向我的导师以及在毕业设计过程中给予我很大帮助的老师、同学们致以最诚挚的谢意!

28

致谢

半年的设计时间虽然短暂,我却从中学到了很多的东西。我由衷地感谢关怀、教诲、帮助、支持和鼓励我完成设计的老师和同学。

特别感谢我的导师,半年来他在学习、科研上一直对我悉心指导,严格要求、热情鼓励,为我创造了很多锻炼提高的机会。老师洞察全局、高屋建瓴,为我的论文的顺利完成指出了很好的方向,郑老师渊博的知识、宽广无私的胸怀、夜以继日的工作态度、对事业的执著追求、诲人不倦的教师风范和对问题的敏锐观察力,都将使我毕生受益。

在此我谨向我的导师以及在毕业设计过程中给予我很大帮助的老师、同学们致以最诚挚的谢意!

28

本文来源:https://www.bwwdw.com/article/50up.html

Top