趙 月,王建華
(江蘇科技大學 電子信息學院,江蘇 鎮江 212003)
虛擬漫游是在真實場景或虛擬場景中,借助必要的裝備以自然的方式在該場景中進行漫游,從任意角度對環境中虛擬對象進行觀察,從而產生身臨其境的感覺,同時也可以對其中的物體進行規劃和操作。
文中是為了實現在實時仿真系統虛擬環境中的漫游,建立視景驅動框架實現實時驅動虛擬場景的變化。Vega Prime(VP)提供多種開發模式[1],一是使用 VP的 Lynx Prime圖形界面,適合簡單交互性不高的小系統;二是運用VP的API函數進行的開發,通過C++編程,調用VP的API函數實現對視景的驅動,可以開發較復雜的系統;三是結合前兩種模式進行的全面開發,首先通過Lynx Prime用戶界面建立acf文件,再將VP的API函數與已經配置完成的acf文件進行結合。文中采用第3種模式,可以大幅減少源代碼開發時間,降低對開發人員要求,這是也最常用的開發模式。
鑒于MFC的開發框架有著友好的交互界面和消息驅動機制,本文詳細介紹了在MFC框架下開發基于Vega Prime視景驅動程序的方法。
實現虛擬場景的漫游,首先需要解決的是三維視景實時驅動,在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工作線程主要代碼:

MFC類庫編程環境下調用VP基本采用如下的方法:
首先單獨創建一工作線程運行VP整個程序流程,包括初始化、定義、配置、仿真循環。然后在MFC框架視圖類中添加成員函數負責開啟線程。再利用API函數AfxBeginThread()開啟VP線程[5],并將該視圖類的指針傳到VP線程中,作為線程函數的輸入參數,這樣使得文檔類和視圖類的公有成員變量在VP線程中可以被方便的讀寫,編程的靈活性得到了提高。
但這樣的方案卻存在著問題,因為視圖類(CView)的指針被傳送到主線程之外其它線程中去,使得不同線程在運行時可以訪問到相同的CView類實例,而MFC類庫本身設計并沒有考慮到多線程的訪問,所以在線程間傳遞視圖類(CView)是不安全的。
在實際開發應用中,在不退出當前應用程序前提下進行更新視圖會出現錯誤。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線程也不能實現場景切換。
首先分別創建兩個進程,VP進程和MFC主進程。就是將同一個應用程序中的不同部分進行相互黑箱化[7],彼此之間僅通過定義好的接口進行訪問,這就最大限度地減小各部分之間的相互影響。
然后在此基礎上對Vega Prime場景中對實例的驅動,包括初始化、定義、配置、仿真循環和退出等操作封裝成一個類,對特效模塊如碰撞等效果封裝成一個類,各類功能互不干擾,程序互相訪問調用。
最后解決VP進程和MFC主進程之間快速有效地進行通信問題。
因為在VP進程和MFC主進程間除了要傳遞大量的視景驅動數據外,還要進行一些控制信息的傳遞,鑒于實現的快捷性、進程通信速度上的性能要求以及便與功能的擴展等方面的綜合考慮,采用內存映射文件的方式。
本文通過共享內存實現進程間的數據交換,利用windows消息機制實現進程間的同步,兩種機制結合使用,不僅解決了交換數據量小的問題,還解決了進程并發存取數據的問題。
從使用者的角度看,數據共享方法是通過讓兩個或多個進程映射同一文件映射對象的視圖來實現的,這意味著他們將共享磁盤上同一文件或者物理存儲器的同一頁面。因此,當一個進程將數據寫入一個共享文件映射對象的視圖時,其它進程可以立即看到它們視圖中的數據變更情況。通過上述操作,用戶操作文件就能夠達到操作內存一樣的效率,多個進程操作該映射文件實現進程間內存一級的高速數據交互。部分實現如下:
//創建文件內核對象,其句柄保存于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);
根據上文提出的方法,對于多進程仿真系統中實現多場景的驅動框圖如圖2所示,其中圖中省略了VP進程部分對實例驅動和特效模塊用不同的類進行封裝的結構圖。圖2中顯示了兩個進程間實現的流程圖。進程間采用內存文件映射和消息機制進行數據通信,MFC主進程負責創建終止VP仿真進程。

圖2 MFC與VP進程間通信流程圖Fig.2 Communication flow chart between MFCand VPprocesses
文中介紹了虛擬場景中漫游驅動的實現,在基于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.