2097 lines · 99.5 KB · C++
RawDownload
////  ViveControllerManager.cpp////  Created by Sam Gondelman on 6/29/15.//  Copyright 2013 High Fidelity, Inc.//  Copyright 2020 Vircadia contributors.////  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> #ifdef _WIN32#pragma warning( push )#pragma warning( disable : 4091 )#pragma warning( disable : 4334 )#endif #ifdef VIVE_PRO_EYE#include <SRanipal.h>#include <SRanipal_Eye.h>#include <SRanipal_Enums.h>#include <interface_gesture.hpp>#endif #ifdef _WIN32#pragma warning( pop )#endif #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 <AvatarConstants.h>#include <glm/ext.hpp>#include <glm/gtc/quaternion.hpp>#include <ui-plugins/PluginContainer.h>#include <plugins/DisplayPlugin.h>#include <ThreadHelpers.h> #include <controllers/UserInputMapper.h>#include <plugins/InputConfiguration.h>#include <controllers/StandardControls.h> #include "OpenVrDisplayPlugin.h" extern PoseData _nextSimPoseData; vr::IVRSystem* acquireOpenVrSystem();void releaseOpenVrSystem(); static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml");const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND; 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; #ifdef VIVE_PRO_EYEenum ViveHandJointIndex {    HAND = 0,    THUMB_1,    THUMB_2,    THUMB_3,    THUMB_4,    INDEX_1,    INDEX_2,    INDEX_3,    INDEX_4,    MIDDLE_1,    MIDDLE_2,    MIDDLE_3,    MIDDLE_4,    RING_1,    RING_2,    RING_3,    RING_4,    PINKY_1,    PINKY_2,    PINKY_3,    PINKY_4,     Size};#endif 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;} #ifdef VIVE_PRO_EYEclass ViveProEyeReadThread : public QThread {public:    ViveProEyeReadThread() {        setObjectName("OpenVR ViveProEye Read Thread");    }    void run() override {        while (!quit) {            ViveSR::anipal::Eye::EyeData eyeData;            int result = ViveSR::anipal::Eye::GetEyeData(&eyeData);            {                QMutexLocker locker(&eyeDataMutex);                eyeDataBuffer.getEyeDataResult = result;                if (result == ViveSR::Error::WORK) {                    uint64_t leftValids = eyeData.verbose_data.left.eye_data_validata_bit_mask;                    uint64_t rightValids = eyeData.verbose_data.right.eye_data_validata_bit_mask;                     eyeDataBuffer.leftDirectionValid =                        (leftValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY) > (uint64_t)0;                    eyeDataBuffer.rightDirectionValid =                        (rightValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY) > (uint64_t)0;                    eyeDataBuffer.leftOpennessValid =                        (leftValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY) > (uint64_t)0;                    eyeDataBuffer.rightOpennessValid =                        (rightValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY) > (uint64_t)0;                     float *leftGaze = eyeData.verbose_data.left.gaze_direction_normalized.elem_;                    float *rightGaze = eyeData.verbose_data.right.gaze_direction_normalized.elem_;                    eyeDataBuffer.leftEyeGaze = glm::vec3(leftGaze[0], leftGaze[1], leftGaze[2]);                    eyeDataBuffer.rightEyeGaze = glm::vec3(rightGaze[0], rightGaze[1], rightGaze[2]);                     eyeDataBuffer.leftEyeOpenness = eyeData.verbose_data.left.eye_openness;                    eyeDataBuffer.rightEyeOpenness = eyeData.verbose_data.right.eye_openness;                }            }        }    }     bool quit { false };     // mutex and buffer for moving data from this thread to the other one    QMutex eyeDataMutex;    EyeDataBuffer eyeDataBuffer;};#endif  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";    case ViveControllerManager::OutOfRangeDataStrategy::DropAfterDelay:        return "DropAfterDelay";    }} static ViveControllerManager::OutOfRangeDataStrategy stringToOutOfRangeDataStrategy(const QString& string) {    if (string == "Drop") {        return ViveControllerManager::OutOfRangeDataStrategy::Drop;    } else if (string == "Freeze") {        return ViveControllerManager::OutOfRangeDataStrategy::Freeze;    } else if (string == "DropAfterDelay") {        return ViveControllerManager::OutOfRangeDataStrategy::DropAfterDelay;    } 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 (configurationSettings.contains("hmdDesktopTracking")) {            _hmdDesktopTracking = configurationSettings["hmdDesktopTracking"].toBool();        }         if (configurationSettings.contains("eyeTrackingEnabled")) {            _eyeTrackingEnabled = configurationSettings["eyeTrackingEnabled"].toBool();        }         _inputDevice->configureCalibrationSettings(configurationSettings);        saveSettings();    }} QJsonObject ViveControllerManager::configurationSettings() {    if (isSupported()) {        QJsonObject configurationSettings = _inputDevice->configurationSettings();        configurationSettings["desktopMode"] = _desktopMode;        configurationSettings["hmdDesktopTracking"] = _hmdDesktopTracking;        configurationSettings["eyeTrackingEnabled"] = _eyeTrackingEnabled;        return configurationSettings;    }     return QJsonObject();} QString ViveControllerManager::configurationLayout() {    return OPENVR_LAYOUT;} bool isDeviceIndexActive(vr::IVRSystem*& system, uint32_t deviceIndex) {    if (!system) {        return false;    }    if (deviceIndex != vr::k_unTrackedDeviceIndexInvalid &&        system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller &&        system->IsTrackedDeviceConnected(deviceIndex)) {        vr::EDeviceActivityLevel activityLevel = system->GetTrackedDeviceActivityLevel(deviceIndex);        if (activityLevel == vr::k_EDeviceActivityLevel_UserInteraction) {            return true;        }    }    return false;} bool isHandControllerActive(vr::IVRSystem*& system, vr::ETrackedControllerRole deviceRole) {    if (!system) {        return false;    }    auto deviceIndex = system->GetTrackedDeviceIndexForControllerRole(deviceRole);    return isDeviceIndexActive(system, deviceIndex);} bool areBothHandControllersActive(vr::IVRSystem*& system) {    return        isHandControllerActive(system, vr::TrackedControllerRole_LeftHand) &&        isHandControllerActive(system, vr::TrackedControllerRole_RightHand);} #ifdef VIVE_PRO_EYEvoid ViveControllerManager::enableGestureDetection() {    if (_viveCameraHandTracker) {        return;    }    if (!ViveSR::anipal::Eye::IsViveProEye()) {        return;    } // #define HAND_TRACKER_USE_EXTERNAL_TRANSFORM 1 #ifdef HAND_TRACKER_USE_EXTERNAL_TRANSFORM    UseExternalTransform(true); // camera hand tracker results are in HMD frame#else    UseExternalTransform(false); // camera hand tracker results are in sensor frame#endif    GestureOption options; // defaults are GestureBackendAuto and GestureModeSkeleton    GestureFailure gestureFailure = StartGestureDetection(&options);    switch (gestureFailure) {        case GestureFailureNone:            qDebug() << "StartGestureDetection success";            _viveCameraHandTracker = true;            break;        case GestureFailureOpenCL:            qDebug() << "StartGestureDetection (Only on Windows) OpenCL is not supported on the machine";            break;        case GestureFailureCamera:            qDebug() << "StartGestureDetection Start camera failed";            break;        case GestureFailureInternal:            qDebug() << "StartGestureDetection Internal errors";            break;        case GestureFailureCPUOnPC:            qDebug() << "StartGestureDetection CPU backend is not supported on Windows";            break;    }} void ViveControllerManager::disableGestureDetection() {    if (!_viveCameraHandTracker) {        return;    }    StopGestureDetection();    _viveCameraHandTracker = false;}#endif 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; #ifdef VIVE_PRO_EYE    if (ViveSR::anipal::Eye::IsViveProEye()) {        qDebug() << "Vive Pro eye-tracking detected";         int error = ViveSR::anipal::Initial(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE, NULL);        if (error == ViveSR::Error::WORK) {            _viveProEye = true;            qDebug() << "Successfully initialize Eye engine.";        } else if (error == ViveSR::Error::RUNTIME_NOT_FOUND) {            _viveProEye = false;            qDebug() << "please follows SRanipal SDK guide to install SR_Runtime first";        } else {            _viveProEye = false;            qDebug() << "Failed to initialize Eye engine. please refer to ViveSR error code:" << error;        }         if (_viveProEye) {            _viveProEyeReadThread = std::make_shared<ViveProEyeReadThread>();            connect(_viveProEyeReadThread.get(), &QThread::started, [] { setThreadName("ViveProEyeReadThread"); });            _viveProEyeReadThread->start(QThread::HighPriority);        }    }#endif     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; #ifdef VIVE_PRO_EYE    if (_viveProEyeReadThread) {        _viveProEyeReadThread->quit = true;        _viveProEyeReadThread->wait();        _viveProEyeReadThread = nullptr;        ViveSR::anipal::Release(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE);    }#endif     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;} #ifdef VIVE_PRO_EYEvoid ViveControllerManager::invalidateEyeInputs() {    _inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false;    _inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false;    _inputDevice->_axisStateMap[controller::EYEBLINK_L].valid = false;    _inputDevice->_axisStateMap[controller::EYEBLINK_R].valid = false;} void ViveControllerManager::updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {    if (!isHeadControllerMounted()) {        invalidateEyeInputs();        return;    }     EyeDataBuffer eyeDataBuffer;    {        // GetEyeData takes around 4ms to finish, so we run it on a thread.        QMutexLocker locker(&_viveProEyeReadThread->eyeDataMutex);        memcpy(&eyeDataBuffer, &_viveProEyeReadThread->eyeDataBuffer, sizeof(eyeDataBuffer));    }     if (eyeDataBuffer.getEyeDataResult != ViveSR::Error::WORK) {        invalidateEyeInputs();        return;    }     // only update from buffer values if the new data is "valid"    if (!eyeDataBuffer.leftDirectionValid) {        eyeDataBuffer.leftEyeGaze = _prevEyeData.leftEyeGaze;        eyeDataBuffer.leftDirectionValid = _prevEyeData.leftDirectionValid;    }    if (!eyeDataBuffer.rightDirectionValid) {        eyeDataBuffer.rightEyeGaze = _prevEyeData.rightEyeGaze;        eyeDataBuffer.rightDirectionValid = _prevEyeData.rightDirectionValid;    }    if (!eyeDataBuffer.leftOpennessValid) {        eyeDataBuffer.leftEyeOpenness = _prevEyeData.leftEyeOpenness;        eyeDataBuffer.leftOpennessValid = _prevEyeData.leftOpennessValid;    }    if (!eyeDataBuffer.rightOpennessValid) {        eyeDataBuffer.rightEyeOpenness = _prevEyeData.rightEyeOpenness;        eyeDataBuffer.rightOpennessValid = _prevEyeData.rightOpennessValid;    }    _prevEyeData = eyeDataBuffer;     // transform data into what the controller system expects. 

Lines 1–500 of 2097.