Merge pull request #5180 from jherico/hmd_offset

Fixing HMD position offset bug in picking & stereo rendering in HMD
This commit is contained in:
Brad Hefta-Gaub 2015-06-22 17:22:26 -07:00
commit 81541e6013
4 changed files with 140 additions and 170 deletions

View file

@ -4748,3 +4748,10 @@ mat4 Application::getEyePose(int eye) const {
return mat4();
}
mat4 Application::getHeadPose() const {
if (isHMDMode()) {
return OculusManager::getHeadPose();
}
return mat4();
}

View file

@ -11,10 +11,10 @@
//
#include "InterfaceConfig.h"
#include "OculusManager.h"
#include "ui/overlays/Text3DOverlay.h"
#include <CursorManager.h>
#include <QDesktopWidget>
#include <QGuiApplication>
#include <QScreen>
@ -37,7 +37,6 @@
#include "InterfaceLogging.h"
#include "Application.h"
template <typename Function>
void for_each_eye(Function function) {
for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
@ -54,6 +53,71 @@ void for_each_eye(const ovrHmd & hmd, Function function) {
function(eye);
}
}
enum CalibrationState {
UNCALIBRATED,
WAITING_FOR_DELTA,
WAITING_FOR_ZERO,
WAITING_FOR_ZERO_HELD,
CALIBRATED
};
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
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) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
}
inline glm::vec3 toGlm(const ovrVector3f & ov) {
return glm::make_vec3(&ov.x);
}
inline glm::vec2 toGlm(const ovrVector2f & ov) {
return glm::make_vec2(&ov.x);
}
inline glm::ivec2 toGlm(const ovrVector2i & ov) {
return glm::ivec2(ov.x, ov.y);
}
inline glm::uvec2 toGlm(const ovrSizei & ov) {
return glm::uvec2(ov.w, ov.h);
}
inline glm::quat toGlm(const ovrQuatf & oq) {
return glm::make_quat(&oq.x);
}
inline glm::mat4 toGlm(const ovrPosef & op) {
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
return translation * orientation;
}
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
ovrMatrix4f result;
glm::mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result;
}
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
return{ v.x, v.y, v.z };
}
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
return{ v.x, v.y };
}
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
return{ (int)v.x, (int)v.y };
}
inline ovrQuatf ovrFromGlm(const glm::quat & q) {
return{ q.x, q.y, q.z, q.w };
}
#ifdef Q_OS_WIN
@ -171,50 +235,54 @@ private:
}
};
SwapFramebufferWrapper* OculusManager::_swapFbo{ nullptr };
MirrorFramebufferWrapper* OculusManager::_mirrorFbo{ nullptr };
ovrLayerEyeFov OculusManager::_sceneLayer;
static SwapFramebufferWrapper* _swapFbo{ nullptr };
static MirrorFramebufferWrapper* _mirrorFbo{ nullptr };
static ovrLayerEyeFov _sceneLayer;
#else
ovrTexture OculusManager::_eyeTextures[ovrEye_Count];
GlWindow* OculusManager::_outputWindow{ nullptr };
static ovrTexture _eyeTextures[ovrEye_Count];
static GlWindow* _outputWindow{ nullptr };
#endif
bool OculusManager::_isConnected = false;
ovrHmd OculusManager::_ovrHmd;
ovrFovPort OculusManager::_eyeFov[ovrEye_Count];
ovrVector3f OculusManager::_eyeOffset[ovrEye_Count];
ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];
ovrSizei OculusManager::_renderTargetSize;
glm::mat4 OculusManager::_eyeProjection[ovrEye_Count];
unsigned int OculusManager::_frameIndex = 0;
bool OculusManager::_frameTimingActive = false;
Camera* OculusManager::_camera = NULL;
ovrEyeType OculusManager::_activeEye = ovrEye_Count;
bool OculusManager::_hswDismissed = false;
static bool _isConnected = false;
static ovrHmd _ovrHmd;
static ovrFovPort _eyeFov[ovrEye_Count];
static ovrVector3f _eyeOffset[ovrEye_Count];
static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
static ovrSizei _renderTargetSize;
static glm::mat4 _eyeProjection[ovrEye_Count];
static unsigned int _frameIndex = 0;
static bool _frameTimingActive = false;
static Camera* _camera = NULL;
static ovrEyeType _activeEye = ovrEye_Count;
static bool _hswDismissed = false;
float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f;
OculusManager::CalibrationState OculusManager::_calibrationState;
glm::vec3 OculusManager::_calibrationPosition;
glm::quat OculusManager::_calibrationOrientation;
quint64 OculusManager::_calibrationStartTime;
int OculusManager::_calibrationMessage = 0;
glm::vec3 OculusManager::_eyePositions[ovrEye_Count];
static const float CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
static const float CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
static const float CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
static const float CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
static const quint64 CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
static const float CALIBRATION_MESSAGE_DISTANCE = 2.5f;
static CalibrationState _calibrationState;
static glm::vec3 _calibrationPosition;
static glm::quat _calibrationOrientation;
static quint64 _calibrationStartTime;
static int _calibrationMessage = 0;
static glm::vec3 _eyePositions[ovrEye_Count];
// TODO expose this as a developer toggle
bool OculusManager::_eyePerFrameMode = false;
ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count;
ovrSizei OculusManager::_recommendedTexSize = { 0, 0 };
float OculusManager::_offscreenRenderScale = 1.0;
static bool _eyePerFrameMode = false;
static ovrEyeType _lastEyeRendered = ovrEye_Count;
static ovrSizei _recommendedTexSize = { 0, 0 };
static float _offscreenRenderScale = 1.0;
static glm::mat4 _combinedProjection;
static ovrPosef _eyeRenderPoses[ovrEye_Count];
ovrRecti OculusManager::_eyeViewports[ovrEye_Count];
static ovrRecti _eyeViewports[ovrEye_Count];
static ovrVector3f _eyeOffsets[ovrEye_Count];
glm::vec3 OculusManager::getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
glm::vec3 OculusManager::getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
void OculusManager::connect(QOpenGLContext* shareContext) {
qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;
@ -267,6 +335,8 @@ void OculusManager::connect(QOpenGLContext* shareContext) {
_eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
_eyeProjection[eye] = toGlm(ovrMatrix4f_Projection(_eyeFov[eye],
DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_ovrHmd, eye, _eyeFov[eye]);
_eyeOffsets[eye] = erd.HmdToEyeViewOffset;
});
ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0];
combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan;
@ -389,7 +459,7 @@ void OculusManager::disconnect() {
}
}
void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) {
void positionCalibrationBillboard(Text3DOverlay* billboard) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::quat headOrientation = myAvatar->getHeadOrientation();
headOrientation.x = 0;
@ -400,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) {
billboard->setRotation(headOrientation);
}
void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) {
void calibrate(const glm::vec3& position, const glm::quat& orientation) {
static QString instructionMessage = "Hold still to calibrate";
static QString progressMessage;
static Text3DOverlay* billboard;
@ -605,9 +675,8 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
}
trackerPosition = bodyOrientation * trackerPosition;
static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } };
ovrPosef eyePoses[ovrEye_Count];
ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr);
ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, _eyeOffsets, eyePoses, nullptr);
#ifndef Q_OS_WIN
ovrHmd_BeginFrame(_ovrHmd, _frameIndex);
#endif
@ -721,7 +790,18 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
ovrHmd_EndFrame(_ovrHmd, _eyeRenderPoses, _eyeTextures);
glCanvas->makeCurrent();
#endif
// in order to account account for changes in the pick ray caused by head movement
// we need to force a mouse move event on every frame (perhaps we could change this
// to based on the head moving a minimum distance from the last position in which we
// sent?)
{
QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()),
Qt::NoButton, Qt::NoButton, 0);
qApp->mouseMoveEvent(&mouseEvent, 0);
}
}
@ -826,3 +906,8 @@ mat4 OculusManager::getEyeProjection(int eye) {
mat4 OculusManager::getEyePose(int eye) {
return toGlm(_eyeRenderPoses[eye]);
}
mat4 OculusManager::getHeadPose() {
ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
return toGlm(ts.HeadPose.ThePose);
}

View file

@ -13,8 +13,6 @@
#ifndef hifi_OculusManager_h
#define hifi_OculusManager_h
#include <OVR_CAPI.h>
#include <ProgramObject.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
@ -23,17 +21,7 @@
#include "RenderArgs.h"
class QOpenGLContext;
class Camera;
class GlWindow;
class PalmData;
class Text3DOverlay;
#ifdef Q_OS_WIN
struct SwapFramebufferWrapper;
struct MirrorFramebufferWrapper;
#endif
/// Handles interaction with the Oculus Rift.
class OculusManager {
@ -57,124 +45,14 @@ public:
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
static glm::vec3 getLeftEyePosition();
static glm::vec3 getRightEyePosition();
static int getHMDScreen();
static glm::mat4 getEyeProjection(int eye);
static glm::mat4 getEyePose(int eye);
private:
static void initSdk();
static void shutdownSdk();
static bool _isConnected;
static glm::vec3 _eyePositions[ovrEye_Count];
static ovrHmd _ovrHmd;
static ovrFovPort _eyeFov[ovrEye_Count];
static ovrVector3f _eyeOffset[ovrEye_Count];
static glm::mat4 _eyeProjection[ovrEye_Count];
static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
static ovrRecti _eyeViewports[ovrEye_Count];
static ovrSizei _renderTargetSize;
static unsigned int _frameIndex;
static bool _frameTimingActive;
static Camera* _camera;
static ovrEyeType _activeEye;
static bool _hswDismissed;
static void calibrate(const glm::vec3 position, const glm::quat orientation);
enum CalibrationState {
UNCALIBRATED,
WAITING_FOR_DELTA,
WAITING_FOR_ZERO,
WAITING_FOR_ZERO_HELD,
CALIBRATED
};
static void positionCalibrationBillboard(Text3DOverlay* message);
static float CALIBRATION_DELTA_MINIMUM_LENGTH;
static float CALIBRATION_DELTA_MINIMUM_ANGLE;
static float CALIBRATION_ZERO_MAXIMUM_LENGTH;
static float CALIBRATION_ZERO_MAXIMUM_ANGLE;
static quint64 CALIBRATION_ZERO_HOLD_TIME;
static float CALIBRATION_MESSAGE_DISTANCE;
static CalibrationState _calibrationState;
static glm::vec3 _calibrationPosition;
static glm::quat _calibrationOrientation;
static quint64 _calibrationStartTime;
static int _calibrationMessage;
// TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value
static ovrSizei _recommendedTexSize;
static float _offscreenRenderScale;
static bool _eyePerFrameMode;
static ovrEyeType _lastEyeRendered;
#ifdef Q_OS_WIN
static SwapFramebufferWrapper* _swapFbo;
static MirrorFramebufferWrapper* _mirrorFbo;
static ovrLayerEyeFov _sceneLayer;
#else
static ovrTexture _eyeTextures[ovrEye_Count];
static GlWindow* _outputWindow;
#endif
static glm::mat4 getHeadPose();
};
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
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) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
}
inline glm::vec3 toGlm(const ovrVector3f & ov) {
return glm::make_vec3(&ov.x);
}
inline glm::vec2 toGlm(const ovrVector2f & ov) {
return glm::make_vec2(&ov.x);
}
inline glm::ivec2 toGlm(const ovrVector2i & ov) {
return glm::ivec2(ov.x, ov.y);
}
inline glm::uvec2 toGlm(const ovrSizei & ov) {
return glm::uvec2(ov.w, ov.h);
}
inline glm::quat toGlm(const ovrQuatf & oq) {
return glm::make_quat(&oq.x);
}
inline glm::mat4 toGlm(const ovrPosef & op) {
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
return translation * orientation;
}
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
ovrMatrix4f result;
glm::mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result;
}
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
return{ v.x, v.y, v.z };
}
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
return{ v.x, v.y };
}
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
return{ (int)v.x, (int)v.y };
}
inline ovrQuatf ovrFromGlm(const glm::quat & q) {
return{ q.x, q.y, q.z, q.w };
}
#endif // hifi_OculusManager_h

View file

@ -334,12 +334,12 @@ void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& or
// Intersection UI overlay space
glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius;
intersectionWithUi += overlayPosition;
glm::vec3 worldSpaceIntersection = (glm::normalize(worldSpaceDirection) * _oculusUIRadius) + overlayPosition;
glm::vec3 worldSpaceHeadPosition = (overlayOrientation * glm::vec3(qApp->getHeadPose()[3])) + overlayPosition;
// Intersection in world space
origin = overlayPosition;
direction = glm::normalize(intersectionWithUi - origin);
origin = worldSpaceHeadPosition;
direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition);
}
//Caculate the click location using one of the sixense controllers. Scale is not applied