OSVR-Vive
来源:互联网 发布:淘宝退货怎么寄件 编辑:程序博客网 时间:2024/05/17 08:18
1.openvr_driver.h中接口:
@brief:表示一个追踪设备。在驱动动态库中实现,如vive的driver_lighthouse.dll,运行时被vrserver加载,可用ITrackedDeviceServerProvider对象的Cleanup方法卸载。
vr::IVRServerDriverHost:
@brief:向server发送各类事件通知(Pose或Button按键信息等),提供以下函数功能:
1>.TrackedDeviceAdded:通知server一个追踪设备已经被添加。若返回true,则server将调用该设备的Active函数,若返回false,则该设备不会被active
2>.TrackedDevicePoseUpdated:往server发送pose信息
3>.TrackedDeviceAxisUpdated:往server发送x,y坐标轴信息(Joystick触摸板)
4>.GetRawTrackedDevicePoses:v1.0.7版本添加的函数,为驱动提供设备裸Pose信息
vr::IServerTrackedDeviceProvider:
@brief:用于查询发送追踪设备信息并往server发送,可理解为一个client与server的中间桥梁作用,在驱动dll动态库中实现,运行时被vrserver加载调用。提供以下函数:
1>.HmdError Init( IDriverLog *pDriverLog, vr::IServerDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir ):
@brief:初始化驱动,该函数最先被调用(在任何函数之前)。当且仅当返回HmdError_None时,dll驱动才会被调用。
@pchUserDriverConfigDir:驱动用户配置文件的绝对路径,如:Steam\config
@pchDriverInstallDir:驱动根目录绝对路径,如:Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64
@note:在V1.0.6之后,若provider含有HMD,则需在Init返回前,调用TrackedDeviceAdded添加HMD的详细信息。其他设备则可在任何时候调用TrackedDeviceAdded添加。
后续版本被virtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0所取代。
其中IVRDriverContext在后面分析。
2>.virtual void Cleanup():
@brief: 卸载vr::ITrackedDeviceServerDriver声明的驱动。
3>.virtual const char * const *GetInterfaceVersions() = 0:
@brief:返回驱动使用的vr::ITrackedDeviceServerDriver接口的版本号
4>.virtual void RunFrame() = 0:
@brief:在server的main循环中被调用,通过vr::ITrackedDeviceServerDriver提供的数据接口循环往server发送pose或button或axis等信息
5>.uint32_t GetTrackedDeviceCount():
@brief:返回驱动连接追踪设备的数量。在启动时,可用来初始化驱动的追踪设备链表。
vr::IVRDriverContext:
@brief:获取驱动所需使用到的接口以及获取驱动handle
1>.virtual void *GetGenericInterface( const char *pchInterfaceVersion, EVRInitError *peError = nullptr ) = 0:
@berief:通过版本号获取接口,以供后续使用。如:
m_pVRServerDriverHost = (IVRServerDriverHost *)VRDriverContext()->GetGenericInterface( IVRServerDriverHost_Version, &eError ); static const char *IVRServerDriverHost_Version = "IVRServerDriverHost_004";@note:在新版本vr::IServerTrackedDeviceProvider的Init使用到。
比如:
EVRInitError CServerDriver_Sample::Init( vr::IVRDriverContext *pDriverContext ) { VR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext ); InitDriverLog( vr::VRDriverLog() ); m_pNullHmdLatest = new CSampleDeviceDriver(); vr::VRServerDriverHost()->TrackedDeviceAdded( m_pNullHmdLatest->GetSerialNumber().c_str(), vr::TrackedDeviceClass_HMD, m_pNullHmdLatest ); return VRInitError_None; }在VR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext )初始化m_pVRServerDriverHost,m_pVRSettings,
m_propertyHelpers,m_pVRDriverLog,m_pVRDriverManager,m_pVRResources接口,以供后续调用它们的方法。
2>.virtual DriverHandle_t GetDriverHandle() = 0:
@brief:返回该驱动属性容器的句柄
vr::IVRSettings:
@brief:提供接口用来获取类似Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings文件下的属性字段
vr::IVRDriverLog:
@virtual void Log( const char *pchLogMessage ) = 0:
将log输出到log文件,并在log文件名前加驱动名前缀。
vr::IVRProperties:
@brief:对设备的属性进行读写,设备属性有追踪设备系统名,产品型号,产品序列号等。
enum ETrackedDeviceProperty { Prop_Invalid = 0, // general properties that apply to all device classes Prop_TrackingSystemName_String = 1000, Prop_ModelNumber_String = 1001, Prop_SerialNumber_String = 1002, Prop_RenderModelName_String = 1003, Prop_WillDriftInYaw_Bool = 1004, Prop_ManufacturerName_String = 1005, Prop_TrackingFirmwareVersion_String = 1006, Prop_HardwareRevision_String = 1007, Prop_AllWirelessDongleDescriptions_String = 1008, Prop_ConnectedWirelessDongle_String = 1009, Prop_DeviceIsWireless_Bool = 1010, Prop_DeviceIsCharging_Bool = 1011, Prop_DeviceBatteryPercentage_Float = 1012, // 0 is empty, 1 is full Prop_StatusDisplayTransform_Matrix34 = 1013, Prop_Firmware_UpdateAvailable_Bool = 1014, Prop_Firmware_ManualUpdate_Bool = 1015, Prop_Firmware_ManualUpdateURL_String = 1016, Prop_HardwareRevision_Uint64 = 1017, Prop_FirmwareVersion_Uint64 = 1018, Prop_FPGAVersion_Uint64 = 1019, Prop_VRCVersion_Uint64 = 1020, Prop_RadioVersion_Uint64 = 1021, Prop_DongleVersion_Uint64 = 1022, Prop_BlockServerShutdown_Bool = 1023, Prop_CanUnifyCoordinateSystemWithHmd_Bool = 1024, Prop_ContainsProximitySensor_Bool = 1025, Prop_DeviceProvidesBatteryStatus_Bool = 1026, Prop_DeviceCanPowerOff_Bool = 1027, Prop_Firmware_ProgrammingTarget_String = 1028, Prop_DeviceClass_Int32 = 1029, Prop_HasCamera_Bool = 1030, Prop_DriverVersion_String = 1031, Prop_Firmware_ForceUpdateRequired_Bool = 1032, Prop_ViveSystemButtonFixRequired_Bool = 1033, Prop_ParentDriver_Uint64 = 1034, Prop_ResourceRoot_String = 1035, // Properties that are unique to TrackedDeviceClass_HMD Prop_ReportsTimeSinceVSync_Bool = 2000, Prop_SecondsFromVsyncToPhotons_Float = 2001, Prop_DisplayFrequency_Float = 2002, Prop_UserIpdMeters_Float = 2003, Prop_CurrentUniverseId_Uint64 = 2004, Prop_PreviousUniverseId_Uint64 = 2005, Prop_DisplayFirmwareVersion_Uint64 = 2006, Prop_IsOnDesktop_Bool = 2007, Prop_DisplayMCType_Int32 = 2008, Prop_DisplayMCOffset_Float = 2009, Prop_DisplayMCScale_Float = 2010, Prop_EdidVendorID_Int32 = 2011, Prop_DisplayMCImageLeft_String = 2012, Prop_DisplayMCImageRight_String = 2013, Prop_DisplayGCBlackClamp_Float = 2014, Prop_EdidProductID_Int32 = 2015, Prop_CameraToHeadTransform_Matrix34 = 2016, Prop_DisplayGCType_Int32 = 2017, Prop_DisplayGCOffset_Float = 2018, Prop_DisplayGCScale_Float = 2019, Prop_DisplayGCPrescale_Float = 2020, Prop_DisplayGCImage_String = 2021, Prop_LensCenterLeftU_Float = 2022, Prop_LensCenterLeftV_Float = 2023, Prop_LensCenterRightU_Float = 2024, Prop_LensCenterRightV_Float = 2025, Prop_UserHeadToEyeDepthMeters_Float = 2026, Prop_CameraFirmwareVersion_Uint64 = 2027, Prop_CameraFirmwareDescription_String = 2028, Prop_DisplayFPGAVersion_Uint64 = 2029, Prop_DisplayBootloaderVersion_Uint64 = 2030, Prop_DisplayHardwareVersion_Uint64 = 2031, Prop_AudioFirmwareVersion_Uint64 = 2032, Prop_CameraCompatibilityMode_Int32 = 2033, Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034, Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035, Prop_DisplaySuppressed_Bool = 2036, Prop_DisplayAllowNightMode_Bool = 2037, Prop_DisplayMCImageWidth_Int32 = 2038, Prop_DisplayMCImageHeight_Int32 = 2039, Prop_DisplayMCImageNumChannels_Int32 = 2040, Prop_DisplayMCImageData_Binary = 2041, Prop_SecondsFromPhotonsToVblank_Float = 2042, // Properties that are unique to TrackedDeviceClass_Controller Prop_AttachedDeviceId_String = 3000, Prop_SupportedButtons_Uint64 = 3001, Prop_Axis0Type_Int32 = 3002, // Return value is of type EVRControllerAxisType Prop_Axis1Type_Int32 = 3003, // Return value is of type EVRControllerAxisType Prop_Axis2Type_Int32 = 3004, // Return value is of type EVRControllerAxisType Prop_Axis3Type_Int32 = 3005, // Return value is of type EVRControllerAxisType Prop_Axis4Type_Int32 = 3006, // Return value is of type EVRControllerAxisType Prop_ControllerRoleHint_Int32 = 3007, // Return value is of type ETrackedControllerRole // Properties that are unique to TrackedDeviceClass_TrackingReference Prop_FieldOfViewLeftDegrees_Float = 4000, Prop_FieldOfViewRightDegrees_Float = 4001, Prop_FieldOfViewTopDegrees_Float = 4002, Prop_FieldOfViewBottomDegrees_Float = 4003, Prop_TrackingRangeMinimumMeters_Float = 4004, Prop_TrackingRangeMaximumMeters_Float = 4005, Prop_ModeLabel_String = 4006, // Properties that are used for user interface like icons names Prop_IconPathName_String = 5000, // usually a directory named "icons" Prop_NamedIconPathDeviceOff_String = 5001, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceSearching_String = 5002, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceSearchingAlert_String = 5003, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceReady_String = 5004, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceReadyAlert_String = 5005, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceNotReady_String = 5006, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceStandby_String = 5007, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others Prop_NamedIconPathDeviceAlertLow_String = 5008, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others // Properties that are used by helpers, but are opaque to applications Prop_DisplayHiddenArea_Binary_Start = 5100, Prop_DisplayHiddenArea_Binary_End = 5150, // Properties that are unique to drivers Prop_UserConfigPath_String = 6000, Prop_InstallPath_String = 6001, Prop_HasDisplayComponent_Bool = 6002, Prop_HasControllerComponent_Bool = 6003, Prop_HasCameraComponent_Bool = 6004, Prop_HasDriverDirectModeComponent_Bool = 6005, Prop_HasVirtualDisplayComponent_Bool = 6006, // Vendors are free to expose private debug data in this reserved region Prop_VendorSpecific_Reserved_Start = 10000, Prop_VendorSpecific_Reserved_End = 10999, }
在vr::ITrackedDeviceServerDriver设备驱动中使用如下:
virtual EVRInitError Activate( vr::TrackedDeviceIndex_t unObjectId ) { m_unObjectId = unObjectId; m_ulPropertyContainer = vr::VRProperties()->TrackedDeviceToPropertyContainer( m_unObjectId ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, Prop_ModelNumber_String, m_sModelNumber.c_str() ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, Prop_RenderModelName_String, m_sModelNumber.c_str() ); vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_UserIpdMeters_Float, m_flIPD ); vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_UserHeadToEyeDepthMeters_Float, 0.f ); vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_DisplayFrequency_Float, m_flDisplayFrequency ); vr::VRProperties()->SetFloatProperty( m_ulPropertyContainer, Prop_SecondsFromVsyncToPhotons_Float, m_flSecondsFromVsyncToPhotons ); // return a constant that's not 0 (invalid) or 1 (reserved for Oculus) vr::VRProperties()->SetUint64Property( m_ulPropertyContainer, Prop_CurrentUniverseId_Uint64, 2 ); // avoid "not fullscreen" warnings from vrmonitor vr::VRProperties()->SetBoolProperty( m_ulPropertyContainer, Prop_IsOnDesktop_Bool, false ); // Icons can be configured in code or automatically configured by an external file "drivername\resources\driver.vrresources". // Icon properties NOT configured in code (post Activate) are then auto-configured by the optional presence of a driver's "drivername\resources\driver.vrresources". // In this manner a driver can configure their icons in a flexible data driven fashion by using an external file. // // The structure of the driver.vrresources file allows a driver to specialize their icons based on their HW. // Keys matching the value in "Prop_ModelNumber_String" are considered first, since the driver may have model specific icons. // An absence of a matching "Prop_ModelNumber_String" then considers the ETrackedDeviceClass ("HMD", "Controller", "GenericTracker", "TrackingReference") // since the driver may have specialized icons based on those device class names. // // An absence of either then falls back to the "system.vrresources" where generic device class icons are then supplied. // // Please refer to "bin\drivers\sample\resources\driver.vrresources" which contains this sample configuration. // // "Alias" is a reserved key and specifies chaining to another json block. // // In this sample configuration file (overly complex FOR EXAMPLE PURPOSES ONLY).... // // "Model-v2.0" chains through the alias to "Model-v1.0" which chains through the alias to "Model-v Defaults". // // Keys NOT found in "Model-v2.0" would then chase through the "Alias" to be resolved in "Model-v1.0" and either resolve their or continue through the alias. // Thus "Prop_NamedIconPathDeviceAlertLow_String" in each model's block represent a specialization specific for that "model". // Keys in "Model-v Defaults" are an example of mapping to the same states, and here all map to "Prop_NamedIconPathDeviceOff_String". // bool bSetupIconUsingExternalResourceFile = true; if ( !bSetupIconUsingExternalResourceFile ) { // Setup properties directly in code. // Path values are of the form {drivername}\icons\some_icon_filename.png vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceOff_String, "{sample}/icons/headset_sample_status_off.png" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceSearching_String, "{sample}/icons/headset_sample_status_searching.gif" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceSearchingAlert_String, "{sample}/icons/headset_sample_status_searching_alert.gif" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceReady_String, "{sample}/icons/headset_sample_status_ready.png" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceReadyAlert_String, "{sample}/icons/headset_sample_status_ready_alert.png" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceNotReady_String, "{sample}/icons/headset_sample_status_error.png" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceStandby_String, "{sample}/icons/headset_sample_status_standby.png" ); vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_NamedIconPathDeviceAlertLow_String, "{sample}/icons/headset_sample_status_ready_low.png" ); } return VRInitError_None; }2.自定义类:
DeviceHolder类:
1>.addAndActivateDevice():代码如下:
IdReturnValue addAndActivateDevice(vr::ITrackedDeviceServerDriver *dev) { /// check to make sure it's not null and not already in there if (!dev) { return IdReturnValue::makeError(); } auto existing = findDevice(dev);//查找 if (existing) { /// @todo do we return an error or the existing location? This /// returns the existing location after re-activating. dev->Activate(existing.value); return existing; } auto newId = static_cast<std::uint32_t>(devices_.size()); devices_.push_back(dev); dev->Activate(newId); return IdReturnValue::makeValue(newId); }
@brief:查找容器devices_中是否存在dev设备驱动,若存在,则active它并返回它的id号;反之,则添加进devices_并返回id号。
2>.addAndActivateDeviceAt():代码如下:
/// Add and activate a device at a reserved id. IdReturnValue addAndActivateDeviceAt(vr::ITrackedDeviceServerDriver *dev, std::uint32_t idx) { /// check to make sure it's not null and not already in there if (!dev) { return IdReturnValue::makeError(); } auto existing = findDevice(dev); if (existing && existing.value != idx) { // if we already found it in there and it's not at the desired // index... return IdReturnValue(existing.value, false); } if (existing) { // well, in this case, we might need to just activate it again. dev->Activate(idx); return IdReturnValue::makeValue(idx); } if (!(idx < devices_.size())) { // OK, we need to reserve more room. reserveIds(idx + 1); } if (devices_[idx]) { // there's already somebody else there... return IdReturnValue::makeError(); } /// Finally, if we made it through that, it's our turn. devices_[idx] = dev; dev->Activate(idx); return IdReturnValue::makeValue(idx); }@brief:激活指定idx的设备。
InterfaceVersionSupport类:
@brief:辅助类,用于管理接口版本号
1>.InterfaceVersionSupport() : supportedInterfaces_(populate()) {}
@brief:接收populate的返回值
2>.populate:
/// Function to create and populate the supported interface /// container, so the object's data member may be const. static Container populate() { Container ret; // Populate a vector with all the supported interfaces. for_each_const_string_array( vr::k_InterfaceVersions, [&](const char *str) { ret.emplace_back(str); }); // so we can use binary_search std::sort(ret.begin(), ret.end()); return ret; }
@brief:将openvr_driver.h中声明的vr::k_InterfaceVersions传入lambda函数,加入vector。之后按序列从小到大排列,
并返回赋给supportedInterfaces_
namespace vr { static const char * const k_InterfaceVersions[] = { IVRSettings_Version, ITrackedDeviceServerDriver_Version, IVRDisplayComponent_Version, IVRDriverDirectModeComponent_Version, IVRControllerComponent_Version, IVRCameraComponent_Version, IServerTrackedDeviceProvider_Version, IVRWatchdogProvider_Version, IVRVirtualDisplay_Version, IVRDriverManager_Version, IVRResources_Version, nullptr }; ... }2>.inline bool isInterfaceNameWeCareAbout(std::string const &interfaceName)
@brief:用于检查传入的接口类是否为该驱动所care的接口类
/// A list of just the interface names we actually use. static const auto interfaceNamesWeCareAbout = { "ITrackedDeviceServerDriver", "IVRDisplayComponent", "IVRControllerComponent", //< @todo do we actually use/cast to // this interface? "IServerTrackedDeviceProvider", "IVRWatchdogProvider"}; } // namespace detail inline bool isInterfaceNameWeCareAbout(std::string const &interfaceName) { return std::find(detail::interfaceNamesWeCareAbout.begin(), detail::interfaceNamesWeCareAbout.end(), interfaceName) != detail::interfaceNamesWeCareAbout.end(); }
DriverLoader:
@brief:用来加载一个steamVR driver dll驱动,获取主入口点及其函数调用,这个类是驱动运行的必要条件。
1>. /// Factory function to make a driver loader.
static std::unique_ptr<DriverLoader>
make(std::string const &driverRoot, std::string const &driverFile);
@brief:工厂方法生成一个驱动加载对象。
loader_ = DriverLoader::make(locations_.driverRoot, locations_.driverFile);
驱动根目录(driverRoot)如:Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64
驱动文件(driverFile)如:Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64\driver_lighthouse.dll
2>.template <typename InterfaceType>
ReturnValue<InterfaceType *, int> getInterface()
@brief:获取模板参数InterfaceType指定的接口类。最初由getProvider<vr::IServerTrackedDeviceProvider>调用。
3>.std::string const &getDriverRoot()
@brief:获取根目录,如:
Steam\steamapps\common\SteamVR\drivers\lighthouse\bin\win64
ChaperoneData:
@brief:一些已知的追踪器空间范围的数据。比如空间界限,游戏空间等。来自于chaperone_info,位于<Steam\config\chaperone_info.vrchap>
1>.struct UniverseData {
CalibrationType type = CalibrationType::Standing;
std::array<double, 3> translation;
double yaw = 0.;
};
@brief:空间数据。类型:站立。数据:位置信息以及偏航角。
2>.ChaperoneData::ChaperoneData(std::string const &steamConfigDir)
: impl_(new Impl), configDir_(steamConfigDir)
@brief:从chaperone_info.vrchap文件中获取字段填充成员变量impl_,结构代码如下:
struct ChaperoneData::Impl { Json::Value chaperoneInfo; UniverseDataMap universes; UniverseBaseSerials baseSerials; };
3>.UniverseData getDataForUniverse(UniverseId universe) const
@brief:获取外设数据。
ChaperoneData::UniverseData ChaperoneData::getDataForUniverse(UniverseId universe) const { auto it = impl_->universes.find(universe); if (it == end(impl_->universes)) { return UniverseData(); } return it->second; // ChaperoneData::UniverseData类型 }@brief:通过universe号获取对应的键值
using UniverseDataMap =
std::map<std::uint64_t, ChaperoneData::UniverseData>;
4>. UniverseId guessUniverseIdFromBaseStations(BaseStationSerials const &bases);
using BaseStationSerials = std::vector<std::string>; ChaperoneData::UniverseId ChaperoneData::guessUniverseIdFromBaseStations( BaseStationSerials const &bases) { auto providedSize = bases.size(); UniverseId ret = 0; using UniverseRank = std::pair<float, UniverseId>; /// Compare function for heap. auto compare = [](UniverseRank const &a, UniverseRank const &b) { return a.first < b.first; }; /// Will contain heap of potential universes and their value (a fraction /// of their base stations and provided base stations that were included /// in the base station list provided to the function) std::vector<UniverseRank> potentialUniverses; auto push = [&](float value, UniverseId id) { potentialUniverses.emplace_back(value, id); std::push_heap(begin(potentialUniverses), end(potentialUniverses), compare); }; for (auto &univBaseSerial : impl_->baseSerials) { auto const &baseSerials = univBaseSerial.second; std::size_t hits = 0; auto b = begin(baseSerials); auto e = end(baseSerials); /// Count the number of entries that we were given that are also in /// this universe's list. auto found = std::count_if(begin(bases), end(bases), [&](std::string const &needle) { return std::find(b, e, needle) != e; }); if (found > 0) { /// This is meant to combine the influence of "found" in both /// providedSize and universe size, and the +1 in the /// denominator is to avoid division by zero. auto weight = 2.f * static_cast<float>(found) / (baseSerials.size() + providedSize + 1); #if 0 std::cout << "Guessing produced weight of " << weight << " for " << univBaseSerial.first << std::endl; #endif push(weight, univBaseSerial.first); } } if (!potentialUniverses.empty()) { /// it's a heap, so the best one is always on top. return potentialUniverses.front().second; } return ret; }
@brief:由基站预测id。
com_osvr_Vive.cpp为OSVR插件一般结构:
OSVR_ReturnCode update(){ if (m_startedInSuccess) { return OSVR_RETURN_SUCCESS; } if (!m_shouldAttemptDetection) { /// We said we shouldn't and wouldn't try again. return OSVR_RETURN_FAILURE; } /// Hand the Vive object off to the OSVR driver. auto startResult = finishViveStartup();// 进入 if (startResult) { /// and it started up the rest of the way just fine! /// We'll keep the driver around! m_logger->info("Vive driver finished startup successfully!"); m_startedInSuccess = true; return OSVR_RETURN_SUCCESS; } m_logger->error("Vive driver startup failed."); if (m_shouldAttemptDetection) { m_logger->info(" Unloading to perhaps try again later."); } return OSVR_RETURN_FAILURE; }
finishViveStartup()中调用ViveDriverHost中的start方法。
ViveDriverHost类:继承自vr::IVRServerDriverHost:
ViveDriverHost::StartResult ViveDriverHost::start(OSVR_PluginRegContext ctx, osvr::vive::DriverWrapper &&inVive) { if (!inVive) { m_logger->error( "Called ViveDriverHost::start() with an invalid vive object!"); return StartResult::TemporaryFailure; } /// Take ownership of the Vive. m_vive.reset(new osvr::vive::DriverWrapper(std::move(inVive))); /// define the lambda to handle the ServerDriverHost::TrackedDeviceAdded auto handleNewDevice = [&](const char *serialNum, ETrackedDeviceClass eDeviceClass, ITrackedDeviceServerDriver *pDriver) { auto dev = pDriver; if (!dev) { m_logger->info("null input device"); return false; } auto ret = activateDevice(dev, eDeviceClass); if (!ret) { m_logger->error("Device with serial number ") << serialNum << " couldn't be added to the devices vector."; return false; } NewDeviceReport out{std::string{serialNum}, ret.value}; { std::lock_guard<std::mutex> lock(m_mutex); m_newDevices.submitNew(std::move(out), lock); } return true; }; m_vive->driverHost().onTrackedDeviceAdded = handleNewDevice; /// Finish setting up the Vive. try { if (!m_vive->startServerDeviceProvider()) { m_logger->error("Could not start the server device provider in " "the Vive driver. Exiting."); return StartResult::TemporaryFailure; } } catch (CouldNotGetInterface &e) { m_logger->error("Caught exception trying to start Vive server " "device provider: ") << e.what(); m_logger->error("SteamVR interface version may have changed, may " "need to be rebuilt against an updated header or " "use an older SteamVR version. Exiting."); return StartResult::PermanentFailure; } /// Check for interface compatibility if (DriverWrapper::InterfaceVersionStatus::InterfaceMismatch == m_vive->checkServerDeviceProviderInterfaces()) { m_logger->error( "SteamVR lighthouse driver requires unavailable/unsupported " "SteamVR lighthouse driver requires unavailable/unsupported " "interface versions - either too old or too new for this " "build. Specifically, the following critical mismaches: "); for (auto iface : m_vive->getUnsupportedRequestedInterfaces()) { if (isInterfaceNameWeCareAbout( detail::getInterfaceName(iface))) { auto supported = m_vive->getSupportedInterfaceVersions() .findSupportedVersionOfInterface(iface); m_logger->error(" - SteamVR lighthouse: ") << iface << "\t\t OSVR-Vive: " << supported; } } m_logger->error("Cannot continue.\n"); return StartResult::PermanentFailure; } /// Power the system up. m_vive->serverDevProvider().LeaveStandby(); /// Reserve ID 0 for the HMD m_vive->devices().reserveIds(1); /// Finish setting this up as an OSVR device. /// Create the initialization options OSVR_DeviceInitOptions opts = osvrDeviceCreateInitOptions(ctx); osvrDeviceTrackerConfigure(opts, &m_tracker); osvrDeviceAnalogConfigure(opts, &m_analog, NUM_ANALOGS); osvrDeviceButtonConfigure(opts, &m_button, NUM_BUTTONS); /// Because the callbacks may not come from the same thread that /// calls RunFrame, we need to be careful to not send directly from /// those callbacks. We can't use an Async device token because the /// waits are too long and they goof up the SteamVR Lighthouse driver. m_dev.initSync(ctx, "Vive", opts); /// Send JSON descriptor m_dev.sendJsonDescriptor(com_osvr_Vive_json); /// Register update callback m_dev.registerUpdateCallback(this); return StartResult::Success; }
1>.将参数DriverWrapper类对象inVive赋给成员变量m_vive
2>.将lambda函数指针handleNewDevice赋给onTrackedDeviceAdded(由m_vive控制的driverHost类):
lambda函数截获串号(类似hydra_controller1或hydra_controller2之类的字符串形式),设备类别(类似HMD PUCK等)以及
设备驱动。通过参数传入将指定idx的外设添加到容器std::vector<vr::ITrackedDeviceServerDriver *> devices_中
,并激活它,激活后返回它的idx值赋值给ret.value。之后,将serialNum与ret.value构造一个NewDeviceReport类,将该类存入
队列deque_。
3>.将lambda函数赋给 m_vive->driverHost().onTrackedDeviceAdded。将在ServerDeviceProvider启动后,在Init中被调用。
4>.startServerDeviceProvider:
初始化vr::IVRSettings,vr::IVRDriverLog,vr::IVRProperties类对象,并使用它们构建一个vr::DriverContext类对象,再通过
VR_INIT_SERVER_DRIVER_CONTEXT(context_)本质上是给COpenVRDriverContext类的m_pVRSettings,m_pVRDriverLog,m_pVRProperties
赋值。以供后续如TrackedDeviceAdded使用。
#define VR_INIT_SERVER_DRIVER_CONTEXT( pContext ) \ { \ vr::EVRInitError eError = vr::InitServerDriverContext( pContext ); \ if( eError != vr::VRInitError_None ) \ return eError; \ }
在将环境准备好之后,serverDeviceProvider_ =
getProvider<vr::IServerTrackedDeviceProvider>(
std::move(loader_), context_);
传入模板参数vr::IServerTrackedDeviceProvider, 随后:
template <typename InterfaceType> inline ProviderPtr<InterfaceType> getProvider(std::unique_ptr<DriverLoader> &&loader, vr::IVRDriverContext *context) { static_assert( InterfaceExpectedFromEntryPointTrait<InterfaceType>::value, "Function only valid for those 'provider' interface types " "expected to be provided by the driver entry point."); return detail::getProviderImpl<InterfaceType>( std::move(loader), context, [](SharedDriverLoader const &) {}); }
传入一个lambda函数指针(不捕获时才可转换为函数指针)。
template <typename InterfaceType, typename F> inline ProviderPtr<InterfaceType> getProviderImpl(std::unique_ptr<DriverLoader> &&loader, vr::IVRDriverContext *context, F &&driverLoaderFunctor) { using return_type = ProviderPtr<InterfaceType>; if (!loader) { return return_type{}; } /// Move into local pointer, so if something goes wrong, the driver /// gets unloaded. std::unique_ptr<DriverLoader> myLoader(std::move(loader)); auto rawPtr = myLoader->getInterfaceThrowing<InterfaceType>(); auto initResults = rawPtr->Init(context); if (vr::VRInitError_None != initResults) { /// Failed, reset the loader pointer to unload the driver. std::cout << "Got error code " << initResults << std::endl; myLoader.reset(); return return_type{}; } /// OK, so this is the interface. Move the loader into a shared /// pointer, make the loader responsible for cleanup of the /// interface, and get the shared pointer of the interface pointer /// returned. SharedDriverLoader sharedLoader(std::move(myLoader)); sharedLoader->cleanupInterfaceOnDestruction(rawPtr); /// Call the hook (std::forward<F>(driverLoaderFunctor))(sharedLoader); /// Create the return value: another shared pointer. /// This is the so-called "aliasing" constructor - this pointer will /// actually keep the DriverLoader alive and do nothing with the /// lifetime of rawPtr (which is why the loader is responsible for /// calling Cleanup, see above) return_type ret(sharedLoader, rawPtr); return ret; }
(std::forward<F>(driverLoaderFunctor))(sharedLoader):钩子获取dll中的接口,与driver_lighthouse.dll衔接。
其中sharedLoader最初由loader_ = DriverLoader::make(locations_.driverRoot,locations_.driverFile);构建而成。
std::unique_ptr<DriverLoader> DriverLoader::make(std::string const &driverRoot, std::string const &driverFile) { std::unique_ptr<DriverLoader> ret( new DriverLoader(driverRoot, driverFile)); return ret; }
返回一个DriverLoader对象。
DriverLoader::DriverLoader(std::string const &driverRoot, std::string const &driverFile) : impl_(new Impl), logger_(osvr::util::log::make_logger("DriverLoader")) { /// Set the PATH to include the driver directory so it can /// find its deps. SearchPathExtender extender(driverRoot); f defined(OSVR_WINDOWS) impl_->driver_ = LoadLibraryA(driverFile.c_str());<strong><span style="font-size:14px;">// 加载steam目录下的driver_lighthouse.dll文件</span></strong> if (!impl_->driver_) { reset(); throw CouldNotLoadDriverModule(); } auto proc = GetProcAddress(impl_->driver_, ENTRY_POINT_FUNCTION_NAME);<strong><span style="font-size:14px;">// 获取dll文件中的HmdDriverFactory接口地址</span></strong> if (!proc) { reset(); throw CouldNotLoadEntryPoint(); } factory_ = reinterpret_cast<DriverFactory>(proc);<strong><span style="font-size:14px;">// 强制转换为void *(*)(const char *, int *)类型</span></strong> lif defined(OSVR_LINUX) || defined(OSVR_MACOSX) impl_->driver_ = dlopen(driverFile.c_str(), RTLD_NOW | RTLD_GLOBAL); if (!impl_->driver_) { reset(); throw CouldNotLoadDriverModule(dlerror()); } auto proc = dlsym(impl_->driver_, ENTRY_POINT_FUNCTION_NAME); if (!proc) { reset(); throw CouldNotLoadEntryPoint(dlerror()); } factory_ = reinterpret_cast<DriverFactory>(proc); ndif }static const auto ENTRY_POINT_FUNCTION_NAME = "HmdDriverFactory";
using DriverFactory = void *(*)(const char *, int *);
目的是存储一个地址到变量:factory_
在driver_lighthouse.dll中的vr::IServerTrackedDeviceProvider已提供接口如下:
CServerDriver g_ServerTrackedDeviceProvider;
HMD_DLL_EXPORT void *HmdDriverFactory(const char *pInterfaceName, int *pReturnCode) { if (0 == strcmp(IServerTrackedDeviceProvider_Version, pInterfaceName)) { return &g_ServerTrackedDeviceProvider; } if (pReturnCode) { *pReturnCode = VRInitError_Init_InterfaceNotFound; } return NULL; }
回到ViveDriverHost::start中,checkServerDeviceProviderInterfaces检测驱动需要的接口openvr_driver.h是否支持。
enum class InterfaceVersionStatus { /// All mentioned interface version strings are handled/described by /// the header we've built against. AllInterfacesOK,// 驱动请求使用的所有接口类 openvr_driver.h中都支持 /// Not all mentioned interface version strings are /// handled/described by the header we've built against, but the /// interfaces that we use match. AllUsedInterfacesOK, // 不是所有请求的接口类openvr_driver.h中都支持,但是所使用到的类都支持。 /// At least one of the interfaces that we use doesn't match the /// version we built against. InterfaceMismatch //至少一个所使用到的接口类在openvr_driver.h中不支持 }; static const char * const k_InterfaceVersions[] = { IVRSettings_Version, ITrackedDeviceServerDriver_Version, IVRDisplayComponent_Version, IVRDriverDirectModeComponent_Version, IVRControllerComponent_Version, IVRCameraComponent_Version, IServerTrackedDeviceProvider_Version, IVRWatchdogProvider_Version, IVRVirtualDisplay_Version, nullptr };
serverDevProvider().GetInterfaceVersions()返回的是以上openvr_driver.h中的接口类名,并比较是否所有接口类版本都支持。
若一个版本不支持,则将其入队,并将其与本驱动care的版本进行对比,若是必须要使用的但是又不被openvr_driver.h所支持。
则allUsedSupported=false.
/// A list of just the interface names we actually use. static const auto interfaceNamesWeCareAbout = { "ITrackedDeviceServerDriver", "IVRDisplayComponent", "IVRControllerComponent", //< @todo do we actually use/cast to // this interface? "IServerTrackedDeviceProvider", "IVRWatchdogProvider"};
关于数据传输部分:
在driver_lighthouse.dll中通过RunFrame()中的vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_unObjectId, GetPose(), sizeof(DriverPose_t));
往vive中的以下接口发:
void ViveDriverHost::TrackedDevicePoseUpdated(uint32_t unWhichDevice, const DriverPose_t &newPose, uint32_t unPoseStructSize) { submitTrackingReport(unWhichDevice, osvr::util::time::getNow(), newPose); } void ViveDriverHost::submitTrackingReport(uint32_t unWhichDevice, OSVR_TimeValue const &tv, const DriverPose_t &newPose) { TrackingReport out; out.timestamp = tv; out.sensor = unWhichDevice; out.report = newPose; { std::lock_guard<std::mutex> lock(m_mutex); m_trackingReports.submitNew(std::move(out), lock); } }因此,整个数据过程为:
通过DriverLoader.cpp加载dll后,再通过m_vive->startServerDeviceProvider()获取dll实现的
vr::IServerTrackedDeviceProvider接口, update中通过调用m_vive->serverDevProvider().RunFrame()结构,通过submitNew往deque_中push,vive osvr端通过grabItems到vector_。最后在update中再通过accessWorkItems获取
vector_。最终通过convertAndSendTracker中的osvrDeviceTrackerSendPoseTimestamped往应用程序传数据。其中chaperone
配置文件中的数据在handleUniverseChange中被处理。
2017-6-27------------------------------------------------------------------------
无论是在直连或者扩展模式上,HTC Vive和它的控制器被OSVR所支持且可以在任何OSVR应用程序上使用,还支持畸变校正,全方位追踪以及输入支持。
通过OSVR,OSVR-Vive插件及其工具访问Vive硬件。
兼容性:
然后改驱动应该兼容所有的Vive家族设备,到目前为止,它只在HTC Vive和Vive PRE(非早期开发版本)上测试过。
OSVR-Vive驱动与为Vive服务的SteamVR驱动交互(driver_lighthouse),因此与SteamVR版本也有关联。
安装流程:
首先确保Vive在SteamVR上工作正常且已经安排了一个房间,最好是进行一个站立状态或房间级别的校准作为游戏空间。然后,下载
与OSVR服务相对应位数的插件二进制包。
在下载的解压包内有以下文件:
1>.一个插件文件。在Windows上,这是一个在bin/osvr-plugins-0目录下的.dll文件。将它放在OSVR server相同目录下。
2>.在bin目录内,一个ViveDisplayExtractor工具---拷贝到OSVR server的bin目录下。
3>.一个起始样例配置文件osvr_server_config(还有一些可以快速替换的预设显示描述符以及网格文件)
首先应该在不需要改变任何SteamVR设置的基础上,能够以直连模式在Vive头显上运行一个OSVR的应用程序。如果Vive在SteamVR上以
直联模式工作正常,但是在OSVR上不能以直连模式打开,则原因可能是在OSVR应用程序启动之前SteamVR没有退出(需要确保在
OSVR应用程序启动之前SteamVR已经退出)。在一些系统上,退出SteamVR之前,在SteamVR菜单内可能需要禁止直连模式。
一次安装:Vive需要一个客户显示描述以及网格畸变数据文件,使用ViveDisplayExtractor工具提取这些文件数据。确保ViveDisplayExtractor与
osvr_server一起运行,也就是Vive与PC连接,SteamVR已经退出,运行ViveDisplayExtractor。
如果成功,将会看到类似以下:
[DisplayExtractor] Writing distortion mesh data file:
C:/Users/Ryan/Desktop/OSVR/bin/displays/HTC_Vive_PRE_meshdata.json
[DisplayExtractor] Writing display descriptor file:
C:/Users/Ryan/Desktop/OSVR/bin/displays/HTC_Vive_PRE.json
[DisplayExtractor] Press enter to quit...
Note:结果配置包含一个到网格数据的绝对路径,因此如果改变了osvr server所在目录,只需要再次运行ViveDisplayExtractor。
以上就是所有的了!现在可以使用样例osvr_server_config.vive.sample.json 文件作为服务配置文件了(将它改为默认名: osvr_server_config.json
),可以在Vive上运行OSVR启动的应用程序了。
如果想要运行SteamVR APP,没问题:只要关闭OSVR Server并且任何在直连模式运行的OSVR Apps即可。
- OSVR-Vive
- OSVR简介
- An Introduction to OSVR
- OSVR-Core编译
- OSVR接入HMD设备
- osvr::clientkit::ClientContext
- OSVR Reset Yaw
- VRPN-OSVR介绍
- SteamVR-OSVR(build 342)
- Using External VRPN Devices in OSVR
- 制作一个简单的OSVR设备插件
- 添加一个新的HMD到OSVR
- Vive开发第一步
- HTV Vive 体验记
- Vive开发教程汇总
- HTC Vive UI Guideline
- HTC Vive全屏
- HTC VIVE 开发 移动
- HDU 1003 注意初始化
- 着色器的一些归纳总结
- 51nod 1413 权势二进制
- Struts学习
- 【AngularJS】解决ng-if中的ng-model值无效的问题
- OSVR-Vive
- 获取XML文件内容
- Junit hamcrest相关问题
- LSTM中隐层神经元的传播机制
- 未知:数列1——题解
- 微服务的优缺点
- 第六讲 单片机之c语言RS485通信
- sqoop mysql与HDFS互转
- Python3之字符编码及文件操作