Seth Alvescleanups552b69b9 years agoHistory
661 lines · 22.6 KB · C++
RawDownload
////  KinectPlugin.cpp////  Created by Brad Hefta-Gaub on 2016/12/7//  Copyright 2016 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 "KinectPlugin.h" #include <controllers/UserInputMapper.h>#include <QLoggingCategory>#include <PathUtils.h>#include <DebugDraw.h>#include <cassert>#include <NumericalConstants.h>#include <StreamUtils.h>#include <Preferences.h>#include <SettingHandle.h> Q_DECLARE_LOGGING_CATEGORY(inputplugins)Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const char* KinectPlugin::NAME = "Kinect";const char* KinectPlugin::KINECT_ID_STRING = "Kinect"; QStringList kinectJointNames = {    "SpineBase",    "SpineMid",    "Neck",    "Head",    "ShoulderLeft",    "ElbowLeft",    "WristLeft",    "HandLeft",    "ShoulderRight",    "ElbowRight",    "WristRight",    "HandRight",    "HipLeft",    "KneeLeft",    "AnkleLeft",    "FootLeft",    "HipRight",    "KneeRight",    "AnkleRight",    "FootRight",    "SpineShoulder",    "HandTipLeft",    "ThumbLeft",    "HandTipRight",    "ThumbRight"}; const bool DEFAULT_ENABLED = false; enum KinectJointIndex {    SpineBase = 0,    SpineMid,    Neck,    Head,     ShoulderLeft,    ElbowLeft,    WristLeft,    HandLeft,     ShoulderRight,    ElbowRight,    WristRight,    HandRight,     HipLeft,    KneeLeft,    AnkleLeft,    FootLeft,     HipRight,    KneeRight,    AnkleRight,    FootRight,     SpineShoulder,     HandTipLeft,    ThumbLeft,     HandTipRight,    ThumbRight,     Size}; #define UNKNOWN_JOINT (controller::StandardPoseChannel)0  static controller::StandardPoseChannel KinectJointIndexToPoseIndexMap[KinectJointIndex::Size] = {    controller::HIPS,    controller::SPINE,    controller::NECK,    controller::HEAD,     controller::LEFT_SHOULDER,    controller::LEFT_ARM,    controller::LEFT_FORE_ARM,    controller::LEFT_HAND,     controller::RIGHT_SHOULDER,    controller::RIGHT_ARM,    controller::RIGHT_FORE_ARM,    controller::RIGHT_HAND,     controller::LEFT_UP_LEG,   // hip socket    controller::LEFT_LEG,      // knee?    controller::LEFT_FOOT,     // ankle?    UNKNOWN_JOINT,              // ????     controller::RIGHT_UP_LEG,   // hip socket    controller::RIGHT_LEG,      // knee?    controller::RIGHT_FOOT,     // ankle?    UNKNOWN_JOINT,              // ????     UNKNOWN_JOINT, /* SpineShoulder */     controller::LEFT_HAND_INDEX4,    controller::LEFT_HAND_THUMB4,     controller::RIGHT_HAND_INDEX4,    controller::RIGHT_HAND_THUMB4,}; // in rig framestatic glm::vec3 rightHandThumb1DefaultAbsTranslation(-2.155500650405884, -0.7610001564025879, 2.685631036758423);static glm::vec3 leftHandThumb1DefaultAbsTranslation(2.1555817127227783, -0.7603635787963867, 2.6856393814086914); static controller::StandardPoseChannel KinectJointIndexToPoseIndex(KinectJointIndex i) {    assert(i >= 0 && i < KinectJointIndex::Size);    if (i >= 0 && i < KinectJointIndex::Size) {        return KinectJointIndexToPoseIndexMap[i];    } else {        return UNKNOWN_JOINT; // not sure what to do here, but don't crash!    }} QStringList controllerJointNames = {    "Hips",    "RightUpLeg",    "RightLeg",    "RightFoot",    "LeftUpLeg",    "LeftLeg",    "LeftFoot",    "Spine",    "Spine1",    "Spine2",    "Spine3",    "Neck",    "Head",    "RightShoulder",    "RightArm",    "RightForeArm",    "RightHand",    "RightHandThumb1",    "RightHandThumb2",    "RightHandThumb3",    "RightHandThumb4",    "RightHandIndex1",    "RightHandIndex2",    "RightHandIndex3",    "RightHandIndex4",    "RightHandMiddle1",    "RightHandMiddle2",    "RightHandMiddle3",    "RightHandMiddle4",    "RightHandRing1",    "RightHandRing2",    "RightHandRing3",    "RightHandRing4",    "RightHandPinky1",    "RightHandPinky2",    "RightHandPinky3",    "RightHandPinky4",    "LeftShoulder",    "LeftArm",    "LeftForeArm",    "LeftHand",    "LeftHandThumb1",    "LeftHandThumb2",    "LeftHandThumb3",    "LeftHandThumb4",    "LeftHandIndex1",    "LeftHandIndex2",    "LeftHandIndex3",    "LeftHandIndex4",    "LeftHandMiddle1",    "LeftHandMiddle2",    "LeftHandMiddle3",    "LeftHandMiddle4",    "LeftHandRing1",    "LeftHandRing2",    "LeftHandRing3",    "LeftHandRing4",    "LeftHandPinky1",    "LeftHandPinky2",    "LeftHandPinky3",    "LeftHandPinky4"}; static const char* getControllerJointName(controller::StandardPoseChannel i) {    if (i >= 0 && i < controller::NUM_STANDARD_POSES) {        return qPrintable(controllerJointNames[i]);    }    return "unknown";} //// KinectPlugin//void KinectPlugin::init() {    loadSettings();     auto preferences = DependencyManager::get<Preferences>();    static const QString KINECT_PLUGIN { "Kinect" };    {        auto getter = [this]()->bool { return _enabled; };        auto setter = [this](bool value) {             _enabled = value;             saveSettings();             if (!_enabled) {                auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();                userInputMapper->withLock([&, this]() {                    _inputDevice->clearState();                });            }        };        auto preference = new CheckPreference(KINECT_PLUGIN, "Enabled", getter, setter);        preferences->addPreference(preference);    }    {        auto debugGetter = [this]()->bool { return _debug; };        auto debugSetter = [this](bool value) {            _debug = value;            saveSettings();        };        auto preference = new CheckPreference(KINECT_PLUGIN, "Extra Debugging", debugGetter, debugSetter);        preferences->addPreference(preference);    }} bool KinectPlugin::isSupported() const {    bool supported = false;#ifdef HAVE_KINECT    supported = initializeDefaultSensor();#endif    return supported;} bool KinectPlugin::activate() {    InputPlugin::activate();     loadSettings();     if (_enabled) {         // register with userInputMapper        auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();        userInputMapper->registerDevice(_inputDevice);         return initializeDefaultSensor();    }    return false;} bool KinectPlugin::isHandController() const {    bool sensorAvailable = false;#ifdef HAVE_KINECT    if (_kinectSensor) {        BOOLEAN sensorIsAvailable = FALSE;        HRESULT hr = _kinectSensor->get_IsAvailable(&sensorIsAvailable);        sensorAvailable = SUCCEEDED(hr) && (sensorIsAvailable == TRUE);    }#endif    return _enabled && _initialized && sensorAvailable;} bool KinectPlugin::isHeadController() const {    return isHandController();}  bool KinectPlugin::initializeDefaultSensor() const {#ifdef HAVE_KINECT    if (_initialized) {        return true;    }     HRESULT hr;     hr = GetDefaultKinectSensor(&_kinectSensor);    if (FAILED(hr)) {        return false;    }     if (_kinectSensor) {        // Initialize the Kinect and get coordinate mapper and the body reader        IBodyFrameSource* bodyFrameSource = NULL;         hr = _kinectSensor->Open();         if (SUCCEEDED(hr)) {            hr = _kinectSensor->get_CoordinateMapper(&_coordinateMapper);        }         if (SUCCEEDED(hr)) {            hr = _kinectSensor->get_BodyFrameSource(&bodyFrameSource);        }         if (SUCCEEDED(hr)) {            hr = bodyFrameSource->OpenReader(&_bodyFrameReader);        }         SafeRelease(bodyFrameSource);    }     if (!_kinectSensor || FAILED(hr)) {        return false;    }     _initialized = true;    return true;#else    return false;#endif} void KinectPlugin::updateBody() {#ifndef HAVE_KINECT    return;#else    if (!_bodyFrameReader) {        return;    }     IBodyFrame* pBodyFrame = NULL;     HRESULT hr = _bodyFrameReader->AcquireLatestFrame(&pBodyFrame);     if (SUCCEEDED(hr)) {        INT64 nTime = 0;        hr = pBodyFrame->get_RelativeTime(&nTime);        IBody* bodies[BODY_COUNT] = {0};        if (SUCCEEDED(hr)) {            hr = pBodyFrame->GetAndRefreshBodyData(_countof(bodies), bodies);        }         if (SUCCEEDED(hr)) {            ProcessBody(nTime, BODY_COUNT, bodies);        }         for (int i = 0; i < _countof(bodies); ++i) {            SafeRelease(bodies[i]);        }    }     SafeRelease(pBodyFrame);#endif} #ifdef HAVE_KINECTvoid KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) {    bool foundOneBody = false;    if (_coordinateMapper) {        for (int i = 0; i < bodyCount; ++i) {            if (foundOneBody) {                break;            }            IBody* body = bodies[i];            if (body) {                BOOLEAN tracked = false;                HRESULT hr = body->get_IsTracked(&tracked);                 if (SUCCEEDED(hr) && tracked) {                    foundOneBody = true;                     if (_joints.size() != JointType_Count) {                        _joints.resize(JointType_Count, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } });                    }                     Joint joints[JointType_Count];                    JointOrientation jointOrientations[JointType_Count];                    HandState leftHandState = HandState_Unknown;                    HandState rightHandState = HandState_Unknown;                     body->get_HandLeftState(&leftHandState);                    body->get_HandRightState(&rightHandState);                     hr = body->GetJoints(_countof(joints), joints);                    hr = body->GetJointOrientations(_countof(jointOrientations), jointOrientations);                     if (SUCCEEDED(hr)) {                        auto jointCount = _countof(joints);                        if (_debug) {                            qDebug() << __FUNCTION__ << "nBodyCount:" << bodyCount << "body:" << i << "jointCount:" << jointCount;                        }                                                for (int j = 0; j < jointCount; ++j) {                             glm::vec3 jointPosition { joints[j].Position.X,                                                      joints[j].Position.Y,                                                      joints[j].Position.Z };                             // This is the rotation in the kinect camera/sensor frame... we adjust that in update...                            // NOTE: glm::quat(W!!!, x, y, z)... not (x,y,z,w)!!!                            glm::quat jointOrientation { jointOrientations[j].Orientation.w,                                                         jointOrientations[j].Orientation.x,                                                         jointOrientations[j].Orientation.y,                                                         jointOrientations[j].Orientation.z };                             if (_debug) {                                QString jointName = kinectJointNames[joints[j].JointType];                                qDebug() << __FUNCTION__ << "joint[" << j << "]:" << jointName                                        << "position:" << jointPosition                                        << "orientation:" << jointOrientation                                        << "isTracked:" << (joints[j].TrackingState != TrackingState_NotTracked);                            }                             // filling in the _joints data...                            if (joints[j].TrackingState != TrackingState_NotTracked) {                                _joints[j].position = jointPosition;                                 // Kinect Documentation...                                //                                // https://social.msdn.microsoft.com/Forums/en-US/31c9aff6-7dab-433d-9af9-59942dfd3d69/kinect-v20-preview-sdk-jointorientation-vs-boneorientation?forum=kinectv2sdk                                // seems to suggest these are absolute...                                //    "These quaternions are absolute, so you can take a mesh in local space, transform it by the quaternion,                                 //    and it will match the exact orientation of the bone.  If you want relative orientation quaternion, you                                 //    can multiply the absolute quaternion by the inverse of the parent joint's quaternion."                                //                                // This is consistent with our findings, but does not include "enough information"                                //  - Bone direction(Y green) - always matches the skeleton.                                //  - Normal(Z blue) - joint roll, perpendicular to the bone                                //  - Binormal(X orange) - perpendicular to the bone and normal                                 // NOTE: Common notation of vectors on paper...                                //     (+) is the back of the arrow - this vector is pointing into the page                                //     (o) is the point of the arrow - this vector is pointing out of the page                                //                                 // From ABOVE the kinect coordinate frame looks like this:                                //                                //   Assuming standing facing the kinect camera                                //   Right Hand with fingers pointing up (green/y)                                //                   thumb pointing behind body (blue/z)                                //                   palm facing the head (point out back of my hand, red/x)                                //                                //   The identity rotation relative to the cameras frame... (the joint data from SDK)                                //                                //              y        | | | |                                //              |        | | | |                                //              |        |     |                                //        z----(o)     \ |right|                                //                x     \_     |                                //                        |   |                                //                        |   |                                //                                  //   Expected... identity rotation for left hand..... [to be verified]                                //   Left Hand with fingers pointing up (green/y)                                //                   thumb pointing forward (blue/z)                                //                   palm facing outward away from head (point out back of my hand, red/x)                                //                                // Our desired coordinate system...                                 //     "the local coordinate of the palm in our system"...                                //                                // From ABOVE the hand canonical axes look like this:                                //                                //                                //      | | | |          y        | | | |                                //      | | | |          |        | | | |                                //      |     |          |        |     |                                //      |left | /  x----(+)     \ |right|                                //      |     _/           z     \_     |                                //       |   |                     |   |                                //       |   |                     |   |                                //                                // Right hand rule... make the hitch hiking sign...                                //     thumb points in direction of the axis you want to rotate around                                //     fisted fingers curl in positive rotation direction....                                //                                // To transform from Kinect to our RIGHT Hand.... Negative 90 deg around Y                                //                                 // FIXME -- Double check if JointType_HandRight vs JointType_WristRight is actually                                 //          the joint we want to be using!!                                //                                 //_joints[j].orientation = jointOrientation;                                if (joints[j].JointType == JointType_HandRight) {                                    static const quat kinectToHandRight = glm::angleAxis(-PI / 2.0f, Vectors::UNIT_Y);                                    // add moving average of orientation quaternion                                     glm::quat jointSample = jointOrientation * kinectToHandRight;

Lines 1–500 of 661.