Merge pull request #13314 from jherico/feature/oculus_update

Update Oculus integration
This commit is contained in:
Sam Gateau 2018-06-07 11:45:31 -07:00 committed by GitHub
commit c53a15ec78
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 359 additions and 357 deletions

View file

@ -17,8 +17,8 @@ if (WIN32)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL https://static.oculus.com/sdk-downloads/1.11.0/Public/1486063832/ovr_sdk_win_1.11.0_public.zip URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.26.0_public.zip
URL_MD5 ea484403757cbfdfa743b6577fb1f9d2 URL_MD5 06804ff9727b910dcd04a37c800053b5
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibOVRCMakeLists.txt" <SOURCE_DIR>/CMakeLists.txt PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibOVRCMakeLists.txt" <SOURCE_DIR>/CMakeLists.txt
LOG_DOWNLOAD 1 LOG_DOWNLOAD 1

View file

@ -4,7 +4,7 @@ project(LibOVR)
include_directories(LibOVR/Include LibOVR/Src) include_directories(LibOVR/Include LibOVR/Src)
file(GLOB HEADER_FILES LibOVR/Include/*.h) file(GLOB HEADER_FILES LibOVR/Include/*.h)
file(GLOB EXTRA_HEADER_FILES LibOVR/Include/Extras/*.h) file(GLOB EXTRA_HEADER_FILES LibOVR/Include/Extras/*.h)
file(GLOB_RECURSE SOURCE_FILES LibOVR/Src/*.c LibOVR/Src/*.cpp) file(GLOB_RECURSE SOURCE_FILES LibOVR/Shim/*.c LibOVR/Shim/*.cpp)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOVR_BUILD_DEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOVR_BUILD_DEBUG")
add_library(LibOVR STATIC ${SOURCE_FILES} ${HEADER_FILES} ${EXTRA_HEADER_FILES}) add_library(LibOVR STATIC ${SOURCE_FILES} ${HEADER_FILES} ${EXTRA_HEADER_FILES})
set_target_properties(LibOVR PROPERTIES DEBUG_POSTFIX "d") set_target_properties(LibOVR PROPERTIES DEBUG_POSTFIX "d")

View file

@ -15,19 +15,25 @@
#include "OculusHelpers.h" #include "OculusHelpers.h"
using namespace hifi;
void OculusBaseDisplayPlugin::resetSensors() { void OculusBaseDisplayPlugin::resetSensors() {
ovr_RecenterTrackingOrigin(_session); ovr_RecenterTrackingOrigin(_session);
_currentRenderFrameInfo.renderPose = glm::mat4(); // identity _currentRenderFrameInfo.renderPose = glm::mat4(); // identity
} }
bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
handleOVREvents(); ovrSessionStatus status{};
if (quitRequested()) { if (!OVR_SUCCESS(ovr_GetSessionStatus(_session, &status))) {
qCWarning(oculusLog) << "Unable to fetch Oculus session status" << ovr::getError();
return false;
}
if (ovr::quitRequested(status)) {
QMetaObject::invokeMethod(qApp, "quit"); QMetaObject::invokeMethod(qApp, "quit");
return false; return false;
} }
if (reorientRequested()) { if (ovr::reorientRequested(status)) {
emit resetSensorsRequested(); emit resetSensorsRequested();
} }
@ -35,18 +41,18 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
_currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
_currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); _currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue); auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue);
_currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.renderPose = ovr::toGlm(trackingState.HeadPose.ThePose);
_currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose; _currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose;
std::array<glm::mat4, 2> handPoses; std::array<glm::mat4, 2> handPoses;
// Make controller poses available to the presentation thread // Make controller poses available to the presentation thread
ovr_for_each_hand([&](ovrHandType hand) { ovr::for_each_hand([&](ovrHandType hand) {
static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked | ovrStatus_PositionTracked; static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked | ovrStatus_PositionTracked;
if (REQUIRED_HAND_STATUS != (trackingState.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) { if (REQUIRED_HAND_STATUS != (trackingState.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) {
return; return;
} }
auto correctedPose = ovrControllerPoseToHandPose(hand, trackingState.HandPoses[hand]); auto correctedPose = ovr::toControllerPose(hand, trackingState.HandPoses[hand]);
static const glm::quat HAND_TO_LASER_ROTATION = glm::rotation(Vectors::UNIT_Z, Vectors::UNIT_NEG_Y); static const glm::quat HAND_TO_LASER_ROTATION = glm::rotation(Vectors::UNIT_Z, Vectors::UNIT_NEG_Y);
handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION); handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION);
}); });
@ -58,7 +64,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
} }
bool OculusBaseDisplayPlugin::isSupported() const { bool OculusBaseDisplayPlugin::isSupported() const {
return oculusAvailable(); return ovr::available();
} }
glm::mat4 OculusBaseDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const { glm::mat4 OculusBaseDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const {
@ -71,7 +77,7 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& ba
ovrFovPort fovPort = _hmdDesc.DefaultEyeFov[eye]; ovrFovPort fovPort = _hmdDesc.DefaultEyeFov[eye];
ovrEyeRenderDesc& erd = ovr_GetRenderDesc(_session, ovrEye, fovPort); ovrEyeRenderDesc& erd = ovr_GetRenderDesc(_session, ovrEye, fovPort);
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL); ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL);
return toGlm(ovrPerspectiveProjection); return ovr::toGlm(ovrPerspectiveProjection);
} else { } else {
return baseProjection; return baseProjection;
} }
@ -85,7 +91,7 @@ glm::mat4 OculusBaseDisplayPlugin::getCullingProjection(const glm::mat4& basePro
float baseFarClip = baseFrustum.getFarClip(); float baseFarClip = baseFrustum.getFarClip();
auto combinedFov = _eyeFovs[0]; auto combinedFov = _eyeFovs[0];
combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan); combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan);
return toGlm(ovrMatrix4f_Projection(combinedFov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL)); return ovr::toGlm(ovrMatrix4f_Projection(combinedFov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL));
} else { } else {
return baseProjection; return baseProjection;
} }
@ -102,7 +108,7 @@ void OculusBaseDisplayPlugin::uncustomizeContext() {
} }
bool OculusBaseDisplayPlugin::internalActivate() { bool OculusBaseDisplayPlugin::internalActivate() {
_session = acquireOculusSession(); _session = ovr::acquireRenderSession();
if (!_session) { if (!_session) {
return false; return false;
} }
@ -113,21 +119,21 @@ bool OculusBaseDisplayPlugin::internalActivate() {
_viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; _viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
_ipd = 0; _ipd = 0;
ovr_for_each_eye([&](ovrEyeType eye) { ovr::for_each_eye([&](ovrEyeType eye) {
_eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye]; _eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye];
ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_session, eye, _eyeFovs[eye]); ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_session, eye, _eyeFovs[eye]);
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL); ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL);
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection); _eyeProjections[eye] = ovr::toGlm(ovrPerspectiveProjection);
_eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeOffset)); _eyeOffsets[eye] = ovr::toGlm(erd.HmdToEyePose);
eyeSizes[eye] = toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f)); eyeSizes[eye] = ovr::toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f));
_viewScaleDesc.HmdToEyeOffset[eye] = erd.HmdToEyeOffset; _viewScaleDesc.HmdToEyePose[eye] = erd.HmdToEyePose;
_ipd += glm::abs(glm::length(toGlm(erd.HmdToEyeOffset))); _ipd += glm::abs(glm::length(ovr::toGlm(erd.HmdToEyePose.Position)));
}); });
auto combinedFov = _eyeFovs[0]; auto combinedFov = _eyeFovs[0];
combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan); combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan);
_cullingProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL)); _cullingProjection = ovr::toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL));
_renderTargetSize = uvec2( _renderTargetSize = uvec2(
eyeSizes[0].x + eyeSizes[1].x, eyeSizes[0].x + eyeSizes[1].x,
@ -136,7 +142,7 @@ bool OculusBaseDisplayPlugin::internalActivate() {
memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov)); memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov));
_sceneLayer.Header.Type = ovrLayerType_EyeFov; _sceneLayer.Header.Type = ovrLayerType_EyeFov;
_sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
ovr_for_each_eye([&](ovrEyeType eye) { ovr::for_each_eye([&](ovrEyeType eye) {
ovrFovPort & fov = _sceneLayer.Fov[eye] = _eyeRenderDescs[eye].Fov; ovrFovPort & fov = _sceneLayer.Fov[eye] = _eyeRenderDescs[eye].Fov;
ovrSizei & size = _sceneLayer.Viewport[eye].Size = ovr_GetFovTextureSize(_session, eye, fov, 1.0f); ovrSizei & size = _sceneLayer.Viewport[eye].Size = ovr_GetFovTextureSize(_session, eye, fov, 1.0f);
_sceneLayer.Viewport[eye].Pos = { eye == ovrEye_Left ? 0 : size.w, 0 }; _sceneLayer.Viewport[eye].Pos = { eye == ovrEye_Left ? 0 : size.w, 0 };
@ -150,28 +156,14 @@ bool OculusBaseDisplayPlugin::internalActivate() {
void OculusBaseDisplayPlugin::internalDeactivate() { void OculusBaseDisplayPlugin::internalDeactivate() {
Parent::internalDeactivate(); Parent::internalDeactivate();
ovr::releaseRenderSession(_session);
} }
bool OculusBaseDisplayPlugin::activateStandBySession() {
if (!_session) {
_session = acquireOculusSession();
}
return _session;
}
void OculusBaseDisplayPlugin::deactivateSession() {
// FIXME
// Switching to Qt 5.9 exposed a race condition or similar issue that caused a crash when putting on an Rift
// while already in VR mode. Commenting these out is a workaround.
//releaseOculusSession();
//_session = nullptr;
}
void OculusBaseDisplayPlugin::updatePresentPose() { void OculusBaseDisplayPlugin::updatePresentPose() {
ovrTrackingState trackingState;
_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
_currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, 0); _currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, 0);
auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse); trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse);
_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose); _currentPresentFrameInfo.presentPose = ovr::toGlm(trackingState.HeadPose.ThePose);
_currentPresentFrameInfo.renderPose = _currentPresentFrameInfo.presentPose; _currentPresentFrameInfo.renderPose = _currentPresentFrameInfo.presentPose;
} }
OculusBaseDisplayPlugin::~OculusBaseDisplayPlugin() {
}

View file

@ -16,37 +16,32 @@
class OculusBaseDisplayPlugin : public HmdDisplayPlugin { class OculusBaseDisplayPlugin : public HmdDisplayPlugin {
using Parent = HmdDisplayPlugin; using Parent = HmdDisplayPlugin;
public: public:
~OculusBaseDisplayPlugin();
bool isSupported() const override; bool isSupported() const override;
bool hasAsyncReprojection() const override { return true; }
bool getSupportsAutoSwitch() override final { return true; }
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override; glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override;
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override; glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override;
bool hasAsyncReprojection() const override { return true; }
// Stereo specific methods // Stereo specific methods
void resetSensors() override final; void resetSensors() override final;
bool beginFrameRender(uint32_t frameIndex) override; bool beginFrameRender(uint32_t frameIndex) override;
float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; } float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; }
bool getSupportsAutoSwitch() override final { return true; }
protected: protected:
void customizeContext() override; void customizeContext() override;
void uncustomizeContext() override; void uncustomizeContext() override;
bool internalActivate() override; bool internalActivate() override;
void internalDeactivate() override; void internalDeactivate() override;
bool activateStandBySession() override;
void deactivateSession() override;
void updatePresentPose() override; void updatePresentPose() override;
protected: protected:
ovrSession _session{ nullptr }; ovrSession _session{ nullptr };
ovrGraphicsLuid _luid; ovrGraphicsLuid _luid;
ovrEyeRenderDesc _eyeRenderDescs[2]; std::array<ovrEyeRenderDesc, 2> _eyeRenderDescs;
ovrFovPort _eyeFovs[2]; std::array<ovrFovPort, 2> _eyeFovs;
ovrHmdDesc _hmdDesc; ovrHmdDesc _hmdDesc;
ovrLayerEyeFov _sceneLayer; ovrLayerEyeFov _sceneLayer;
ovrViewScaleDesc _viewScaleDesc; ovrViewScaleDesc _viewScaleDesc;
// ovrLayerEyeFovDepth _depthLayer;
}; };

View file

@ -22,34 +22,23 @@
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <StreamUtils.h> #include <StreamUtils.h>
#include <OVR_CAPI.h> #include <ovr_capi.h>
#include "OculusHelpers.h" #include "OculusHelpers.h"
Q_DECLARE_LOGGING_CATEGORY(oculus) using namespace hifi;
static const char* MENU_PARENT = "Avatar";
static const char* MENU_NAME = "Oculus Touch Controllers";
static const char* MENU_PATH = "Avatar" ">" "Oculus Touch Controllers";
const char* OculusControllerManager::NAME = "Oculus"; const char* OculusControllerManager::NAME = "Oculus";
const quint64 LOST_TRACKING_DELAY = 3000000; const quint64 LOST_TRACKING_DELAY = 3000000;
bool OculusControllerManager::isSupported() const { bool OculusControllerManager::isSupported() const {
return oculusAvailable(); return hifi::ovr::available();
} }
bool OculusControllerManager::activate() { bool OculusControllerManager::activate() {
InputPlugin::activate(); InputPlugin::activate();
if (!_session) {
_session = acquireOculusSession();
}
Q_ASSERT(_session);
checkForConnectedDevices(); checkForConnectedDevices();
return true; return true;
} }
@ -58,10 +47,11 @@ void OculusControllerManager::checkForConnectedDevices() {
return; return;
} }
unsigned int controllerConnected = ovr_GetConnectedControllerTypes(_session); ovr::withSession([&] (ovrSession session) {
unsigned int controllerConnected = ovr_GetConnectedControllerTypes(session);
if (!_remote && (controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) { if (!_remote && (controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) {
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) { if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_inputState))) {
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
_remote = std::make_shared<RemoteDevice>(*this); _remote = std::make_shared<RemoteDevice>(*this);
userInputMapper->registerDevice(_remote); userInputMapper->registerDevice(_remote);
@ -69,22 +59,18 @@ void OculusControllerManager::checkForConnectedDevices() {
} }
if (!_touch && (controllerConnected & ovrControllerType_Touch) != 0) { if (!_touch && (controllerConnected & ovrControllerType_Touch) != 0) {
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_inputState))) {
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
_touch = std::make_shared<TouchDevice>(*this); _touch = std::make_shared<TouchDevice>(*this);
userInputMapper->registerDevice(_touch); userInputMapper->registerDevice(_touch);
} }
} }
});
} }
void OculusControllerManager::deactivate() { void OculusControllerManager::deactivate() {
InputPlugin::deactivate(); InputPlugin::deactivate();
if (_session) {
releaseOculusSession();
_session = nullptr;
}
// unregister with UserInputMapper // unregister with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
if (_touch) { if (_touch) {
@ -100,20 +86,30 @@ void OculusControllerManager::pluginUpdate(float deltaTime, const controller::In
checkForConnectedDevices(); checkForConnectedDevices();
bool updateRemote = false, updateTouch = false;
ovr::withSession([&](ovrSession session) {
if (_touch) { if (_touch) {
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { updateTouch = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_inputState));
_touch->update(deltaTime, inputCalibrationData); if (!updateTouch) {
} else { qCWarning(oculusLog) << "Unable to read Oculus touch input state" << ovr::getError();
qCWarning(oculus) << "Unable to read Oculus touch input state";
} }
} }
if (_remote) {
updateRemote = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_inputState));
if (!updateRemote) {
qCWarning(oculusLog) << "Unable to read Oculus remote input state" << ovr::getError();
}
}
});
if (_touch && updateTouch) {
_touch->update(deltaTime, inputCalibrationData);
}
if (_remote) { if (_remote && updateRemote) {
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) {
_remote->update(deltaTime, inputCalibrationData); _remote->update(deltaTime, inputCalibrationData);
} else {
qCWarning(oculus) << "Unable to read Oculus remote input state";
}
} }
} }
@ -210,15 +206,6 @@ void OculusControllerManager::RemoteDevice::focusOutEvent() {
_buttonPressedMap.clear(); _buttonPressedMap.clear();
} }
bool OculusControllerManager::isHeadControllerMounted() const {
ovrSessionStatus status;
bool success = OVR_SUCCESS(ovr_GetSessionStatus(_session, &status));
if (!success) {
return false;
}
return status.HmdMounted == ovrTrue;
}
void OculusControllerManager::TouchDevice::update(float deltaTime, void OculusControllerManager::TouchDevice::update(float deltaTime,
const controller::InputCalibrationData& inputCalibrationData) { const controller::InputCalibrationData& inputCalibrationData) {
_buttonPressedMap.clear(); _buttonPressedMap.clear();
@ -226,10 +213,19 @@ void OculusControllerManager::TouchDevice::update(float deltaTime,
int numTrackedControllers = 0; int numTrackedControllers = 0;
quint64 currentTime = usecTimestampNow(); quint64 currentTime = usecTimestampNow();
static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked | ovrStatus_PositionTracked; static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked | ovrStatus_PositionTracked;
auto tracking = ovr_GetTrackingState(_parent._session, 0, false); bool hasInputFocus = ovr::hasInputFocus();
ovr_for_each_hand([&](ovrHandType hand) { auto tracking = ovr::getTrackingState(); // ovr_GetTrackingState(_parent._session, 0, false);
ovr::for_each_hand([&](ovrHandType hand) {
++numTrackedControllers; ++numTrackedControllers;
int controller = (hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND); int controller = (hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND);
// Disable hand tracking while in Oculus Dash (Dash renders it's own hands)
if (!hasInputFocus) {
_poseStateMap.erase(controller);
_poseStateMap[controller].valid = false;
return;
}
if (REQUIRED_HAND_STATUS == (tracking.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) { if (REQUIRED_HAND_STATUS == (tracking.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) {
_poseStateMap.erase(controller); _poseStateMap.erase(controller);
handlePose(deltaTime, inputCalibrationData, hand, tracking.HandPoses[hand]); handlePose(deltaTime, inputCalibrationData, hand, tracking.HandPoses[hand]);
@ -253,7 +249,7 @@ void OculusControllerManager::TouchDevice::update(float deltaTime,
handleRotationForUntrackedHand(inputCalibrationData, hand, tracking.HandPoses[hand]); handleRotationForUntrackedHand(inputCalibrationData, hand, tracking.HandPoses[hand]);
}); });
if (_parent.isHeadControllerMounted()) { if (ovr::hmdMounted()) {
handleHeadPose(deltaTime, inputCalibrationData, tracking.HeadPose); handleHeadPose(deltaTime, inputCalibrationData, tracking.HeadPose);
} else { } else {
_poseStateMap[controller::HEAD].valid = false; _poseStateMap[controller::HEAD].valid = false;
@ -311,7 +307,7 @@ void OculusControllerManager::TouchDevice::handlePose(float deltaTime,
ovrHandType hand, const ovrPoseStatef& handPose) { ovrHandType hand, const ovrPoseStatef& handPose) {
auto poseId = hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND; auto poseId = hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND;
auto& pose = _poseStateMap[poseId]; auto& pose = _poseStateMap[poseId];
pose = ovrControllerPoseToHandPose(hand, handPose); pose = ovr::toControllerPose(hand, handPose);
// transform into avatar frame // transform into avatar frame
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
pose = pose.transform(controllerToAvatar); pose = pose.transform(controllerToAvatar);
@ -320,15 +316,15 @@ void OculusControllerManager::TouchDevice::handlePose(float deltaTime,
void OculusControllerManager::TouchDevice::handleHeadPose(float deltaTime, void OculusControllerManager::TouchDevice::handleHeadPose(float deltaTime,
const controller::InputCalibrationData& inputCalibrationData, const controller::InputCalibrationData& inputCalibrationData,
const ovrPoseStatef& headPose) { const ovrPoseStatef& headPose) {
glm::mat4 mat = createMatFromQuatAndPos(toGlm(headPose.ThePose.Orientation), glm::mat4 mat = createMatFromQuatAndPos(ovr::toGlm(headPose.ThePose.Orientation),
toGlm(headPose.ThePose.Position)); ovr::toGlm(headPose.ThePose.Position));
//perform a 180 flip to make the HMD face the +z instead of -z, beacuse the head faces +z //perform a 180 flip to make the HMD face the +z instead of -z, beacuse the head faces +z
glm::mat4 matYFlip = mat * Matrices::Y_180; glm::mat4 matYFlip = mat * Matrices::Y_180;
controller::Pose pose(extractTranslation(matYFlip), controller::Pose pose(extractTranslation(matYFlip),
glmExtractRotation(matYFlip), glmExtractRotation(matYFlip),
toGlm(headPose.LinearVelocity), // XXX * matYFlip ? ovr::toGlm(headPose.LinearVelocity), // XXX * matYFlip ?
toGlm(headPose.AngularVelocity)); ovr::toGlm(headPose.AngularVelocity));
glm::mat4 sensorToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; glm::mat4 sensorToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibrationData.defaultCenterEyeMat) * glm::mat4 defaultHeadOffset = glm::inverse(inputCalibrationData.defaultCenterEyeMat) *
@ -343,7 +339,7 @@ void OculusControllerManager::TouchDevice::handleRotationForUntrackedHand(const
auto poseId = (hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND); auto poseId = (hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND);
auto& pose = _poseStateMap[poseId]; auto& pose = _poseStateMap[poseId];
auto lastHandPose = _lastControllerPose[poseId]; auto lastHandPose = _lastControllerPose[poseId];
pose = ovrControllerRotationToHandRotation(hand, handPose, lastHandPose); pose = ovr::toControllerPose(hand, handPose, lastHandPose);
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
pose = pose.transform(controllerToAvatar); pose = pose.transform(controllerToAvatar);
} }
@ -351,13 +347,14 @@ void OculusControllerManager::TouchDevice::handleRotationForUntrackedHand(const
bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) { bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) {
Locker locker(_lock); Locker locker(_lock);
bool toReturn = true; bool toReturn = true;
ovr::withSession([&](ovrSession session) {
if (hand == controller::BOTH || hand == controller::LEFT) { if (hand == controller::BOTH || hand == controller::LEFT) {
if (strength == 0.0f) { if (strength == 0.0f) {
_leftHapticStrength = 0.0f; _leftHapticStrength = 0.0f;
_leftHapticDuration = 0.0f; _leftHapticDuration = 0.0f;
} else { } else {
_leftHapticStrength = (duration > _leftHapticDuration) ? strength : _leftHapticStrength; _leftHapticStrength = (duration > _leftHapticDuration) ? strength : _leftHapticStrength;
if (ovr_SetControllerVibration(_parent._session, ovrControllerType_LTouch, 1.0f, _leftHapticStrength) != ovrSuccess) { if (ovr_SetControllerVibration(session, ovrControllerType_LTouch, 1.0f, _leftHapticStrength) != ovrSuccess) {
toReturn = false; toReturn = false;
} }
_leftHapticDuration = std::max(duration, _leftHapticDuration); _leftHapticDuration = std::max(duration, _leftHapticDuration);
@ -369,18 +366,21 @@ bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, fl
_rightHapticDuration = 0.0f; _rightHapticDuration = 0.0f;
} else { } else {
_rightHapticStrength = (duration > _rightHapticDuration) ? strength : _rightHapticStrength; _rightHapticStrength = (duration > _rightHapticDuration) ? strength : _rightHapticStrength;
if (ovr_SetControllerVibration(_parent._session, ovrControllerType_RTouch, 1.0f, _rightHapticStrength) != ovrSuccess) { if (ovr_SetControllerVibration(session, ovrControllerType_RTouch, 1.0f, _rightHapticStrength) != ovrSuccess) {
toReturn = false; toReturn = false;
} }
_rightHapticDuration = std::max(duration, _rightHapticDuration); _rightHapticDuration = std::max(duration, _rightHapticDuration);
} }
} }
});
return toReturn; return toReturn;
} }
void OculusControllerManager::TouchDevice::stopHapticPulse(bool leftHand) { void OculusControllerManager::TouchDevice::stopHapticPulse(bool leftHand) {
auto handType = (leftHand ? ovrControllerType_LTouch : ovrControllerType_RTouch); auto handType = (leftHand ? ovrControllerType_LTouch : ovrControllerType_RTouch);
ovr_SetControllerVibration(_parent._session, handType, 0.0f, 0.0f); ovr::withSession([&](ovrSession session) {
ovr_SetControllerVibration(session, handType, 0.0f, 0.0f);
});
} }
/**jsdoc /**jsdoc

View file

@ -26,10 +26,8 @@ public:
// Plugin functions // Plugin functions
bool isSupported() const override; bool isSupported() const override;
const QString getName() const override { return NAME; } const QString getName() const override { return NAME; }
bool isHandController() const override { return _touch != nullptr; } bool isHandController() const override { return _touch != nullptr; }
bool isHeadController() const override { return true; } bool isHeadController() const override { return true; }
bool isHeadControllerMounted() const;
QStringList getSubdeviceNames() override; QStringList getSubdeviceNames() override;
bool activate() override; bool activate() override;
@ -105,7 +103,6 @@ private:
void checkForConnectedDevices(); void checkForConnectedDevices();
ovrSession _session { nullptr };
ovrInputState _inputState {}; ovrInputState _inputState {};
RemoteDevice::Pointer _remote; RemoteDevice::Pointer _remote;
TouchDevice::Pointer _touch; TouchDevice::Pointer _touch;

View file

@ -19,6 +19,8 @@
#include "OculusHelpers.h" #include "OculusHelpers.h"
using namespace hifi;
const char* OculusDisplayPlugin::NAME { "Oculus Rift" }; const char* OculusDisplayPlugin::NAME { "Oculus Rift" };
static ovrPerfHudMode currentDebugMode = ovrPerfHud_Off; static ovrPerfHudMode currentDebugMode = ovrPerfHud_Off;
@ -63,7 +65,7 @@ void OculusDisplayPlugin::cycleDebugOutput() {
void OculusDisplayPlugin::customizeContext() { void OculusDisplayPlugin::customizeContext() {
Parent::customizeContext(); Parent::customizeContext();
_outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OculusOutput", gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y)); _outputFramebuffer.reset(gpu::Framebuffer::create("OculusOutput", gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y));
ovrTextureSwapChainDesc desc = { }; ovrTextureSwapChainDesc desc = { };
desc.Type = ovrTexture_2D; desc.Type = ovrTexture_2D;
desc.ArraySize = 1; desc.ArraySize = 1;
@ -76,14 +78,14 @@ void OculusDisplayPlugin::customizeContext() {
ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &_textureSwapChain); ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &_textureSwapChain);
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
logCritical("Failed to create swap textures"); qCritical(oculusLog) << "Failed to create swap textures" << ovr::getError();
return; return;
} }
int length = 0; int length = 0;
result = ovr_GetTextureSwapChainLength(_session, _textureSwapChain, &length); result = ovr_GetTextureSwapChainLength(_session, _textureSwapChain, &length);
if (!OVR_SUCCESS(result) || !length) { if (!OVR_SUCCESS(result) || !length) {
logCritical("Unable to count swap chain textures"); qCritical(oculusLog) << "Unable to count swap chain textures" << ovr::getError();
return; return;
} }
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
@ -164,8 +166,8 @@ void OculusDisplayPlugin::hmdPresent() {
auto result = ovr_CommitTextureSwapChain(_session, _textureSwapChain); auto result = ovr_CommitTextureSwapChain(_session, _textureSwapChain);
Q_ASSERT(OVR_SUCCESS(result)); Q_ASSERT(OVR_SUCCESS(result));
_sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime; _sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime;
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovr::poseFromGlm(_currentPresentFrameInfo.renderPose);
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovr::poseFromGlm(_currentPresentFrameInfo.renderPose);
auto submitStart = usecTimestampNow(); auto submitStart = usecTimestampNow();
uint64_t nonSubmitInterval = 0; uint64_t nonSubmitInterval = 0;
@ -192,7 +194,7 @@ void OculusDisplayPlugin::hmdPresent() {
} }
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
logWarning("Failed to present"); qWarning(oculusLog) << "Failed to present" << ovr::getError();
} }
static int compositorDroppedFrames = 0; static int compositorDroppedFrames = 0;
@ -234,9 +236,7 @@ QJsonObject OculusDisplayPlugin::getHardwareStats() const {
} }
bool OculusDisplayPlugin::isHmdMounted() const { bool OculusDisplayPlugin::isHmdMounted() const {
ovrSessionStatus status; return ovr::hmdMounted();
return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) &&
(ovrFalse != status.HmdMounted));
} }
QString OculusDisplayPlugin::getPreferredAudioInDevice() const { QString OculusDisplayPlugin::getPreferredAudioInDevice() const {

View file

@ -24,41 +24,17 @@
#include <NumericalConstants.h> #include <NumericalConstants.h>
Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display")
Q_LOGGING_CATEGORY(oculus, "hifi.plugins.display.oculus") Q_LOGGING_CATEGORY(oculusLog, "hifi.plugins.display.oculus")
static std::atomic<uint32_t> refCount { 0 };
static ovrSession session { nullptr };
static bool _quitRequested { false };
static bool _reorientRequested { false };
inline ovrErrorInfo getError() {
ovrErrorInfo error;
ovr_GetLastErrorInfo(&error);
return error;
}
void logWarning(const char* what) {
qWarning(oculus) << what << ":" << getError().ErrorString;
}
void logCritical(const char* what) {
std::string error("[oculus] ");
error += what;
error += ": ";
error += getError().ErrorString;
qCritical(error.c_str());
}
using namespace hifi;
static wchar_t* REQUIRED_OCULUS_DLL = L"LibOVRRT64_1.dll"; static wchar_t* REQUIRED_OCULUS_DLL = L"LibOVRRT64_1.dll";
static wchar_t FOUND_PATH[MAX_PATH]; static wchar_t FOUND_PATH[MAX_PATH];
bool oculusAvailable() { bool ovr::available() {
static std::once_flag once; static std::once_flag once;
static bool result{ false }; static bool result{ false };
std::call_once(once, [&] { std::call_once(once, [&] {
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR"); static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR");
static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
if (enableDebugOpenVR) { if (enableDebugOpenVR) {
@ -81,113 +57,107 @@ bool oculusAvailable() {
return result; return result;
} }
ovrSession acquireOculusSession() { class ovrImpl {
if (!session && !oculusAvailable()) { using Mutex = std::mutex;
qCDebug(oculus) << "oculus: no runtime or HMD present"; using Lock = std::unique_lock<Mutex>;
return session; std::mutex mutex;
} ovrSession session{ nullptr };
size_t renderCount{ 0 };
if (!session) { private:
ovrInitParams initParams { void setupSession(bool render) {
ovrInit_RequestVersion | ovrInit_MixedRendering, OVR_MINOR_VERSION, nullptr, 0, 0 if (session) {
}; return;
}
ovrInitParams initParams{ ovrInit_RequestVersion | ovrInit_FocusAware, OVR_MINOR_VERSION, nullptr, 0, 0 };
if (render) {
initParams.Flags |= ovrInit_MixedRendering;
} else {
initParams.Flags |= ovrInit_Invisible;
}
if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { if (!OVR_SUCCESS(ovr_Initialize(&initParams))) {
logWarning("Failed to initialize Oculus SDK"); qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError();
return session; return;
} }
#ifdef OCULUS_APP_ID
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) {
// we were unable to initialize the platform for entitlement check - fail the check
_quitRequested = true;
} else {
qCDebug(oculus) << "Performing Oculus Platform entitlement check";
ovr_Entitlement_GetIsViewerEntitled();
}
}
#endif
Q_ASSERT(0 == refCount);
ovrGraphicsLuid luid; ovrGraphicsLuid luid;
if (!OVR_SUCCESS(ovr_Create(&session, &luid))) { if (!OVR_SUCCESS(ovr_Create(&session, &luid))) {
logWarning("Failed to acquire Oculus session"); qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError();
return session; return;
} }
} }
++refCount; void releaseSession() {
return session;
}
void releaseOculusSession() {
Q_ASSERT(refCount > 0 && session);
// HACK the Oculus runtime doesn't seem to play well with repeated shutdown / restart.
// So for now we'll just hold on to the session
#if 0
if (!--refCount) {
qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session";
ovr_Destroy(session);
ovr_Shutdown();
session = nullptr;
}
#endif
}
void handleOVREvents() {
if (!session) { if (!session) {
return; return;
} }
ovr_Destroy(session);
session = nullptr;
ovr_Shutdown();
}
ovrSessionStatus status; public:
void withSession(const std::function<void(ovrSession)>& f) {
Lock lock(mutex);
if (!session) {
setupSession(false);
}
f(session);
}
ovrSession acquireRenderSession() {
Lock lock(mutex);
if (renderCount++ == 0) {
releaseSession();
setupSession(true);
}
return session;
}
void releaseRenderSession(ovrSession session) {
Lock lock(mutex);
if (--renderCount == 0) {
releaseSession();
}
}
} _ovr;
ovrSession ovr::acquireRenderSession() {
return _ovr.acquireRenderSession();
}
void ovr::releaseRenderSession(ovrSession session) {
_ovr.releaseRenderSession(session);
}
void ovr::withSession(const std::function<void(ovrSession)>& f) {
_ovr.withSession(f);
}
ovrSessionStatus ovr::getStatus() {
ovrSessionStatus status{};
withSession([&](ovrSession session) {
if (!OVR_SUCCESS(ovr_GetSessionStatus(session, &status))) { if (!OVR_SUCCESS(ovr_GetSessionStatus(session, &status))) {
return; qCWarning(oculusLog) << "Failed to get session status" << ovr::getError();
}
});
return status;
} }
_quitRequested = status.ShouldQuit; ovrTrackingState ovr::getTrackingState() {
_reorientRequested = status.ShouldRecenter; ovrTrackingState result{};
withSession([&](ovrSession session) { result = ovr_GetTrackingState(session, 0, ovrFalse); });
#ifdef OCULUS_APP_ID return result;
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
// pop messages to see if we got a return for an entitlement check
ovrMessageHandle message = ovr_PopMessage();
while (message) {
switch (ovr_Message_GetType(message)) {
case ovrMessage_Entitlement_GetIsViewerEntitled: {
if (!ovr_Message_IsError(message)) {
// this viewer is entitled, no need to flag anything
qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally";
} else {
// we failed the entitlement check, set our flag so the app can stop
qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
_quitRequested = true;
}
}
} }
// free the message handle to cleanup and not leak QString ovr::getError() {
ovr_FreeMessage(message); static ovrErrorInfo error;
ovr_GetLastErrorInfo(&error);
// pop the next message to check, if there is one return QString(error.ErrorString);
message = ovr_PopMessage();
}
}
#endif
} }
bool quitRequested() { controller::Pose hifi::ovr::toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose) {
return _quitRequested;
}
bool reorientRequested() {
return _reorientRequested;
}
controller::Pose ovrControllerPoseToHandPose(
ovrHandType hand,
const ovrPoseStatef& handPose) {
// 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
@ -247,9 +217,8 @@ controller::Pose ovrControllerPoseToHandPose(
static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand; static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand;
static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, static const glm::vec3 CONTROLLER_OFFSET =
-CONTROLLER_LENGTH_OFFSET / 2.0f, glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, -CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET * 1.5f);
CONTROLLER_LENGTH_OFFSET * 1.5f);
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;
@ -268,7 +237,8 @@ controller::Pose ovrControllerPoseToHandPose(
return pose; return pose;
} }
controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, const ovrPoseStatef& handPose, controller::Pose hifi::ovr::toControllerPose(ovrHandType hand,
const ovrPoseStatef& handPose,
const ovrPoseStatef& lastHandPose) { const ovrPoseStatef& lastHandPose) {
static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y);
static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X);
@ -281,9 +251,8 @@ controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, const ovr
static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand; static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand;
static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, static const glm::vec3 CONTROLLER_OFFSET =
-CONTROLLER_LENGTH_OFFSET / 2.0f, glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, -CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET * 1.5f);
CONTROLLER_LENGTH_OFFSET * 1.5f);
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;
@ -301,3 +270,52 @@ controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, const ovr
pose.valid = true; pose.valid = true;
return pose; return pose;
} }
// FIXME These should be moved to an oculusPlatform plugin, they don't interact with the controller or session state
#if 0
void handleOVREvents() {
updateSessionStatus(true);
#ifdef OCULUS_APP_ID
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
// pop messages to see if we got a return for an entitlement check
ovrMessageHandle message = ovr_PopMessage();
while (message) {
switch (ovr_Message_GetType(message)) {
case ovrMessage_Entitlement_GetIsViewerEntitled:
{
if (!ovr_Message_IsError(message)) {
// this viewer is entitled, no need to flag anything
qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally";
} else {
// we failed the entitlement check, set our flag so the app can stop
qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
_quitRequested = true;
}
}
}
// free the message handle to cleanup and not leak
ovr_FreeMessage(message);
// pop the next message to check, if there is one
message = ovr_PopMessage();
}
}
#endif
}
#ifdef OCULUS_APP_ID
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) {
// we were unable to initialize the platform for entitlement check - fail the check
_quitRequested = true;
} else {
qCDebug(oculusLog) << "Performing Oculus Platform entitlement check";
ovr_Entitlement_GetIsViewerEntitled();
}
}
#endif
#endif

View file

@ -7,10 +7,9 @@
// //
#pragma once #pragma once
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
#include <OVR_CAPI_GL.h> #include <ovr_capi.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
@ -18,106 +17,107 @@
#include <controllers/Forward.h> #include <controllers/Forward.h>
Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_DECLARE_LOGGING_CATEGORY(displayplugins)
Q_DECLARE_LOGGING_CATEGORY(oculus) Q_DECLARE_LOGGING_CATEGORY(oculusLog)
void logWarning(const char* what); namespace hifi {
void logCritical(const char* what);
bool oculusAvailable();
ovrSession acquireOculusSession();
void releaseOculusSession();
void handleOVREvents(); struct ovr {
bool quitRequested(); static bool available();
bool reorientRequested(); static ovrSession acquireRenderSession();
static void releaseRenderSession(ovrSession session);
static void withSession(const std::function<void(ovrSession)>& f);
static ovrSessionStatus getStatus();
static ovrTrackingState getTrackingState();
static QString getError();
static inline bool quitRequested() { return quitRequested(getStatus()); }
static inline bool reorientRequested() { return reorientRequested(getStatus()); }
static inline bool hmdMounted() { return hmdMounted(getStatus()); }
static inline bool hasInputFocus() { return hasInputFocus(getStatus()); }
static inline bool quitRequested(const ovrSessionStatus& status) { return status.ShouldQuit != ovrFalse; }
static inline bool reorientRequested(const ovrSessionStatus& status) { return status.ShouldRecenter != ovrFalse; }
static inline bool hmdMounted(const ovrSessionStatus& status) { return status.HmdMounted != ovrFalse; }
static inline bool hasInputFocus(const ovrSessionStatus& status) { return status.HasInputFocus != ovrFalse; }
// Convenience method for looping over each eye with a lambda // Convenience method for looping over each eye with a lambda
template <typename Function> static inline void for_each_eye(const std::function<void(ovrEyeType eye)>& f) {
inline void ovr_for_each_eye(Function function) { for (ovrEyeType eye = ovrEye_Left; eye < ovrEye_Count; eye = static_cast<ovrEyeType>(eye + 1)) {
for (ovrEyeType eye = ovrEyeType::ovrEye_Left; f(eye);
eye < ovrEyeType::ovrEye_Count;
eye = static_cast<ovrEyeType>(eye + 1)) {
function(eye);
} }
} }
template <typename Function> static inline void for_each_hand(const std::function<void(ovrHandType eye)>& f) {
inline void ovr_for_each_hand(Function function) { for (ovrHandType hand = ovrHand_Left; hand < ovrHand_Count; hand = static_cast<ovrHandType>(hand + 1)) {
for (ovrHandType hand = ovrHandType::ovrHand_Left; f(hand);
hand <= ovrHandType::ovrHand_Right;
hand = static_cast<ovrHandType>(hand + 1)) {
function(hand);
} }
} }
static inline glm::mat4 toGlm(const ovrMatrix4f& om) {
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
return glm::transpose(glm::make_mat4(&om.M[0][0])); return glm::transpose(glm::make_mat4(&om.M[0][0]));
} }
inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { static inline glm::mat4 toGlm(const ovrFovPort& fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
} }
inline glm::vec3 toGlm(const ovrVector3f & ov) { static inline glm::vec3 toGlm(const ovrVector3f& ov) {
return glm::make_vec3(&ov.x); return glm::make_vec3(&ov.x);
} }
inline glm::vec2 toGlm(const ovrVector2f & ov) { static inline glm::vec2 toGlm(const ovrVector2f& ov) {
return glm::make_vec2(&ov.x); return glm::make_vec2(&ov.x);
} }
inline glm::uvec2 toGlm(const ovrSizei & ov) { static inline glm::uvec2 toGlm(const ovrSizei& ov) {
return glm::uvec2(ov.w, ov.h); return glm::uvec2(ov.w, ov.h);
} }
inline glm::quat toGlm(const ovrQuatf & oq) { static inline glm::quat toGlm(const ovrQuatf& oq) {
return glm::make_quat(&oq.x); return glm::make_quat(&oq.x);
} }
inline glm::mat4 toGlm(const ovrPosef & op) { static inline glm::mat4 toGlm(const ovrPosef& op) {
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
return translation * orientation; return translation * orientation;
} }
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { static inline ovrMatrix4f fromGlm(const glm::mat4& m) {
ovrMatrix4f result; ovrMatrix4f result;
glm::mat4 transposed(glm::transpose(m)); glm::mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result; return result;
} }
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { static inline ovrVector3f fromGlm(const glm::vec3& v) {
return { v.x, v.y, v.z }; return { v.x, v.y, v.z };
} }
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { static inline ovrVector2f fromGlm(const glm::vec2& v) {
return { v.x, v.y }; return { v.x, v.y };
} }
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { static inline ovrSizei fromGlm(const glm::uvec2& v) {
return { (int)v.x, (int)v.y }; return { (int)v.x, (int)v.y };
} }
inline ovrQuatf ovrFromGlm(const glm::quat & q) { static inline ovrQuatf fromGlm(const glm::quat& q) {
return { q.x, q.y, q.z, q.w }; return { q.x, q.y, q.z, q.w };
} }
inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) { static inline ovrPosef poseFromGlm(const glm::mat4& m) {
glm::vec3 translation = glm::vec3(m[3]) / m[3].w; glm::vec3 translation = glm::vec3(m[3]) / m[3].w;
glm::quat orientation = glm::quat_cast(m); glm::quat orientation = glm::quat_cast(m);
ovrPosef result; ovrPosef result;
result.Orientation = ovrFromGlm(orientation); result.Orientation = fromGlm(orientation);
result.Position = ovrFromGlm(translation); result.Position = fromGlm(translation);
return result; return result;
} }
controller::Pose ovrControllerPoseToHandPose( static controller::Pose toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose);
ovrHandType hand, static controller::Pose toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose, const ovrPoseStatef& lastHandPose);
const ovrPoseStatef& handPose);
controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, };
const ovrPoseStatef& handPose, const ovrPoseStatef& lastHandPose);
} // namespace hifi