OpenVR: More reliable detection of left and right hands

This commit is contained in:
Anthony J. Thibault 2016-02-26 14:38:35 -08:00
parent 7457b73e74
commit 01ef5aabcb
2 changed files with 61 additions and 64 deletions

View file

@ -60,10 +60,10 @@ void ViveControllerManager::activate() {
[this] (bool clicked) { this->setRenderControllers(clicked); }, [this] (bool clicked) { this->setRenderControllers(clicked); },
true, true); true, true);
if (!_hmd) { if (!_system) {
_hmd = acquireOpenVrSystem(); _system = acquireOpenVrSystem();
} }
Q_ASSERT(_hmd); Q_ASSERT(_system);
// OpenVR provides 3d mesh representations of the controllers // OpenVR provides 3d mesh representations of the controllers
// Disabled controller rendering code // Disabled controller rendering code
@ -71,7 +71,7 @@ void ViveControllerManager::activate() {
auto renderModels = vr::VRRenderModels(); auto renderModels = vr::VRRenderModels();
vr::RenderModel_t model; vr::RenderModel_t model;
if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { if (!_system->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) {
qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING);
} else { } else {
model::Mesh* mesh = new model::Mesh(); model::Mesh* mesh = new model::Mesh();
@ -118,7 +118,7 @@ void ViveControllerManager::activate() {
} }
*/ */
// unregister with UserInputMapper // register with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
userInputMapper->registerDevice(_inputDevice); userInputMapper->registerDevice(_inputDevice);
_registeredWithInputMapper = true; _registeredWithInputMapper = true;
@ -130,9 +130,9 @@ void ViveControllerManager::deactivate() {
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
_container->removeMenu(MENU_PATH); _container->removeMenu(MENU_PATH);
if (_hmd) { if (_system) {
releaseOpenVrSystem(); releaseOpenVrSystem();
_hmd = nullptr; _system = nullptr;
} }
_inputDevice->_poseStateMap.clear(); _inputDevice->_poseStateMap.clear();
@ -226,56 +226,56 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
_poseStateMap.clear(); _poseStateMap.clear();
_buttonPressedMap.clear(); _buttonPressedMap.clear();
PerformanceTimer perfTimer("ViveControllerManager::update"); PerformanceTimer perfTimer("ViveControllerManager::update");
auto leftHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand);
auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);
if (!jointsCaptured) {
handleHandController(leftHandDeviceIndex, inputCalibrationData, true);
handleHandController(rightHandDeviceIndex, inputCalibrationData, false);
}
int numTrackedControllers = 0; int numTrackedControllers = 0;
if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
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++; numTrackedControllers++;
bool left = numTrackedControllers == 2; }
if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
numTrackedControllers++;
}
_trackedControllers = numTrackedControllers;
}
if (!jointsCaptured) { void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) {
const mat4& mat = _trackedDevicePoseMat4[device];
const vec3 linearVelocity = _trackedDeviceLinearVelocities[device]; if (_system->IsTrackedDeviceConnected(deviceIndex) &&
const vec3 angularVelocity = _trackedDeviceAngularVelocities[device]; _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller &&
handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, numTrackedControllers - 1); _trackedDevicePose[deviceIndex].bPoseIsValid) {
}
// process pose
const mat4& mat = _trackedDevicePoseMat4[deviceIndex];
const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex];
const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex];
handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand);
// handle inputs
vr::VRControllerState_t controllerState = vr::VRControllerState_t(); vr::VRControllerState_t controllerState = vr::VRControllerState_t();
if (_hmd->GetControllerState(device, &controllerState)) { if (_system->GetControllerState(deviceIndex, &controllerState)) {
//qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: ");
//qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; // process each button
//qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y;
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
bool pressed = 0 != (controllerState.ulButtonPressed & mask); bool pressed = 0 != (controllerState.ulButtonPressed & mask);
handleButtonEvent(i, pressed, left); handleButtonEvent(i, pressed, isLeftHand);
} }
// process each axis
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand);
} }
} }
} }
_trackedControllers = numTrackedControllers;
} }
void ViveControllerManager::InputDevice::focusOutEvent() { void ViveControllerManager::InputDevice::focusOutEvent() {
@ -284,42 +284,38 @@ void ViveControllerManager::InputDevice::focusOutEvent() {
}; };
// These functions do translation from the Steam IDs to the standard controller IDs // These functions do translation from the Steam IDs to the standard controller IDs
void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) { void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand) {
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs //FIX ME? It enters here every frame: probably we want to enter only if an event occurs
axis += vr::k_EButton_Axis0; axis += vr::k_EButton_Axis0;
using namespace controller; using namespace controller;
if (axis == vr::k_EButton_SteamVR_Touchpad) { if (axis == vr::k_EButton_SteamVR_Touchpad) {
_axisStateMap[left ? LX : RX] = x; _axisStateMap[isLeftHand ? LX : RX] = x;
_axisStateMap[left ? LY : RY] = y; _axisStateMap[isLeftHand ? LY : RY] = y;
} else if (axis == vr::k_EButton_SteamVR_Trigger) { } else if (axis == vr::k_EButton_SteamVR_Trigger) {
_axisStateMap[left ? LT : RT] = x; _axisStateMap[isLeftHand ? LT : RT] = x;
} }
} }
// These functions do translation from the Steam IDs to the standard controller IDs // These functions do translation from the Steam IDs to the standard controller IDs
void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) { void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand) {
if (!pressed) { if (!pressed) {
return; return;
} }
if (button == vr::k_EButton_ApplicationMenu) { if (button == vr::k_EButton_ApplicationMenu) {
_buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); _buttonPressedMap.insert(isLeftHand ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB);
} else if (button == vr::k_EButton_Grip) { } else if (button == vr::k_EButton_Grip) {
// Tony says these are harder to reach, so make them the meta buttons _buttonPressedMap.insert(isLeftHand ? controller::LB : controller::RB);
_buttonPressedMap.insert(left ? controller::LB : controller::RB);
} else if (button == vr::k_EButton_SteamVR_Trigger) { } else if (button == vr::k_EButton_SteamVR_Trigger) {
_buttonPressedMap.insert(left ? controller::LT : controller::RT); _buttonPressedMap.insert(isLeftHand ? controller::LT : controller::RT);
} else if (button == vr::k_EButton_SteamVR_Touchpad) { } else if (button == vr::k_EButton_SteamVR_Touchpad) {
_buttonPressedMap.insert(left ? controller::LS : controller::RS); _buttonPressedMap.insert(isLeftHand ? controller::LS : controller::RS);
} else if (button == vr::k_EButton_System) {
//FIX ME: not able to ovrewrite the behaviour of this button
_buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB);
} }
} }
void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData,
const mat4& mat, const vec3& linearVelocity, const mat4& mat, const vec3& linearVelocity,
const vec3& angularVelocity, bool left) { const vec3& angularVelocity, bool isLeftHand) {
// When the sensor-to-world rotation is identity the coordinate axes look like this: // When the sensor-to-world rotation is identity the coordinate axes look like this:
// //
// user // user
@ -384,8 +380,8 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
auto translationOffset = (left ? leftTranslationOffset : rightTranslationOffset); auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset);
auto rotationOffset = (left ? leftRotationOffset : rightRotationOffset); auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset);
glm::vec3 position = extractTranslation(mat); glm::vec3 position = extractTranslation(mat);
glm::quat rotation = glm::normalize(glm::quat_cast(mat)); glm::quat rotation = glm::normalize(glm::quat_cast(mat));
@ -399,7 +395,7 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
// handle change in velocity due to translationOffset // handle change in velocity due to translationOffset
avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat)); avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat));
avatarPose.angularVelocity = angularVelocity; avatarPose.angularVelocity = angularVelocity;
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar);
} }
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const { controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {

View file

@ -50,7 +50,7 @@ public:
private: private:
class InputDevice : public controller::InputDevice { class InputDevice : public controller::InputDevice {
public: public:
InputDevice(vr::IVRSystem*& hmd) : controller::InputDevice("Vive"), _hmd(hmd) {} InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {}
private: private:
// Device functions // Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override; virtual controller::Input::NamedVector getAvailableInputs() const override;
@ -58,13 +58,14 @@ private:
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void focusOutEvent() override; virtual void focusOutEvent() override;
void handleButtonEvent(uint32_t button, bool pressed, bool left); void handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
void handleAxisEvent(uint32_t axis, float x, float y, bool left); void handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand);
void handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand);
void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
const vec3& linearVelocity, const vec3& angularVelocity, bool left); const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
int _trackedControllers { 0 }; int _trackedControllers { 0 };
vr::IVRSystem*& _hmd; vr::IVRSystem*& _system;
friend class ViveControllerManager; friend class ViveControllerManager;
}; };
@ -81,8 +82,8 @@ private:
int _rightHandRenderID { 0 }; int _rightHandRenderID { 0 };
bool _renderControllers { false }; bool _renderControllers { false };
vr::IVRSystem* _hmd { nullptr }; vr::IVRSystem* _system { nullptr };
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_hmd) }; std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
static const QString NAME; static const QString NAME;