三维场景虚拟漫游系统的设计与实现
2012-09-18杨刚
杨 刚
(陕西理工学院数学与计算机科学学院,陕西汉中 723000)
目前,基于Windows系统的虚拟现实系统的实现主要采用2种技术:DirectX和 OpenGL。OpenGL是一个三维的计算机图形和模型库,利用它可以实现专业级的仿真。同时相对DirectX而言,OpenGL的建模过程更简单、更灵活。在效果处理方面,OpenGL具有alpha处理能力,生成的图形真实感强。本研究选用了OpenGL进行系统开发。
1 系统的开发框架
OpenGL程序开发框架比较众多,本研究选择Win32 Application。选择Win32而不使用MFC来开发应用程序,是因为MFC主要是用于基于窗口和文档的应用软件的编程,它集成了大量的数据和方法,将许多烦琐的任务如应用程序初始化文档处理和磁盘I/O封装起来,虽然这样给使用者的编程带来了巨大方便,但在编制基于图形显示和多媒体的应用程序时会给编程人员带来极大的麻烦[1]。
Win32 Application程序的入口函数是WinMain,此函数的原形是 int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)。此函数用来调用窗口创建例程、处理窗口消息,并监视人机交互。系统中其他函数见表1。
表1 程序中的函数
2 建立三维场景
2.1 场景文件的创建
OpenGL中场景的创建一般有3种方法:第1种方法是在3DS MAX或其他三维建模软件中绘制好场景,然后将之读入到OpenGL程序中[2];第2种方法是在OpenGL中建模,创建场景,这种方法比较繁琐;第3种方法是读入外部数据文件。本研究采用第3种方法读入数据文件,这样程序比较灵活,还可以根据需要加载不同的场景。数据文件采用文本格式,这样效率较高。
系统中创建了一个场景文件 house.txt,文件部分内容见表2。其中场景文件中每行的数据结构为(x,y,z,u,v),(x,y,z)代表该顶点的坐标,(u,v)代表该顶点对应的纹理坐标。此文件定义的场景剖面图如图1所示。house.txt文件中数据的坐标系如图1所示,其中y轴的正向垂直xoz平面向上。
图1 场景示意图
2.2 场景数据的组织
三维场景中的数据信息比较丰富,而且数据量随着场景复杂程度的增加而增加,因此在系统中必须将数据进行归类以便于处理。系统中定义了一系列结构体用来组织场景中的大量数据。主要思想是把三维世界看做许多区段(区段可以是1个物体或房子等等)的集合。1个区段中包含许多三角形,1个三角形是由3个顶点组成,每个顶点含有x、y、z坐标分量和此点对应的纹理坐标u、v。这样程序中就需要定义以下结构:
typedef struct tagVERTEX{float x,y,z;float u,v;}VERTEX;//定义顶点结构
typedef struct tagTRIANGLE{VERTEX vertex[3];}TRIANGLE; //定义三角形结构
typedef struct tagSECTOR{int numtriangles;TRIANGLE*triangle;}SECTOR;//定义区段结构
2.3 场景数据的读入
函数SetupHouse()用来从文件中取得数据资料。此函数在运行时需要调用函数readstr(),从数据文件中读入一个有意义的行数据,然后再把这些数据依次赋给区段的某个三角形的某个顶点的相应变量,通过这种方式将数据文件中的数据存储在内存中。
表2 场景文件的部分内容
2.4 加载位图文件并转化为纹理
系统中采用位图进行纹理映射[3]。LoadBMP()函数用来加载位图文件(文件后缀扩展名为bmp)。如果文件不存在,返回NULL值告知程序无法加载位图。函数LoadGLTextures()调用LoadBMP()函数先加载位图文件,然后将之创建为纹理。系统中创建3种纹理:Nearest Filtered Texture、Linear Filtered Texture 和 MipMapped Texture,这样在程序运行时可以通过键盘选择不同的纹理样式。创建Nearest Filtered Texture的代码如下:
2.5 深度缓存
在屏幕显示三维场景的OpenGL程序中都要使用深度缓存。可以将深度缓存设想为屏幕后面的层,深度缓存不断地对进入屏幕内部的深度进行跟踪,以便对场景进行排序,决定哪个物体先绘制,哪个物体后绘制,这样才能正确地显示场景。这部分程序设计在函数InitGL()中,具体代码如下:
3 虚拟场景的漫游
3.1 不同方向漫游的设计
在OpenGL中默认的镜头位置在原点(0,0,0)。本系统中漫游的功能是通过变换场景而产生移动或转动镜头的错觉实现的。具体是围绕原点以与镜头相反的旋转方向来旋转场景,从而让人产生镜头旋转的错觉,同时以与镜头平移相反的方向来平移场景。
系统中镜头(或叫相机、视点)的移动是通过键盘上的几个方向键控制的[4]:按“←”键可以使视点向左转动;按“→”键可以使视点向右转动;按“↑”键可以使视点向前移动;按“↓”键可以使视点向后移动;按“PgUp”键可以使视点向上偏移;按“PgDn”键可以使视点向下偏移。
由于键盘上每个键值都可以用0~255的1个数来代表,程序中定义了一个监控键盘动作的全局数组:bool keys[256]。当程序运行过程中有键盘被按下或释放时就捕捉这部分消息并标记数组中对应相应键的组成员,这部分代码添加在窗口消息处理函数LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)中。此函数中uMsg表示消息,wParam、lParam表示附加的消息内容。如果有键被按下,通过读取wParam的信息可以找出键值,将键盘数组keys[]相应的数组组成员的值设为TRUE,这样就可以通过查找key[]来得知什么键被按下。如果有键被释放则将键盘数组keys[]相应的数组组成员的值设为FALSE。
捕捉到相应键盘消息后,将改变视点的代码添加在函数WinMain()中。如按“↑”键可以使视点向前移动的代码如下:
3.2 漫游的实现
程序运行后,系统提示用户选择窗口和全屏2种模式。全屏显示下,漫游效果更为逼真、沉浸性更好。用户可以用键盘中4个方向键进行前进、后退、左转和右转进行漫游,用“PgUp”、“PgDn”两个键进行仰视和俯视的操作,还可以按下“F”键观察同一位图的3种不同纹理样式生成不同场景的效果(按3次分别对应3种变化)。
4 碰撞检测的处理
如果不考虑碰撞检测问题,在漫游过程中观察者有时可能穿墙而过,故应在系统中对这种情况进行正确的处理。本系统处理方法[5]:记录第1次动作的视点位置,当视点位置变换到一个新位置时,判断是否有墙面穿越新旧视点的连线,如果有,则这个视点位置变动不能进行,仍留在原位置,否则视点可以移动到新的位置。如以按“↑”键由室内向外穿过A1墙壁(见图1所示,此墙在地面的投影为一线段,其左端点的坐标为(-2,0,-2)、右端点的坐标为(-0.5,0,-2))为例,需要在WinMain()函数中的检测“↑”键被按下的代码中添加新的内容:
运行表明以上代码起到较好的作用,漫游时不会使视点穿过A1墙体。
5 结束语
运用图形程序库和Visual C++6.0开发了一个三维场景漫游系统。系统实现中采用了光照、纹理映射、视点变换、碰撞检测、全屏显示等技术,增强了虚拟场景的真实感和沉浸式交互性。
[1]樊雅萍,黄生学,温佩芝,等.基于OpenGL的机器人虚拟漫游系统开发[J].系统仿真学报,2005,17(10):119-121.
[2]和平鸽工作室.OpenGL高级编程与可视化系统开发——高级编程篇[M].2版.北京:中国水利水电出版社,2006.
[3]刘兴龙,王斌,张赭,等.农业中三维地形可视化及其漫游技术的研究[J].农机化研究,2008(9):179-181.
[4]郭蓬松,殷宏,晏峰,等.基于OpenGL的飞机虚拟场景漫游系统的实现[J].计算机工程与设计,2005.26(7):1938-1941.
[5]李熳,张曙光,刘英.电力系统中基于多边形与图像绘制相结合的实时漫游[J].计算机工程与应用,2003(11):222-224.