1421 lines · 66.4 KB · C++
RawDownload
////  ViveControllerManager.cpp//  input-plugins/src/input-plugins////  Created by Sam Gondelman on 6/29/15.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "ViveControllerManager.h"#include <algorithm>#include <string> #include <PerfStat.h>#include <PathUtils.h>#include <GeometryCache.h>#include <gpu/Batch.h>#include <gpu/Context.h>#include <DeferredLightingEffect.h>#include <NumericalConstants.h>#include <ui-plugins/PluginContainer.h>#include <UserActivityLogger.h>#include <NumericalConstants.h>#include <Preferences.h>#include <SettingHandle.h>#include <OffscreenUi.h>#include <GLMHelpers.h>#include <glm/ext.hpp>#include <glm/gtc/quaternion.hpp>#include <ui-plugins/PluginContainer.h>#include <plugins/DisplayPlugin.h> #include <controllers/UserInputMapper.h>#include <Plugins/InputConfiguration.h>#include <controllers/StandardControls.h> extern PoseData _nextSimPoseData; vr::IVRSystem* acquireOpenVrSystem();void releaseOpenVrSystem(); static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml");static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND; static const char* MENU_PARENT = "Avatar";static const char* MENU_NAME = "Vive Controllers";static const char* MENU_PATH = "Avatar" ">" "Vive Controllers"; static const int MIN_HEAD = 1;static const int MIN_PUCK_COUNT = 2;static const int MIN_FEET_AND_HIPS = 3;static const int MIN_FEET_HIPS_CHEST = 4;static const int MIN_FEET_HIPS_SHOULDERS = 5;static const int MIN_FEET_HIPS_CHEST_SHOULDERS = 6; static const int FIRST_FOOT = 0;static const int SECOND_FOOT = 1;static const int HIP = 2;static const int CHEST = 3; const char* ViveControllerManager::NAME { "OpenVR" }; const std::map<vr::ETrackingResult, QString> TRACKING_RESULT_TO_STRING = {    {vr::TrackingResult_Uninitialized, QString("vr::TrackingResult_Uninitialized")},    {vr::TrackingResult_Calibrating_InProgress, QString("vr::TrackingResult_Calibrating_InProgess")},    {vr::TrackingResult_Calibrating_OutOfRange, QString("TrackingResult_Calibrating_OutOfRange")},    {vr::TrackingResult_Running_OK, QString("TrackingResult_Running_Ok")},    {vr::TrackingResult_Running_OutOfRange, QString("TrackingResult_Running_OutOfRange")}}; static glm::mat4 computeOffset(glm::mat4 defaultToReferenceMat, glm::mat4 defaultJointMat, controller::Pose puckPose) {    glm::mat4 poseMat = createMatFromQuatAndPos(puckPose.rotation, puckPose.translation);    glm::mat4 referenceJointMat = defaultToReferenceMat * defaultJointMat;    return glm::inverse(poseMat) * referenceJointMat;} static bool sortPucksYPosition(const PuckPosePair& firstPuck, const PuckPosePair& secondPuck) {    return (firstPuck.second.translation.y < secondPuck.second.translation.y);} static bool determineLimbOrdering(const controller::Pose& poseA, const controller::Pose& poseB, glm::vec3 axis, glm::vec3 axisOrigin) {    glm::vec3 poseAPosition = poseA.getTranslation();    glm::vec3 poseBPosition = poseB.getTranslation();     glm::vec3 poseAVector = poseAPosition - axisOrigin;    glm::vec3 poseBVector = poseBPosition - axisOrigin;     float poseAProjection = glm::dot(poseAVector, axis);    float poseBProjection = glm::dot(poseBVector, axis);    return (poseAProjection > poseBProjection);} static glm::vec3 getReferenceHeadXAxis(glm::mat4 defaultToReferenceMat, glm::mat4 defaultHead) {    glm::mat4 finalHead = defaultToReferenceMat * defaultHead;    return glmExtractRotation(finalHead) * Vectors::UNIT_X;} static glm::vec3 getReferenceHeadPosition(glm::mat4 defaultToReferenceMat, glm::mat4 defaultHead) {    glm::mat4 finalHead = defaultToReferenceMat * defaultHead;    return extractTranslation(finalHead);} static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult) {    QString result;    auto iterator = TRACKING_RESULT_TO_STRING.find(trackingResult);     if (iterator != TRACKING_RESULT_TO_STRING.end()) {        return iterator->second;    }    return result;} static glm::mat4 calculateResetMat() {    auto chaperone = vr::VRChaperone();    if (chaperone) {        float const UI_RADIUS = 1.0f;        float const UI_HEIGHT = 1.6f;        float const UI_Z_OFFSET = 0.5;         float xSize, zSize;        chaperone->GetPlayAreaSize(&xSize, &zSize);        glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET);         return glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos));    }    return glm::mat4();} static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) {    switch (strategy) {    default:    case ViveControllerManager::OutOfRangeDataStrategy::None:        return "None";    case ViveControllerManager::OutOfRangeDataStrategy::Freeze:        return "Freeze";    case ViveControllerManager::OutOfRangeDataStrategy::Drop:        return "Drop";    }} static ViveControllerManager::OutOfRangeDataStrategy stringToOutOfRangeDataStrategy(const QString& string) {    if (string == "Drop") {        return ViveControllerManager::OutOfRangeDataStrategy::Drop;    } else if (string == "Freeze") {        return ViveControllerManager::OutOfRangeDataStrategy::Freeze;    } else {        return ViveControllerManager::OutOfRangeDataStrategy::None;    }} bool ViveControllerManager::isDesktopMode() {    if (_container) {        return !_container->getActiveDisplayPlugin()->isHmd();    }    return false;} void ViveControllerManager::calibrate() {    if (isSupported()) {        _inputDevice->calibrateNextFrame();    }} bool ViveControllerManager::uncalibrate() {    if (isSupported()) {        _inputDevice->uncalibrate();        return true;    }    return false;} bool ViveControllerManager::isSupported() const {    return openVrSupported();} void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) {    if (isSupported()) {        if (configurationSettings.contains("desktopMode")) {            _desktopMode = configurationSettings["desktopMode"].toBool();            if (!_desktopMode) {                _resetMatCalculated = false;            }        }         if (configurationSettings.contains("hmdDesktopTracking")) {            _hmdDesktopTracking = configurationSettings["hmdDesktopTracking"].toBool();        }         _inputDevice->configureCalibrationSettings(configurationSettings);        saveSettings();    }} QJsonObject ViveControllerManager::configurationSettings() {    if (isSupported()) {        QJsonObject configurationSettings = _inputDevice->configurationSettings();        configurationSettings["desktopMode"] = _desktopMode;        configurationSettings["hmdDesktopTracking"] = _hmdDesktopTracking;        return configurationSettings;    }     return QJsonObject();} QString ViveControllerManager::configurationLayout() {    return OPENVR_LAYOUT;} bool ViveControllerManager::activate() {    InputPlugin::activate();     loadSettings();     if (!_system) {        _system = acquireOpenVrSystem();    }     if (!_system) {        return false;    }     enableOpenVrKeyboard(_container);     // register with UserInputMapper    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();    userInputMapper->registerDevice(_inputDevice);    _registeredWithInputMapper = true;    return true;} void ViveControllerManager::deactivate() {    InputPlugin::deactivate();     disableOpenVrKeyboard();     if (_system) {        _container->makeRenderingContextCurrent();        releaseOpenVrSystem();        _system = nullptr;    }     _inputDevice->_poseStateMap.clear();     // unregister with UserInputMapper    auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();    userInputMapper->removeDevice(_inputDevice->_deviceID);    _registeredWithInputMapper = false;     saveSettings();} bool ViveControllerManager::isHeadControllerMounted() const {    if (_inputDevice && _inputDevice->isHeadControllerMounted()) {        return true;    }    vr::EDeviceActivityLevel activityLevel = _system->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);    return activityLevel == vr::k_EDeviceActivityLevel_UserInteraction;} void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {     if (!_system) {        return;    }     if (isDesktopMode() && _desktopMode) {        if (!_resetMatCalculated) {            _resetMat = calculateResetMat();            _resetMatCalculated = true;        }         _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 0, _nextSimPoseData.vrPoses, vr::k_unMaxTrackedDeviceCount);        _nextSimPoseData.update(_resetMat);    } else if (isDesktopMode()) {        _nextSimPoseData.resetToInvalid();    }     auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();    handleOpenVrEvents();    if (openVrQuitRequested()) {        deactivate();        return;    }     // because update mutates the internal state we need to lock    userInputMapper->withLock([&, this]() {        _inputDevice->update(deltaTime, inputCalibrationData);    });     if (_inputDevice->_trackedControllers == 0 && _registeredWithInputMapper) {        userInputMapper->removeDevice(_inputDevice->_deviceID);        _registeredWithInputMapper = false;        _inputDevice->_poseStateMap.clear();    }     if (!_registeredWithInputMapper && _inputDevice->_trackedControllers > 0) {        userInputMapper->registerDevice(_inputDevice);        _registeredWithInputMapper = true;    }} void ViveControllerManager::loadSettings() {    Settings settings;    QString nameString = getName();    settings.beginGroup(nameString);    {        if (_inputDevice) {            const double DEFAULT_ARM_CIRCUMFERENCE = 0.33;            const double DEFAULT_SHOULDER_WIDTH = 0.48;            const QString DEFAULT_OUT_OF_RANGE_STRATEGY = "Drop";            _inputDevice->_armCircumference = settings.value("armCircumference", QVariant(DEFAULT_ARM_CIRCUMFERENCE)).toDouble();            _inputDevice->_shoulderWidth = settings.value("shoulderWidth", QVariant(DEFAULT_SHOULDER_WIDTH)).toDouble();            _inputDevice->_outOfRangeDataStrategy = stringToOutOfRangeDataStrategy(settings.value("outOfRangeDataStrategy", QVariant(DEFAULT_OUT_OF_RANGE_STRATEGY)).toString());        }    }    settings.endGroup();} void ViveControllerManager::saveSettings() const {    Settings settings;    QString nameString = getName();    settings.beginGroup(nameString);    {        if (_inputDevice) {            settings.setValue(QString("armCircumference"), _inputDevice->_armCircumference);            settings.setValue(QString("shoulderWidth"), _inputDevice->_shoulderWidth);            settings.setValue(QString("outOfRangeDataStrategy"), outOfRangeDataStrategyToString(_inputDevice->_outOfRangeDataStrategy));        }    }    settings.endGroup();}  ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) :    controller::InputDevice("Vive"),    _system(system) {     _configStringMap[Config::None] = QString("None");    _configStringMap[Config::Feet] = QString("Feet");    _configStringMap[Config::FeetAndHips] = QString("FeetAndHips");    _configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest");    _configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders");    _configStringMap[Config::FeetHipsChestAndShoulders] = QString("FeetHipsChestAndShoulders");} void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {    _poseStateMap.clear();    _buttonPressedMap.clear();    _validTrackedObjects.clear();    _trackedControllers = 0;     if (_headsetName == "") {        _headsetName = getOpenVrDeviceName();        if (_headsetName == "HTC") {            _headsetName += " Vive";        }    }    // While the keyboard is open, we defer strictly to the keyboard values    if (isOpenVrKeyboardShown()) {        _axisStateMap.clear();        return;    }     PerformanceTimer perfTimer("ViveControllerManager::update");     auto leftHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand);    auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);     handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true);    handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false);     // collect poses for all generic trackers    for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {        handleTrackedObject(i, inputCalibrationData);        handleHmd(i, inputCalibrationData);    }     // handle haptics    {        Locker locker(_lock);        if (_leftHapticDuration > 0.0f) {            hapticsHelper(deltaTime, true);        }        if (_rightHapticDuration > 0.0f) {            hapticsHelper(deltaTime, false);        }    }     if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {        _trackedControllers++;    }    if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {        _trackedControllers++;    }     calibrateFromHandController(inputCalibrationData);    calibrateFromUI(inputCalibrationData);     updateCalibratedLimbs(inputCalibrationData);    _lastSimPoseData = _nextSimPoseData;} void ViveControllerManager::InputDevice::calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData) {    if (checkForCalibrationEvent()) {        quint64 currentTime = usecTimestampNow();        if (!_timeTilCalibrationSet) {            _timeTilCalibrationSet = true;            _timeTilCalibration = currentTime + CALIBRATION_TIMELAPSE;        }         if (currentTime > _timeTilCalibration && !_triggersPressedHandled) {            _triggersPressedHandled = true;            calibrateOrUncalibrate(inputCalibrationData);        }    } else {        _triggersPressedHandled = false;        _timeTilCalibrationSet = false;    }} void ViveControllerManager::InputDevice::calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData) {    if (_calibrate) {        uncalibrate();        calibrate(inputCalibrationData);        emitCalibrationStatus();        _calibrate = false;    }} static const float CM_TO_M = 0.01f;static const float M_TO_CM = 100.0f; void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) {    Locker locker(_lock);    if (!configurationSettings.empty()) {        auto iter = configurationSettings.begin();        auto end = configurationSettings.end();        bool hmdDesktopTracking = true;        bool hmdDesktopMode = false;        while (iter != end) {            if (iter.key() == "bodyConfiguration") {                setConfigFromString(iter.value().toString());            } else if (iter.key() == "headConfiguration") {                QJsonObject headObject = iter.value().toObject();                bool overrideHead = headObject["override"].toBool();                if (overrideHead) {                    _headConfig = HeadConfig::Puck;                    _headPuckYOffset = headObject["Y"].toDouble() * CM_TO_M;                    _headPuckZOffset = headObject["Z"].toDouble() * CM_TO_M;                } else {                    _headConfig = HeadConfig::HMD;                }            } else if (iter.key() == "handConfiguration") {                QJsonObject handsObject = iter.value().toObject();                bool overrideHands = handsObject["override"].toBool();                if (overrideHands) {                    _handConfig = HandConfig::Pucks;                    _handPuckYOffset = handsObject["Y"].toDouble() * CM_TO_M;                    _handPuckZOffset = handsObject["Z"].toDouble() * CM_TO_M;                } else {                    _handConfig = HandConfig::HandController;                }            } else if (iter.key() == "armCircumference") {                _armCircumference = (float)iter.value().toDouble() * CM_TO_M;            } else if (iter.key() == "shoulderWidth") {                _shoulderWidth = (float)iter.value().toDouble() * CM_TO_M;            } else if (iter.key() == "hmdDesktopTracking") {                hmdDesktopTracking = iter.value().toBool();            } else if (iter.key() == "desktopMode") {                hmdDesktopMode = iter.value().toBool();            } else if (iter.key() == "outOfRangeDataStrategy") {                _outOfRangeDataStrategy = stringToOutOfRangeDataStrategy(iter.value().toString());            }            iter++;        }         _hmdTrackingEnabled = !(hmdDesktopMode && hmdDesktopTracking);    }} void ViveControllerManager::InputDevice::calibrateNextFrame() {    Locker locker(_lock);    _calibrate = true;} QJsonObject ViveControllerManager::InputDevice::configurationSettings() {    Locker locker(_lock);    QJsonObject configurationSettings;    configurationSettings["trackerConfiguration"] = configToString(_preferedConfig);    configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD);    configurationSettings["handController"] = (_handConfig == HandConfig::HandController);    configurationSettings["puckCount"] = (int)_validTrackedObjects.size();    configurationSettings["armCircumference"] = (double)_armCircumference * M_TO_CM;    configurationSettings["shoulderWidth"] = (double)_shoulderWidth * M_TO_CM;    configurationSettings["outOfRangeDataStrategy"] = outOfRangeDataStrategyToString(_outOfRangeDataStrategy);    return configurationSettings;}

Lines 1–500 of 1421.