mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 07:17:43 +02:00
Merge pull request #7220 from hyperlogic/tony/vive-controller-work
OpenVR: improved controller support
This commit is contained in:
commit
9a0b91e094
2 changed files with 98 additions and 68 deletions
|
@ -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(deltaTime, leftHandDeviceIndex, inputCalibrationData, true);
|
||||||
|
handleHandController(deltaTime, 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(float deltaTime, 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(deltaTime, 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(deltaTime, 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(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_trackedControllers = numTrackedControllers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::focusOutEvent() {
|
void ViveControllerManager::InputDevice::focusOutEvent() {
|
||||||
|
@ -284,42 +284,46 @@ 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(float deltaTime, 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;
|
glm::vec2 stick(x, y);
|
||||||
_axisStateMap[left ? LY : RY] = y;
|
if (isLeftHand) {
|
||||||
|
stick = _filteredLeftStick.process(deltaTime, stick);
|
||||||
|
} else {
|
||||||
|
stick = _filteredRightStick.process(deltaTime, stick);
|
||||||
|
}
|
||||||
|
_axisStateMap[isLeftHand ? LX : RX] = stick.x;
|
||||||
|
_axisStateMap[isLeftHand ? LY : RY] = stick.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(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) {
|
||||||
if (!pressed) {
|
if (!pressed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace controller;
|
||||||
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 ? LEFT_PRIMARY_THUMB : 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 ? LB : 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 ? LT : 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 ? LS : 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(float deltaTime, 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 +388,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 +403,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 {
|
||||||
|
|
|
@ -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,20 +58,46 @@ 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(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
|
||||||
void handleAxisEvent(uint32_t axis, float x, float y, bool left);
|
void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand);
|
||||||
void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
|
||||||
const vec3& linearVelocity, const vec3& angularVelocity, bool left);
|
void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
||||||
|
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
|
||||||
|
|
||||||
|
class FilteredStick {
|
||||||
|
public:
|
||||||
|
glm::vec2 process(float deltaTime, const glm::vec2& stick) {
|
||||||
|
// Use a timer to prevent the stick going to back to zero.
|
||||||
|
// This to work around the noisy touch pad that will flash back to zero breifly
|
||||||
|
const float ZERO_HYSTERESIS_PERIOD = 0.2f; // 200 ms
|
||||||
|
if (glm::length(stick) == 0.0f) {
|
||||||
|
if (_timer <= 0.0f) {
|
||||||
|
return glm::vec2(0.0f, 0.0f);
|
||||||
|
} else {
|
||||||
|
_timer -= deltaTime;
|
||||||
|
return _stick;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_timer = ZERO_HYSTERESIS_PERIOD;
|
||||||
|
_stick = stick;
|
||||||
|
return stick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
float _timer { 0.0f };
|
||||||
|
glm::vec2 _stick { 0.0f, 0.0f };
|
||||||
|
};
|
||||||
|
|
||||||
|
FilteredStick _filteredLeftStick;
|
||||||
|
FilteredStick _filteredRightStick;
|
||||||
|
|
||||||
int _trackedControllers { 0 };
|
int _trackedControllers { 0 };
|
||||||
vr::IVRSystem*& _hmd;
|
vr::IVRSystem*& _system;
|
||||||
friend class ViveControllerManager;
|
friend class ViveControllerManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool _registeredWithInputMapper { false };
|
bool _registeredWithInputMapper { false };
|
||||||
bool _modelLoaded { false };
|
bool _modelLoaded { false };
|
||||||
model::Geometry _modelGeometry;
|
model::Geometry _modelGeometry;
|
||||||
|
@ -81,8 +107,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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue