基于MFC的Vega Prime场景漫游驱动框架的设计
2013-01-18王建华
赵 月,王建华
(江苏科技大学 电子信息学院,江苏 镇江 212003)
虚拟漫游是在真实场景或虚拟场景中,借助必要的装备以自然的方式在该场景中进行漫游,从任意角度对环境中虚拟对象进行观察,从而产生身临其境的感觉,同时也可以对其中的物体进行规划和操作。
文中是为了实现在实时仿真系统虚拟环境中的漫游,建立视景驱动框架实现实时驱动虚拟场景的变化。Vega Prime(VP)提供多种开发模式[1],一是使用 VP的 Lynx Prime图形界面,适合简单交互性不高的小系统;二是运用VP的API函数进行的开发,通过C++编程,调用VP的API函数实现对视景的驱动,可以开发较复杂的系统;三是结合前两种模式进行的全面开发,首先通过Lynx Prime用户界面建立acf文件,再将VP的API函数与已经配置完成的acf文件进行结合。文中采用第3种模式,可以大幅减少源代码开发时间,降低对开发人员要求,这是也最常用的开发模式。
鉴于MFC的开发框架有着友好的交互界面和消息驱动机制,本文详细介绍了在MFC框架下开发基于Vega Prime视景驱动程序的方法。
1 建立基于MFC的VP视景驱动程序
实现虚拟场景的漫游,首先需要解决的是三维视景实时驱动,在Windows平台上进行VP开发,采用VC++编程。MFC基于文档/视图结构的应用程序框架结构是开发Windows应用程序的主要框架结构。文档对象用于保存应用程序的数据,视图对象用于数据的显示和用户的交互[2]。两种结构联系又独立,分工明确,简化了开发过程
MFC提供多线程应用程序编程[3],包括用户界面线程UI(User Interface)和工作者线程,两种线程区别于UI线程有消息循环功能,工作者线程没有。UI线程既是MFC的主线程,进行创建窗口并处理发送到该窗口的消息,作为主要仿真界面,负责开启VP线程、终止VP线程等,控制VP仿真过程。相对UI线程外的其它线程是工作者线程。在MFC下实现VP程序,即创建一工作者线程,在线程主函数里调用VP初始化函数和执行主循环。系统框架如图1所示。
图1 系统框架Fig.1 System framework
基于MFC的VP窗口显示包含了MFC和VP窗口。MFC窗口应作为VP窗口的父窗口,配置过程中将要利用VP中vr Window 类提供的 setParent(Window win)函数[4],将 MFC 的视图类CView窗口句柄m_hWnd传递到vpWindow窗口即可。
假设基于MFC的VP项目名称为MFCVP。
VP工作线程控制函数主要代码如下:
启动VP工作线程主要代码:
中止VP工作线程,在UI线程结束之前,应先结束VP工作线程。因为VP是基于多线程的,若直接退出主线程会引发异常。
//中止VP工作线程主要代码:
2 MFC框架下VP的问题分析及解决
MFC类库编程环境下调用VP基本采用如下的方法:
首先单独创建一工作线程运行VP整个程序流程,包括初始化、定义、配置、仿真循环。然后在MFC框架视图类中添加成员函数负责开启线程。再利用API函数AfxBeginThread()开启VP线程[5],并将该视图类的指针传到VP线程中,作为线程函数的输入参数,这样使得文档类和视图类的公有成员变量在VP线程中可以被方便的读写,编程的灵活性得到了提高。
但这样的方案却存在着问题,因为视图类(CView)的指针被传送到主线程之外其它线程中去,使得不同线程在运行时可以访问到相同的CView类实例,而MFC类库本身设计并没有考虑到多线程的访问,所以在线程间传递视图类(CView)是不安全的。
2.1 在VP线程中更新视图时访问保护异常错误的研究
在实际开发应用中,在不退出当前应用程序前提下进行更新视图会出现错误。VP线程在没有退出的情况下进行重新配置将导致失败,那么终止正在运行的线程,然后再重新开启一新的线程,在初始化VP阶段时,VP也会出现地址访问保护错误。
下面分析错误产生的原因[6],基于MFC的VP应用程序在配置中要利用VP中vrWindow类提供的void setParent(Window win)函数,将MFC的Windows窗口句柄m_hWnd传递给VP作为其父窗口。由此可以判断出,基于MFC的VP应用程序实质上是将VP渲染放入到MFC的View窗口中进行的。
VP由于是基于多线程的,所以在初始化过程中会自动开启一个VP窗口子线程。该子线程会根据传送的窗口句柄去创建一个与该句柄对应的窗口有相同大小的窗口,附在该窗口上。在用户终止VP线程时,该窗口线程不会自动中止,而且也没给用户提供终止函数。再次启动VP线程,进行初始化时,不会启动新的VP窗口线程,任保留原来没有被终止的窗口线程。这样就会导致再次启动VP线程时会出现地址保护错误。因此,终止VP线程也不能实现场景切换。
2.2 基于进程的场景切换方法
首先分别创建两个进程,VP进程和MFC主进程。就是将同一个应用程序中的不同部分进行相互黑箱化[7],彼此之间仅通过定义好的接口进行访问,这就最大限度地减小各部分之间的相互影响。
然后在此基础上对Vega Prime场景中对实例的驱动,包括初始化、定义、配置、仿真循环和退出等操作封装成一个类,对特效模块如碰撞等效果封装成一个类,各类功能互不干扰,程序互相访问调用。
最后解决VP进程和MFC主进程之间快速有效地进行通信问题。
因为在VP进程和MFC主进程间除了要传递大量的视景驱动数据外,还要进行一些控制信息的传递,鉴于实现的快捷性、进程通信速度上的性能要求以及便与功能的扩展等方面的综合考虑,采用内存映射文件的方式。
本文通过共享内存实现进程间的数据交换,利用windows消息机制实现进程间的同步,两种机制结合使用,不仅解决了交换数据量小的问题,还解决了进程并发存取数据的问题。
3 同机进程间内存映射的实现
从使用者的角度看,数据共享方法是通过让两个或多个进程映射同一文件映射对象的视图来实现的,这意味着他们将共享磁盘上同一文件或者物理存储器的同一页面。因此,当一个进程将数据写入一个共享文件映射对象的视图时,其它进程可以立即看到它们视图中的数据变更情况。通过上述操作,用户操作文件就能够达到操作内存一样的效率,多个进程操作该映射文件实现进程间内存一级的高速数据交互。部分实现如下:
//创建文件内核对象,其句柄保存于m_hFileSave
HANDLE m_hFileSave=CreateFile(m_FileName(保存文件 ), GENERIC_READ |GENERIC_WRITE, 0, NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL)
//以实际数据长度创建另外一个文件映射内核对象
m_hMapSave=CreateFileMapping (m_hFileSave, NULL,PAGE_READWRITE, 0, ((DWORD) qwFileOffset&0xffffffff)*sizeof(DWORD)); NULL);
//关闭文件内核对象
CloseHandle (m_hFileSave);
//将文件数据映射到进程的地址空间
IMapAddressSave = (PDWORD) MapViewOfFile(m_hMapSave, FILE_MAP_ALL_ACCESS, 0, 0,qwFileOffset*sizeof(DWO
RD));
//将数据从原来的内存映射文件复制到此内存映射文件
Memcpy (lpbMapAddressSave, lpbMapAddress,qwFileOffset*sizeof(DWORD));
//从进程的地址空间撤销文件数据映象
UnmapViewOfFile (lpbMapAddress); UnmapViewOfFile(lpbMapAddressSave);
//关闭文件映射对象 CloseHandle(m_hMap);
CloseHandle (m_hMapSave);
//删除临时文件
DeleteFile (m_FileName);
4 多场景仿真系统进程的实现
根据上文提出的方法,对于多进程仿真系统中实现多场景的驱动框图如图2所示,其中图中省略了VP进程部分对实例驱动和特效模块用不同的类进行封装的结构图。图2中显示了两个进程间实现的流程图。进程间采用内存文件映射和消息机制进行数据通信,MFC主进程负责创建终止VP仿真进程。
图2 MFC与VP进程间通信流程图Fig.2 Communication flow chart between MFCand VPprocesses
5 结 论
文中介绍了虚拟场景中漫游驱动的实现,在基于MFC的Vega Prime框架的设计,具体分析了多场景切换中遇到的问题,从面向对象的角度,提出了较为全面和稳定的解决方法。此方法可以满足多场景的数据共享和快速通信,具有广泛的通用性和实用性。
[1]张波,丁莹.基于Vega Prime的视景仿真系统的研究[C]//第六届全国仿真器学术会议,2007:261-265.
[2]车忠志,孙雪雁.MFC应用程序基本框架分析[J].农业网络信息,2010,29(9):154-147.CHE Zhong-zhi,SUN Xue-yan.The analysis of MFC application framework[J].Agriculture Network Information,2010,29(9):154-147.
[3]王娇艳,康凤举.MFC框架下多通道视景仿真技术[J].火力与指挥控制,2010,35(7):130-132.WANG Jiao-yan,KANG Feng-ju.Research on multi-channel based on Vega Prime under MFC framework[J].Fire Control&Command Control,2010,35(7):130-132.
[4]刘淑霞,范雄飞,孟艳.基于MFC的Vega Prime程序框架研究 [C]//系统仿真技术及其应用学术会议论文集,2009:418-421.
[5]胡梓楠,于劲松.基于MFC框架的Vega Prime软件集成技术的研究[J].系统仿真学报,2007,21(14):4291-4295.HU Zi-nan,YU Jin-song.The research on the framework of vegaprime software integration technology based on MFC[J].Journal Of System Simulation,2007,21(14):4291-4295.
[6]孙科峰,李洁.基于Vega Prime的多场景仿真系统框架[J].计算机仿真,2007,24(12):193-196.SUN Ke-feng,LI Jie.Vrious scense renging system frame based on Vega prime[J].Computer simulation,2007,24(12):193-196.
[7]李军,王邵棣,常建刚,等.基于Vega的视景驱动软件的分析与设计[J].系统仿真学报,2003,15(3):397-401.LI Jun,WANG Shao-di,CHANG Jian-gang,et al.Aalysis and design of renging software based on Vega[J].Journal of System Smulation,2003,15(3):397-401.