From 702da3a663372e1a477dee5fdff77a979cc8b9d5 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Thu, 14 Nov 2019 10:32:26 -0800 Subject: [PATCH] Making Oculus Quest support haptic feedback. --- .../oculusvr/cpp/DeviceDelegateOculusVR.cpp | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp index cab14b47d..624205a24 100644 --- a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp +++ b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp @@ -644,6 +644,9 @@ struct DeviceDelegateOculusVR::State { ovrInputTrackedRemoteCapabilities capabilities = {}; vrb::Matrix transform = vrb::Matrix::Identity(); ovrInputStateTrackedRemote inputState = {}; + uint64_t inputFrameID = 0; + float remainingVibrateTime = 0.0f; + double lastHapticUpdateTimeStamp = 0.0f; bool Is6DOF() const { return (capabilities.ControllerCapabilities & ovrControllerCaps_HasPositionTracking) && @@ -689,7 +692,6 @@ struct DeviceDelegateOculusVR::State { device::CPULevel minCPULevel = device::CPULevel::Normal; device::DeviceType deviceType = device::UnknownType; - void UpdatePerspective() { float fovX = vrapi_GetSystemPropertyFloat(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X); float fovY = vrapi_GetSystemPropertyFloat(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y); @@ -965,6 +967,16 @@ struct DeviceDelegateOculusVR::State { } } + double GetTimeStamp() { + timespec spec = {}; + const double kNanosecondsToSeconds = 1.0e9; + double timeStamp = 0.0f; + if (clock_gettime(CLOCK_MONOTONIC, &spec) == 0) { + timeStamp = (double) spec.tv_sec + (spec.tv_nsec / kNanosecondsToSeconds); + } + return timeStamp; + } + void UpdateControllers(const vrb::Matrix & head) { UpdateDeviceId(); if (!controller) { @@ -1034,7 +1046,6 @@ struct DeviceDelegateOculusVR::State { const bool yTouched = (controllerState.inputState.Touches & ovrTouch_Y) != 0; const bool menuPressed = (controllerState.inputState.Buttons & ovrButton_Enter) != 0; - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_X, 3, xPressed, xTouched); controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_Y, 4, yPressed, yTouched); @@ -1061,6 +1072,46 @@ struct DeviceDelegateOculusVR::State { const bool thumbRest = (controllerState.inputState.Touches & ovrTouch_ThumbUp) != 0; controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_OTHERS, 5, thumbRest, thumbRest); + + // Only Oculus 6 DOF (Quest) has haptic feedback. + controller->SetHapticCount(controllerState.index, 1); + uint64_t inputFrameID = 0; + float pulseDuration = 0.0f, pulseIntensity = 0.0f; + controller->GetHapticFeedback(controllerState.index, inputFrameID, pulseDuration, pulseIntensity); + if (inputFrameID > 0 && pulseIntensity > 0.0f && pulseDuration > 0) { + if (controllerState.inputFrameID != inputFrameID) { + // When there is a new input frame id from haptic vibration, + // that means we start a new session for a vibration. + controllerState.inputFrameID = inputFrameID; + controllerState.remainingVibrateTime = pulseDuration; + controllerState.lastHapticUpdateTimeStamp = GetTimeStamp(); + } else { + // We are still running the previous vibration. + // So, it needs to reduce the delta time from the last vibration. + const double timeStamp = GetTimeStamp(); + controllerState.remainingVibrateTime -= (timeStamp - controllerState.lastHapticUpdateTimeStamp); + controllerState.lastHapticUpdateTimeStamp = timeStamp; + } + if (controllerState.remainingVibrateTime > 0.0f) { + if (vrapi_SetHapticVibrationSimple(ovr, controllerState.index, pulseIntensity > 1.0f ? 1.0f : pulseIntensity) + == ovrError_InvalidOperation) { + VRB_ERROR("vrapi_SetHapticVibrationBuffer failed."); + } + } else { + // The remaining time is zero, stop the vibration. + if (vrapi_SetHapticVibrationSimple(ovr, controllerState.index, 0.0f) == ovrError_InvalidOperation) { + VRB_ERROR("vrapi_SetHapticVibrationBuffer failed."); + } + controllerState.remainingVibrateTime = 0.0f; + } + } else if (controllerState.remainingVibrateTime > 0.0f) { + // While the haptic feedback is terminated from the client side, + // but it still have remaining time, we need to ask for stopping vibration. + if (vrapi_SetHapticVibrationSimple(ovr, controllerState.index, 0.0f) == ovrError_InvalidOperation) { + VRB_ERROR("vrapi_SetHapticVibrationBuffer failed."); + } + controllerState.remainingVibrateTime = 0.0f; + } } else { triggerPressed = (controllerState.inputState.Buttons & ovrButton_A) != 0; triggerTouched = triggerPressed; @@ -1084,6 +1135,9 @@ struct DeviceDelegateOculusVR::State { } axes[0] = trackpadTouched ? trackpadX * 2.0f - 1.0f : 0.0f; axes[1] = trackpadTouched ? trackpadY * 2.0f - 1.0f : 0.0f; + + // Oculus Go has no haptic feedback. + controller->SetHapticCount(controllerState.index, 0); } controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_TRIGGER, 1, triggerPressed, triggerTouched, controllerState.inputState.IndexTrigger);