void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN _poseStateMap.clear(); // TODO: This shouldn't be necessary if (!_hmd) { return; } _buttonPressedMap.clear(); PerformanceTimer perfTimer("ViveControllerManager::update"); int numTrackedControllers = 0; for (vr::TrackedDeviceIndex_t device = vr::k_unTrackedDeviceIndex_Hmd + 1; device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) { if (!_hmd->IsTrackedDeviceConnected(device)) { continue; } if(_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) { continue; } if (!_trackedDevicePose[device].bPoseIsValid) { continue; } numTrackedControllers++; const mat4& mat = _trackedDevicePoseMat4[device]; if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } // handle inputs vr::VRControllerState_t controllerState = vr::VRControllerState_t(); if (_hmd->GetControllerState(device, &controllerState)) { //qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: "); //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; handleButtonEvent(controllerState.ulButtonPressed, numTrackedControllers - 1); for (int i = 0; i < vr::k_unControllerStateAxisCount; i++) { handleAxisEvent(Axis(i), controllerState.rAxis[i].x, controllerState.rAxis[i].y, numTrackedControllers - 1); } } } auto userInputMapper = DependencyManager::get<UserInputMapper>(); if (numTrackedControllers == 0) { if (_deviceID != 0) { userInputMapper->removeDevice(_deviceID); _deviceID = 0; _poseStateMap.clear(); } } if (_trackedControllers == 0 && numTrackedControllers > 0) { registerToUserInputMapper(*userInputMapper); assignDefaultInputMapping(*userInputMapper); UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR"); } _trackedControllers = numTrackedControllers; #endif }
void SixenseManager::update(float deltaTime) { #ifdef HAVE_SIXENSE Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand(); if (_isInitialized && _isEnabled) { _buttonPressedMap.clear(); #ifdef __APPLE__ SixenseBaseFunction sixenseGetNumActiveControllers = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); #endif if (sixenseGetNumActiveControllers() == 0) { _hydrasConnected = false; if (_deviceID != 0) { Application::getUserInputMapper()->removeDevice(_deviceID); _deviceID = 0; if (_prevPalms[0]) { _prevPalms[0]->setActive(false); } if (_prevPalms[1]) { _prevPalms[1]->setActive(false); } } return; } PerformanceTimer perfTimer("sixense"); if (!_hydrasConnected) { _hydrasConnected = true; registerToUserInputMapper(*Application::getUserInputMapper()); getInstance().assignDefaultInputMapping(*Application::getUserInputMapper()); UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); } #ifdef __APPLE__ SixenseBaseFunction sixenseGetMaxControllers = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); #endif int maxControllers = sixenseGetMaxControllers(); // we only support two controllers sixenseControllerData controllers[2]; #ifdef __APPLE__ SixenseTakeIntFunction sixenseIsControllerEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); #endif int numControllersAtBase = 0; int numActiveControllers = 0; for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { if (!sixenseIsControllerEnabled(i)) { continue; } sixenseControllerData* data = controllers + numActiveControllers; ++numActiveControllers; sixenseGetNewestData(i, data); // Set palm position and normal based on Hydra position/orientation // Either find a palm matching the sixense controller, or make a new one PalmData* palm; bool foundHand = false; for (size_t j = 0; j < hand->getNumPalms(); j++) { if (hand->getPalms()[j].getSixenseID() == data->controller_index) { palm = &(hand->getPalms()[j]); _prevPalms[numActiveControllers - 1] = palm; foundHand = true; } } if (!foundHand) { PalmData newPalm(hand); hand->getPalms().push_back(newPalm); palm = &(hand->getPalms()[hand->getNumPalms() - 1]); palm->setSixenseID(data->controller_index); _prevPalms[numActiveControllers - 1] = palm; qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index); } // Disable the hands (and return to default pose) if both controllers are at base station if (foundHand) { palm->setActive(!_controllersAtBase); } else { palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive } // Read controller buttons and joystick into the hand palm->setControllerButtons(data->buttons); palm->setTrigger(data->trigger); palm->setJoystick(data->joystick_x, data->joystick_y); // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); position *= METERS_PER_MILLIMETER; // Check to see if this hand/controller is on the base const float CONTROLLER_AT_BASE_DISTANCE = 0.075f; if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) { numControllersAtBase++; palm->setActive(false); } else { handleButtonEvent(data->buttons, numActiveControllers - 1); handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1); // Emulate the mouse so we can use scripts if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { emulateMouse(palm, numActiveControllers - 1); } } // Transform the measured position into body frame. glm::vec3 neck = _neckBase; // Zeroing y component of the "neck" effectively raises the measured position a little bit. neck.y = 0.0f; position = _orbRotation * (position - neck); // Rotation of Palm glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation; // Compute current velocity from position change glm::vec3 rawVelocity; if (deltaTime > 0.0f) { rawVelocity = (position - palm->getRawPosition()) / deltaTime; } else { rawVelocity = glm::vec3(0.0f); } palm->setRawVelocity(rawVelocity); // meters/sec // adjustment for hydra controllers fit into hands float sign = (i == 0) ? -1.0f : 1.0f; rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); // Angular Velocity of Palm glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation()); glm::vec3 angularVelocity(0.0f); float rotationAngle = glm::angle(deltaRotation); if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) { angularVelocity = glm::normalize(glm::axis(deltaRotation)); angularVelocity *= (rotationAngle / deltaTime); palm->setRawAngularVelocity(angularVelocity); } else { palm->setRawAngularVelocity(glm::vec3(0.0f)); } if (_lowVelocityFilter) { // Use a velocity sensitive filter to damp small motions and preserve large ones with // no latency. float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter); rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter); palm->setRawPosition(position); palm->setRawRotation(rotation); } else { palm->setRawPosition(position); palm->setRawRotation(rotation); } // Store the one fingertip in the palm structure so we can track velocity const float FINGER_LENGTH = 0.3f; // meters const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; glm::vec3 oldTipPosition = palm->getTipRawPosition(); if (deltaTime > 0.0f) { palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime); } else { palm->setTipVelocity(glm::vec3(0.0f)); } palm->setTipPosition(newTipPosition); } if (numActiveControllers == 2) { updateCalibration(controllers); } _controllersAtBase = (numControllersAtBase == 2); } for (auto axisState : _axisStateMap) { if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { _axisStateMap[axisState.first] = 0.0f; } } #endif // HAVE_SIXENSE }