VRPN 介紹及使用
VRPN 簡介
Virtual-Reality Peripheral Network ( VRPN )由一系列的類庫組成,它也提供一系列的服務在虛擬現實系統中實現應用程序與外圍物理設備( tracker 等)之間的網絡透明接口。
VRPN 提供:
- 通過易用和可擴展的接口訪問各種 VR 外圍設備。
- 設備的網絡透明接口。
- 來往設備之間的消息的時間標記。
- 處於不同機器中的客戶端與服務器進行時鐘同步。
- 同一時間可與設備建立多個鏈接。
- 與失效遠程服務器重新自動建立鏈接。
- 對交互會話進行存儲和重放。
V RPN 的目標不是提供一套全面的 VR API , VRPN 專注於爲儘量多的設備提供統一的接口,實現網絡透明訪問設備的低延遲和可靠性。
設備類型和分層
不難想象 VRPN 不是爲一套設備提供驅動程序,而是爲一套功能提供接口。特定的設備屬於一個或多個標準設備類型。每種設備類型指定一致的接口和語法通過設備實現這些功能。常用的設備列在下面。有新的設備類型提供就可以建立新的類型。
-
- Tracker 記錄姿勢(位置和方向)姿勢的速度和,或者加速度。
- Button 記錄按鈕的按下與釋放事件。
- Analog 記錄一個或多個模擬值。
- Dial 記錄增值旋轉。
- ForceDevice 指定三維空間中的表面和受力範圍。
映射一系列設備到一個標準設備,需要映射每個設備的不同功能到同一個接口。是提供一個簡單的接口還是提供一個功能齊全的接口是個兩難的決定。 VRPN 通過以下解決:
- 以功能區分設備。
- 映射設備到 VRPN 中的連接。
- 允許設備輸出多種接口。
- 捨棄那些不被支持的消息類型。
- 應用程序層可以取得所有的消息。
實例解析:一個特定的設備可能實現不止一種的功能。一個該設備的 VRPN 驅動程序輸出多種設備類型的接口。 SensAble™ Technologies Phantom™ haptic display 的服務器在相同的設備下輸出 Tracker, Button, 和 ForceDevice 三個接口 . 客戶端處理 Phantom™ ,好像是三個設備各自提供各自的功能。雖然在 Phantom™ 系統中 Tracker, Button 和 ForceDevice 設備在邏輯上時分開的,但是爲了更有效的通信,在內部它們是一起被映射到相同的網絡連接。
功能分解讓應用程序在不同的輸入 ¥ 輸出設備移動變得容易。客戶端程序不用變就可實現在不同 VR 設備之間的移動。
VRPN 的編譯測試
以 Windows 系統 VS2005 爲例,其他參見 http://www.cs.unc.edu/Research/vrpn/index.html
- 從 ftp://ftp.cs.unc.edu/pub/packages/GRIP/vrpn 下載最新的 VRPN 版本解壓縮,得到兩個文件 quat /, vrpn/ (網站說還有 vrpn_html/ ,我沒見到 ~~ )。 vrpn/ 包含庫源碼和一些應用程序源碼, quat/ 是一個實現的四元素的類。
- 在編譯之前,你必須首先查看下 vrpn_Configuration.h 文件 ,看是否需要更改其中的默認選項以符合你的需要。 例如 DirectInput 是不被配置的因爲它需要 DirectX 的支持。
- VS2005 下,打開 vrpn.sln , 打開文件視圖 ,可以看見很多工程文件。( client_and_server 是一個客戶端和服務器端用一個程序實現的例子, vrpn_print_de vices 是一個很好的客戶端測試程序, vrpn_server 是一個通用的服務端程序 )
- 生成 quat, vrpn, vrpn_server, printvals and test_vrpn 工程(可通過生成 test_vrpn ,其他也就相應的自動生成)右擊 test_vrpn 點擊 ‘ 生成 ’ 。 vrpn.lib 生成於 pc_win32/Debug 目錄下,可執行程序在 pc_win32/client_src/[SERVER_NAME]/Debug 和 pc_win32/server_src/[SERVER_NAME]/Debug 目錄下。 vrpndll.lib 和 vrpndll.dll 生成於 pc_win32/DLL/Debug 目錄下;
- 運行測試程序:運行 vrpn_server.exe ,需要一個配置文件,配置文件的設置見 VRPN 網頁。運行 vrpn_print_devices.exe ,控制檯應用程序,輸入命令行 'vrpn_print_devices device@ hostname ' (設備名和運行 vrpn_server 的機器名)。
實例: DTrack 跟蹤設備
- DTrack 與 DTrack controller 建立連接,並通過 DTrack 進行空間和物體座標校準。
- 運行 vrpn_server (設好配置文件),運行 vrpn_print_devices.exe ( ‘ vrpn_print_devices DTrack@localhost -trackerstride 100 ‘ )。
- 移動被跟蹤物體, vrpn_print_devices 打印數據。
編寫自己客戶端程序
- 類似 vrpn_print_devices ,只是簡單的打印位置數據。
#include <stdlib.h>
#include <stdio.h>
#include <vrpn_tracker.h>
//回調函數, vrpn_tracker 下有很多的回調函數,可以實現對各種數據的處理,//這裏只是 以 得到位置和方向信息的 回調函數爲例。
void VRPN_CALLBACK handle_tracker(void *userdata, const vrpn_TRACKERCB t)
{
printf("handle_tracker/tSensor %d is now at (%g,%g,%g)/n",
t.sensor,
t.pos[0], t.pos[1], t.pos[2]);
}
int main(int argc, char *argv[])
{
vrpn_Tracker_Remote *tkr;
// 打開跟蹤器
tkr = new vrpn_Tracker_Remote(" DTrack @ localhost ");
// 設置回調函數
tkr->register_change_handler(NULL, handle_tracker);
// 主循環
while ( ! done ) {
//得到更新數據並調用相應回調函數
tkr->mainloop();
}
}
- OSG , DTrack 小程序
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/Geometry>
#include <osg/Geode>
#include <osgUtil/Optimizer>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgSim/OverlayNode>
#include <osgViewer/Viewer>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <vrpn_tracker.h>
int i = 0;
osg::Quat rota;
osg::Vec3 pv;
void VRPN_CALLBACK handle_tracker(void *userdata, const vrpn_TRACKERCB t)
{
rota.x() = t.quat[0];
rota.y() = t.quat[1];
rota.z() = t.quat[2];
rota.w() = t.quat[3];
pv.x() = t.pos[0] * 20;
pv.y() = t.pos[1] * 20;
pv.z() = t.pos[2] * 20;
}
int main(int argc, char *argv[])
{
vrpn_Tracker_Remote *tkr;
tkr = new vrpn_Tracker_Remote("DTrack@localhost");
tkr->register_change_handler(NULL, handle_tracker);
osg::ArgumentParser arguments(&argc,argv);
// initialize the viewer.
osgViewer::Viewer viewer;
// load the nodes from the commandline arguments.
osg::Node* model = osgDB::readNodeFile("cessna.osg");
if (!model)
{
return 1;
}
// tilt the scene so the default eye position is looking down on the model.
osg::MatrixTransform* rootnode = new osg::MatrixTransform;
rootnode->setMatrix(osg::Matrix::rotate(osg::inDegrees( 30.0f ), 1.0f , 0.0f , 0.0f ));
rootnode->addChild(model);
// run optimization over the scene graph
osgUtil::Optimizer optimzer;
optimzer.optimize(rootnode);
// set the scene to render
viewer.setSceneData(rootnode);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
viewer.realize();
osg::Quat r;
while (!viewer.done())
{
tkr->mainloop();
rootnode->setMatrix(osg::Matrix::rotate(rota) * osg::Matrix::translate(pv));
viewer.frame();
}
return 0;
}
運行結果:通過跟蹤物體改變,改變應用程序中飛機的位置和旋轉變化